Merge branch 'tip/perf/ringbuffer-2' of git://git.kernel.org/pub/scm/linux/kernel...
authorIngo Molnar <mingo@elte.hu>
Tue, 26 Oct 2010 11:14:02 +0000 (13:14 +0200)
committerIngo Molnar <mingo@elte.hu>
Tue, 26 Oct 2010 11:14:02 +0000 (13:14 +0200)
2030 files changed:
Documentation/ABI/testing/sysfs-ata [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-power
Documentation/ABI/testing/sysfs-power
Documentation/DocBook/genericirq.tmpl
Documentation/DocBook/kernel-locking.tmpl
Documentation/RCU/checklist.txt
Documentation/RCU/stallwarn.txt
Documentation/RCU/trace.txt
Documentation/arm/00-INDEX
Documentation/arm/msm/gpiomux.txt [new file with mode: 0644]
Documentation/cputopology.txt
Documentation/feature-removal-schedule.txt
Documentation/filesystems/ocfs2.txt
Documentation/kernel-parameters.txt
Documentation/kprobes.txt
Documentation/pcmcia/driver-changes.txt
Documentation/power/00-INDEX
Documentation/power/interface.txt
Documentation/power/opp.txt [new file with mode: 0644]
Documentation/power/runtime_pm.txt
Documentation/power/s2ram.txt
Documentation/power/swsusp.txt
Documentation/powerpc/dts-bindings/fsl/spi.txt
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/include/asm/irqflags.h [new file with mode: 0644]
arch/alpha/include/asm/perf_event.h
arch/alpha/include/asm/system.h
arch/alpha/kernel/perf_event.c
arch/alpha/kernel/time.c
arch/arm/Kconfig
arch/arm/Kconfig.debug
arch/arm/Makefile
arch/arm/common/gic.c
arch/arm/common/pl330.c
arch/arm/common/sa1111.c
arch/arm/configs/at91sam9g20ek_defconfig
arch/arm/configs/kirkwood_defconfig
arch/arm/configs/mx27_defconfig
arch/arm/configs/mx31pdk_defconfig [deleted file]
arch/arm/configs/mx3_defconfig
arch/arm/configs/mx51_defconfig
arch/arm/configs/realview-smp_defconfig
arch/arm/configs/realview_defconfig
arch/arm/configs/s5p64x0_defconfig [moved from arch/arm/configs/s5p6440_defconfig with 97% similarity]
arch/arm/configs/u300_defconfig
arch/arm/include/asm/assembler.h
arch/arm/include/asm/cacheflush.h
arch/arm/include/asm/cachetype.h
arch/arm/include/asm/elf.h
arch/arm/include/asm/ftrace.h
arch/arm/include/asm/hardware/coresight.h
arch/arm/include/asm/hw_breakpoint.h [new file with mode: 0644]
arch/arm/include/asm/hw_irq.h
arch/arm/include/asm/io.h
arch/arm/include/asm/irqflags.h
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/mmu_context.h
arch/arm/include/asm/module.h
arch/arm/include/asm/perf_event.h
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/processor.h
arch/arm/include/asm/ptrace.h
arch/arm/include/asm/seccomp.h [new file with mode: 0644]
arch/arm/include/asm/smp_mpidr.h [new file with mode: 0644]
arch/arm/include/asm/smp_plat.h
arch/arm/include/asm/system.h
arch/arm/include/asm/thread_info.h
arch/arm/include/asm/tlbflush.h
arch/arm/kernel/Makefile
arch/arm/kernel/armksyms.c
arch/arm/kernel/asm-offsets.c
arch/arm/kernel/debug.S
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/etm.c
arch/arm/kernel/ftrace.c
arch/arm/kernel/head-common.S
arch/arm/kernel/head-nommu.S
arch/arm/kernel/head.S
arch/arm/kernel/hw_breakpoint.c [new file with mode: 0644]
arch/arm/kernel/irq.c
arch/arm/kernel/module.c
arch/arm/kernel/perf_event.c
arch/arm/kernel/process.c
arch/arm/kernel/ptrace.c
arch/arm/kernel/setup.c
arch/arm/kernel/smp.c
arch/arm/kernel/unwind.c
arch/arm/kernel/vmlinux.lds.S
arch/arm/mach-aaec2000/aaed2000.c
arch/arm/mach-aaec2000/include/mach/debug-macro.S
arch/arm/mach-aaec2000/include/mach/vmalloc.h
arch/arm/mach-at91/Kconfig
arch/arm/mach-at91/Makefile
arch/arm/mach-at91/board-1arm.c
arch/arm/mach-at91/board-afeb-9260v1.c
arch/arm/mach-at91/board-at572d940hf_ek.c
arch/arm/mach-at91/board-cam60.c
arch/arm/mach-at91/board-cap9adk.c
arch/arm/mach-at91/board-carmeva.c
arch/arm/mach-at91/board-cpu9krea.c
arch/arm/mach-at91/board-cpuat91.c
arch/arm/mach-at91/board-csb337.c
arch/arm/mach-at91/board-csb637.c
arch/arm/mach-at91/board-dk.c
arch/arm/mach-at91/board-eb9200.c
arch/arm/mach-at91/board-ecbat91.c
arch/arm/mach-at91/board-eco920.c
arch/arm/mach-at91/board-ek.c
arch/arm/mach-at91/board-flexibity.c [new file with mode: 0644]
arch/arm/mach-at91/board-kafa.c
arch/arm/mach-at91/board-kb9202.c
arch/arm/mach-at91/board-neocore926.c
arch/arm/mach-at91/board-picotux200.c
arch/arm/mach-at91/board-qil-a9260.c
arch/arm/mach-at91/board-sam9-l9260.c
arch/arm/mach-at91/board-sam9260ek.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c [deleted file]
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9m10g45ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board-snapper9260.c
arch/arm/mach-at91/board-stamp9g20.c
arch/arm/mach-at91/board-usb-a9260.c
arch/arm/mach-at91/board-usb-a9263.c
arch/arm/mach-at91/board-yl-9200.c
arch/arm/mach-at91/include/mach/at91x40.h
arch/arm/mach-at91/include/mach/debug-macro.S
arch/arm/mach-at91/include/mach/system.h
arch/arm/mach-bcmring/arch.c
arch/arm/mach-bcmring/dma.c
arch/arm/mach-bcmring/include/mach/vmalloc.h
arch/arm/mach-bcmring/irq.c
arch/arm/mach-clps711x/autcpu12.c
arch/arm/mach-clps711x/cdb89712.c
arch/arm/mach-clps711x/ceiva.c
arch/arm/mach-clps711x/clep7312.c
arch/arm/mach-clps711x/edb7211-arch.c
arch/arm/mach-clps711x/fortunet.c
arch/arm/mach-clps711x/include/mach/debug-macro.S
arch/arm/mach-clps711x/include/mach/vmalloc.h
arch/arm/mach-clps711x/p720t.c
arch/arm/mach-cns3xxx/cns3420vb.c
arch/arm/mach-cns3xxx/include/mach/debug-macro.S
arch/arm/mach-davinci/board-da830-evm.c
arch/arm/mach-davinci/board-da850-evm.c
arch/arm/mach-davinci/board-dm355-evm.c
arch/arm/mach-davinci/board-dm355-leopard.c
arch/arm/mach-davinci/board-dm365-evm.c
arch/arm/mach-davinci/board-dm644x-evm.c
arch/arm/mach-davinci/board-dm646x-evm.c
arch/arm/mach-davinci/board-neuros-osd2.c
arch/arm/mach-davinci/board-sffsdr.c
arch/arm/mach-davinci/board-tnetv107x-evm.c
arch/arm/mach-davinci/include/mach/debug-macro.S
arch/arm/mach-dove/dove-db-setup.c
arch/arm/mach-dove/include/mach/debug-macro.S
arch/arm/mach-ebsa110/core.c
arch/arm/mach-ebsa110/include/mach/debug-macro.S
arch/arm/mach-ebsa110/include/mach/vmalloc.h
arch/arm/mach-ep93xx/adssphere.c
arch/arm/mach-ep93xx/edb93xx.c
arch/arm/mach-ep93xx/gesbc9312.c
arch/arm/mach-ep93xx/include/mach/debug-macro.S
arch/arm/mach-ep93xx/micro9.c
arch/arm/mach-ep93xx/simone.c
arch/arm/mach-ep93xx/snappercl15.c
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-footbridge/cats-hw.c
arch/arm/mach-footbridge/ebsa285.c
arch/arm/mach-footbridge/include/mach/debug-macro.S
arch/arm/mach-footbridge/include/mach/vmalloc.h
arch/arm/mach-footbridge/netwinder-hw.c
arch/arm/mach-footbridge/personal.c
arch/arm/mach-gemini/board-nas4220b.c
arch/arm/mach-gemini/board-rut1xx.c
arch/arm/mach-gemini/board-wbd111.c
arch/arm/mach-gemini/board-wbd222.c
arch/arm/mach-gemini/include/mach/debug-macro.S
arch/arm/mach-h720x/h7201-eval.c
arch/arm/mach-h720x/h7202-eval.c
arch/arm/mach-h720x/include/mach/debug-macro.S
arch/arm/mach-h720x/include/mach/vmalloc.h
arch/arm/mach-imx/Kconfig
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/clock-imx1.c
arch/arm/mach-imx/clock-imx21.c
arch/arm/mach-imx/clock-imx27.c
arch/arm/mach-imx/devices-imx1.h
arch/arm/mach-imx/devices-imx21.h
arch/arm/mach-imx/devices-imx27.h
arch/arm/mach-imx/devices.c
arch/arm/mach-imx/devices.h
arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
arch/arm/mach-imx/mach-cpuimx27.c
arch/arm/mach-imx/mach-imx27_visstrim_m10.c [new file with mode: 0644]
arch/arm/mach-imx/mach-imx27lite.c
arch/arm/mach-imx/mach-mx1ads.c
arch/arm/mach-imx/mach-mx21ads.c
arch/arm/mach-imx/mach-mx27_3ds.c
arch/arm/mach-imx/mach-mx27ads.c
arch/arm/mach-imx/mach-mxt_td60.c
arch/arm/mach-imx/mach-pca100.c
arch/arm/mach-imx/mach-pcm038.c
arch/arm/mach-imx/mach-scb9328.c
arch/arm/mach-imx/pcm970-baseboard.c
arch/arm/mach-integrator/include/mach/debug-macro.S
arch/arm/mach-integrator/include/mach/vmalloc.h
arch/arm/mach-integrator/integrator_ap.c
arch/arm/mach-integrator/integrator_cp.c
arch/arm/mach-iop13xx/include/mach/debug-macro.S
arch/arm/mach-iop13xx/iq81340mc.c
arch/arm/mach-iop13xx/iq81340sc.c
arch/arm/mach-iop13xx/msi.c
arch/arm/mach-iop32x/em7210.c
arch/arm/mach-iop32x/glantank.c
arch/arm/mach-iop32x/include/mach/debug-macro.S
arch/arm/mach-iop32x/iq31244.c
arch/arm/mach-iop32x/iq80321.c
arch/arm/mach-iop32x/n2100.c
arch/arm/mach-iop33x/include/mach/debug-macro.S
arch/arm/mach-iop33x/iq80331.c
arch/arm/mach-iop33x/iq80332.c
arch/arm/mach-ixp2000/enp2611.c
arch/arm/mach-ixp2000/include/mach/debug-macro.S
arch/arm/mach-ixp2000/ixdp2400.c
arch/arm/mach-ixp2000/ixdp2800.c
arch/arm/mach-ixp2000/ixdp2x01.c
arch/arm/mach-ixp23xx/espresso.c
arch/arm/mach-ixp23xx/include/mach/debug-macro.S
arch/arm/mach-ixp23xx/ixdp2351.c
arch/arm/mach-ixp23xx/roadrunner.c
arch/arm/mach-ixp4xx/avila-setup.c
arch/arm/mach-ixp4xx/coyote-setup.c
arch/arm/mach-ixp4xx/dsmg600-setup.c
arch/arm/mach-ixp4xx/fsg-setup.c
arch/arm/mach-ixp4xx/gateway7001-setup.c
arch/arm/mach-ixp4xx/goramo_mlr.c
arch/arm/mach-ixp4xx/gtwx5715-setup.c
arch/arm/mach-ixp4xx/include/mach/debug-macro.S
arch/arm/mach-ixp4xx/ixdp425-setup.c
arch/arm/mach-ixp4xx/nas100d-setup.c
arch/arm/mach-ixp4xx/nslu2-setup.c
arch/arm/mach-ixp4xx/vulcan-setup.c
arch/arm/mach-ixp4xx/wg302v2-setup.c
arch/arm/mach-kirkwood/Kconfig
arch/arm/mach-kirkwood/Makefile
arch/arm/mach-kirkwood/d2net_v2-setup.c [new file with mode: 0644]
arch/arm/mach-kirkwood/db88f6281-bp-setup.c
arch/arm/mach-kirkwood/dockstar-setup.c [new file with mode: 0644]
arch/arm/mach-kirkwood/guruplug-setup.c
arch/arm/mach-kirkwood/include/mach/debug-macro.S
arch/arm/mach-kirkwood/include/mach/leds-netxbig.h [new file with mode: 0644]
arch/arm/mach-kirkwood/lacie_v2-common.c [new file with mode: 0644]
arch/arm/mach-kirkwood/lacie_v2-common.h [new file with mode: 0644]
arch/arm/mach-kirkwood/mv88f6281gtw_ge-setup.c
arch/arm/mach-kirkwood/netspace_v2-setup.c
arch/arm/mach-kirkwood/netxbig_v2-setup.c
arch/arm/mach-kirkwood/openrd-setup.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-kirkwood/t5325-setup.c
arch/arm/mach-kirkwood/ts219-setup.c
arch/arm/mach-kirkwood/ts41x-setup.c
arch/arm/mach-ks8695/board-acs5k.c
arch/arm/mach-ks8695/board-dsm320.c
arch/arm/mach-ks8695/board-micrel.c
arch/arm/mach-ks8695/include/mach/debug-macro.S
arch/arm/mach-l7200/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/mach-lh7a40x/arch-kev7a400.c
arch/arm/mach-lh7a40x/arch-lpd7a40x.c
arch/arm/mach-lh7a40x/include/mach/debug-macro.S
arch/arm/mach-loki/include/mach/debug-macro.S
arch/arm/mach-loki/lb88rc8480-setup.c
arch/arm/mach-lpc32xx/include/mach/debug-macro.S
arch/arm/mach-lpc32xx/phy3250.c
arch/arm/mach-mmp/Kconfig
arch/arm/mach-mmp/Makefile
arch/arm/mach-mmp/aspenite.c
arch/arm/mach-mmp/avengers_lite.c
arch/arm/mach-mmp/common.c
arch/arm/mach-mmp/flint.c
arch/arm/mach-mmp/include/mach/cputype.h
arch/arm/mach-mmp/include/mach/debug-macro.S
arch/arm/mach-mmp/include/mach/irqs.h
arch/arm/mach-mmp/include/mach/mfp-pxa168.h
arch/arm/mach-mmp/include/mach/pxa168.h
arch/arm/mach-mmp/include/mach/regs-apmu.h
arch/arm/mach-mmp/include/mach/teton_bga.h [new file with mode: 0644]
arch/arm/mach-mmp/jasper.c
arch/arm/mach-mmp/pxa168.c
arch/arm/mach-mmp/tavorevb.c
arch/arm/mach-mmp/teton_bga.c [new file with mode: 0644]
arch/arm/mach-mmp/ttc_dkb.c
arch/arm/mach-msm/Kconfig
arch/arm/mach-msm/Makefile
arch/arm/mach-msm/board-halibut.c
arch/arm/mach-msm/board-mahimahi.c
arch/arm/mach-msm/board-msm7x27.c
arch/arm/mach-msm/board-msm7x30.c
arch/arm/mach-msm/board-msm8x60.c [new file with mode: 0644]
arch/arm/mach-msm/board-qsd8x50.c
arch/arm/mach-msm/board-sapphire.c
arch/arm/mach-msm/board-trout.c
arch/arm/mach-msm/clock-dummy.c [new file with mode: 0644]
arch/arm/mach-msm/devices-msm7x30.c
arch/arm/mach-msm/devices-msm8x60-iommu.c [new file with mode: 0644]
arch/arm/mach-msm/devices-qsd8x50.c
arch/arm/mach-msm/gpio.c
arch/arm/mach-msm/gpio_hw.h [new file with mode: 0644]
arch/arm/mach-msm/gpiomux-7x30.c [new file with mode: 0644]
arch/arm/mach-msm/gpiomux-8x50.c [new file with mode: 0644]
arch/arm/mach-msm/gpiomux-8x60.c [new file with mode: 0644]
arch/arm/mach-msm/gpiomux-v1.c [new file with mode: 0644]
arch/arm/mach-msm/gpiomux-v1.h [new file with mode: 0644]
arch/arm/mach-msm/gpiomux-v2.c [new file with mode: 0644]
arch/arm/mach-msm/gpiomux-v2.h [new file with mode: 0644]
arch/arm/mach-msm/gpiomux.c [new file with mode: 0644]
arch/arm/mach-msm/gpiomux.h [new file with mode: 0644]
arch/arm/mach-msm/include/mach/board.h
arch/arm/mach-msm/include/mach/debug-macro.S
arch/arm/mach-msm/include/mach/dma.h
arch/arm/mach-msm/include/mach/entry-macro-qgic.S [new file with mode: 0644]
arch/arm/mach-msm/include/mach/entry-macro-vic.S [new file with mode: 0644]
arch/arm/mach-msm/include/mach/entry-macro.S
arch/arm/mach-msm/include/mach/gpio.h
arch/arm/mach-msm/include/mach/io.h
arch/arm/mach-msm/include/mach/iommu.h [new file with mode: 0644]
arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h [new file with mode: 0644]
arch/arm/mach-msm/include/mach/irqs-8x60.h [new file with mode: 0644]
arch/arm/mach-msm/include/mach/irqs.h
arch/arm/mach-msm/include/mach/memory.h
arch/arm/mach-msm/include/mach/msm_iomap-8x60.h [new file with mode: 0644]
arch/arm/mach-msm/include/mach/msm_iomap.h
arch/arm/mach-msm/include/mach/smp.h [new file with mode: 0644]
arch/arm/mach-msm/include/mach/vmalloc.h
arch/arm/mach-msm/io.c
arch/arm/mach-msm/iommu.c [new file with mode: 0644]
arch/arm/mach-msm/iommu_dev.c [new file with mode: 0644]
arch/arm/mach-msm/timer.c
arch/arm/mach-mv78xx0/buffalo-wxl-setup.c
arch/arm/mach-mv78xx0/db78x00-bp-setup.c
arch/arm/mach-mv78xx0/include/mach/debug-macro.S
arch/arm/mach-mv78xx0/rd78x00-masa-setup.c
arch/arm/mach-mx25/Kconfig
arch/arm/mach-mx25/clock.c
arch/arm/mach-mx25/devices-imx25.h
arch/arm/mach-mx25/devices.c
arch/arm/mach-mx25/devices.h
arch/arm/mach-mx25/eukrea_mbimxsd-baseboard.c
arch/arm/mach-mx25/mach-cpuimx25.c
arch/arm/mach-mx25/mach-mx25_3ds.c
arch/arm/mach-mx3/Kconfig
arch/arm/mach-mx3/Makefile
arch/arm/mach-mx3/clock-imx31.c
arch/arm/mach-mx3/clock-imx35.c
arch/arm/mach-mx3/cpu.c
arch/arm/mach-mx3/devices-imx31.h
arch/arm/mach-mx3/devices-imx35.h
arch/arm/mach-mx3/devices.c
arch/arm/mach-mx3/devices.h
arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c
arch/arm/mach-mx3/mach-armadillo5x0.c
arch/arm/mach-mx3/mach-cpuimx35.c
arch/arm/mach-mx3/mach-kzm_arm11_01.c
arch/arm/mach-mx3/mach-mx31_3ds.c
arch/arm/mach-mx3/mach-mx31ads.c
arch/arm/mach-mx3/mach-mx31lilly.c
arch/arm/mach-mx3/mach-mx31lite.c
arch/arm/mach-mx3/mach-mx31moboard.c
arch/arm/mach-mx3/mach-mx35_3ds.c
arch/arm/mach-mx3/mach-pcm037.c
arch/arm/mach-mx3/mach-pcm037_eet.c
arch/arm/mach-mx3/mach-pcm043.c
arch/arm/mach-mx3/mach-qong.c
arch/arm/mach-mx3/mm.c
arch/arm/mach-mx5/Kconfig
arch/arm/mach-mx5/Makefile
arch/arm/mach-mx5/board-cpuimx51.c
arch/arm/mach-mx5/board-cpuimx51sd.c [new file with mode: 0644]
arch/arm/mach-mx5/board-mx51_3ds.c
arch/arm/mach-mx5/board-mx51_babbage.c
arch/arm/mach-mx5/board-mx51_efikamx.c [new file with mode: 0644]
arch/arm/mach-mx5/clock-mx51.c
arch/arm/mach-mx5/cpu.c
arch/arm/mach-mx5/devices-imx51.h [new file with mode: 0644]
arch/arm/mach-mx5/devices.c
arch/arm/mach-mx5/devices.h
arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c
arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c [new file with mode: 0644]
arch/arm/mach-mxc91231/magx-zn5.c
arch/arm/mach-netx/include/mach/debug-macro.S
arch/arm/mach-netx/include/mach/vmalloc.h
arch/arm/mach-netx/nxdb500.c
arch/arm/mach-netx/nxdkn.c
arch/arm/mach-netx/nxeb500hmi.c
arch/arm/mach-nomadik/board-nhk8815.c
arch/arm/mach-nomadik/include/mach/debug-macro.S
arch/arm/mach-ns9xxx/include/mach/debug-macro.S
arch/arm/mach-nuc93x/mach-nuc932evb.c
arch/arm/mach-omap1/board-ams-delta.c
arch/arm/mach-omap1/board-fsample.c
arch/arm/mach-omap1/board-generic.c
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-htcherald.c
arch/arm/mach-omap1/board-innovator.c
arch/arm/mach-omap1/board-nokia770.c
arch/arm/mach-omap1/board-osk.c
arch/arm/mach-omap1/board-palmte.c
arch/arm/mach-omap1/board-palmtt.c
arch/arm/mach-omap1/board-palmz71.c
arch/arm/mach-omap1/board-perseus2.c
arch/arm/mach-omap1/board-sx1.c
arch/arm/mach-omap1/board-voiceblue.c
arch/arm/mach-omap1/include/mach/debug-macro.S
arch/arm/mach-omap1/include/mach/vmalloc.h
arch/arm/mach-omap2/board-2430sdp.c
arch/arm/mach-omap2/board-3430sdp.c
arch/arm/mach-omap2/board-3630sdp.c
arch/arm/mach-omap2/board-4430sdp.c
arch/arm/mach-omap2/board-am3517evm.c
arch/arm/mach-omap2/board-apollon.c
arch/arm/mach-omap2/board-cm-t35.c
arch/arm/mach-omap2/board-devkit8000.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/board-h4.c
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/board-omap3beagle.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/board-omap3pandora.c
arch/arm/mach-omap2/board-omap3stalker.c
arch/arm/mach-omap2/board-omap3touchbook.c
arch/arm/mach-omap2/board-omap4panda.c
arch/arm/mach-omap2/board-overo.c
arch/arm/mach-omap2/board-rx51.c
arch/arm/mach-omap2/board-zoom2.c
arch/arm/mach-omap2/board-zoom3.c
arch/arm/mach-omap2/include/mach/debug-macro.S
arch/arm/mach-omap2/include/mach/vmalloc.h
arch/arm/mach-orion5x/d2net-setup.c
arch/arm/mach-orion5x/db88f5281-setup.c
arch/arm/mach-orion5x/dns323-setup.c
arch/arm/mach-orion5x/edmini_v2-setup.c
arch/arm/mach-orion5x/include/mach/debug-macro.S
arch/arm/mach-orion5x/kurobox_pro-setup.c
arch/arm/mach-orion5x/ls_hgl-setup.c
arch/arm/mach-orion5x/lsmini-setup.c
arch/arm/mach-orion5x/mss2-setup.c
arch/arm/mach-orion5x/mv2120-setup.c
arch/arm/mach-orion5x/net2big-setup.c
arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
arch/arm/mach-orion5x/rd88f5182-setup.c
arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
arch/arm/mach-orion5x/terastation_pro2-setup.c
arch/arm/mach-orion5x/ts209-setup.c
arch/arm/mach-orion5x/ts409-setup.c
arch/arm/mach-orion5x/ts78xx-setup.c
arch/arm/mach-orion5x/wnr854t-setup.c
arch/arm/mach-orion5x/wrt350n-v2-setup.c
arch/arm/mach-pnx4008/core.c
arch/arm/mach-pnx4008/include/mach/debug-macro.S
arch/arm/mach-pnx4008/include/mach/vmalloc.h
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/balloon3.c
arch/arm/mach-pxa/capc7117.c
arch/arm/mach-pxa/cm-x2xx.c
arch/arm/mach-pxa/cm-x300.c
arch/arm/mach-pxa/colibri-pxa270.c
arch/arm/mach-pxa/colibri-pxa300.c
arch/arm/mach-pxa/colibri-pxa320.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/cpufreq-pxa3xx.c
arch/arm/mach-pxa/csb726.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/devices.h
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/eseries.c
arch/arm/mach-pxa/ezx.c
arch/arm/mach-pxa/generic.c
arch/arm/mach-pxa/generic.h
arch/arm/mach-pxa/gumstix.c
arch/arm/mach-pxa/h5000.c
arch/arm/mach-pxa/himalaya.c
arch/arm/mach-pxa/hx4700.c
arch/arm/mach-pxa/icontrol.c
arch/arm/mach-pxa/idp.c
arch/arm/mach-pxa/include/mach/balloon3.h
arch/arm/mach-pxa/include/mach/debug-macro.S
arch/arm/mach-pxa/include/mach/eseries-irq.h
arch/arm/mach-pxa/include/mach/hx4700.h
arch/arm/mach-pxa/include/mach/irqs.h
arch/arm/mach-pxa/include/mach/littleton.h
arch/arm/mach-pxa/include/mach/lpd270.h
arch/arm/mach-pxa/include/mach/lubbock.h
arch/arm/mach-pxa/include/mach/magician.h
arch/arm/mach-pxa/include/mach/mainstone.h
arch/arm/mach-pxa/include/mach/mfp-pxa930.h
arch/arm/mach-pxa/include/mach/pcm027.h
arch/arm/mach-pxa/include/mach/poodle.h
arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h [new file with mode: 0644]
arch/arm/mach-pxa/include/mach/tosa.h
arch/arm/mach-pxa/include/mach/zeus.h
arch/arm/mach-pxa/include/mach/zylonite.h
arch/arm/mach-pxa/littleton.c
arch/arm/mach-pxa/lpd270.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-pxa/mp900.c
arch/arm/mach-pxa/palmld.c
arch/arm/mach-pxa/palmt5.c
arch/arm/mach-pxa/palmtc.c
arch/arm/mach-pxa/palmte2.c
arch/arm/mach-pxa/palmtreo.c
arch/arm/mach-pxa/palmtx.c
arch/arm/mach-pxa/palmz72.c
arch/arm/mach-pxa/pcm027.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/pxa3xx-ulpi.c [new file with mode: 0644]
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/pxa930.c
arch/arm/mach-pxa/raumfeld.c
arch/arm/mach-pxa/saar.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/stargate2.c
arch/arm/mach-pxa/tavorevb.c
arch/arm/mach-pxa/tavorevb3.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/vpac270.c
arch/arm/mach-pxa/xcep.c
arch/arm/mach-pxa/z2.c
arch/arm/mach-pxa/zeus.c
arch/arm/mach-pxa/zylonite.c
arch/arm/mach-realview/core.c
arch/arm/mach-realview/include/mach/debug-macro.S
arch/arm/mach-realview/include/mach/smp.h
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_pba8.c
arch/arm/mach-realview/realview_pbx.c
arch/arm/mach-rpc/include/mach/debug-macro.S
arch/arm/mach-rpc/include/mach/vmalloc.h
arch/arm/mach-rpc/riscpc.c
arch/arm/mach-s3c2410/include/mach/debug-macro.S
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-otom.c
arch/arm/mach-s3c2410/mach-qt2410.c
arch/arm/mach-s3c2410/mach-smdk2410.c
arch/arm/mach-s3c2410/mach-tct_hammer.c
arch/arm/mach-s3c2410/mach-vr1000.c
arch/arm/mach-s3c2412/mach-jive.c
arch/arm/mach-s3c2412/mach-smdk2413.c
arch/arm/mach-s3c2412/mach-vstms.c
arch/arm/mach-s3c2416/mach-smdk2416.c
arch/arm/mach-s3c2440/mach-anubis.c
arch/arm/mach-s3c2440/mach-at2440evb.c
arch/arm/mach-s3c2440/mach-gta02.c
arch/arm/mach-s3c2440/mach-mini2440.c
arch/arm/mach-s3c2440/mach-nexcoder.c
arch/arm/mach-s3c2440/mach-osiris.c
arch/arm/mach-s3c2440/mach-rx1950.c
arch/arm/mach-s3c2440/mach-rx3715.c
arch/arm/mach-s3c2440/mach-smdk2440.c
arch/arm/mach-s3c2443/mach-smdk2443.c
arch/arm/mach-s3c24a0/include/mach/debug-macro.S
arch/arm/mach-s3c64xx/include/mach/debug-macro.S
arch/arm/mach-s3c64xx/mach-anw6410.c
arch/arm/mach-s3c64xx/mach-hmt.c
arch/arm/mach-s3c64xx/mach-ncp.c
arch/arm/mach-s3c64xx/mach-real6410.c
arch/arm/mach-s3c64xx/mach-smartq.c
arch/arm/mach-s3c64xx/mach-smartq5.c
arch/arm/mach-s3c64xx/mach-smartq7.c
arch/arm/mach-s3c64xx/mach-smdk6400.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/mach-s5p6440/Kconfig [deleted file]
arch/arm/mach-s5p6440/Makefile [deleted file]
arch/arm/mach-s5p6440/clock.c [deleted file]
arch/arm/mach-s5p6440/cpu.c [deleted file]
arch/arm/mach-s5p6440/dev-audio.c [deleted file]
arch/arm/mach-s5p6440/dev-spi.c [deleted file]
arch/arm/mach-s5p6440/include/mach/debug-macro.S [deleted file]
arch/arm/mach-s5p6440/include/mach/gpio.h [deleted file]
arch/arm/mach-s5p6440/include/mach/io.h [deleted file]
arch/arm/mach-s5p6440/include/mach/map.h [deleted file]
arch/arm/mach-s5p6440/include/mach/regs-clock.h [deleted file]
arch/arm/mach-s5p6440/include/mach/spi-clocks.h [deleted file]
arch/arm/mach-s5p6440/include/mach/uncompress.h [deleted file]
arch/arm/mach-s5p6440/init.c [deleted file]
arch/arm/mach-s5p6442/cpu.c
arch/arm/mach-s5p6442/include/mach/debug-macro.S
arch/arm/mach-s5p6442/include/mach/map.h
arch/arm/mach-s5p6442/mach-smdk6442.c
arch/arm/mach-s5p64x0/Kconfig [new file with mode: 0644]
arch/arm/mach-s5p64x0/Makefile [new file with mode: 0644]
arch/arm/mach-s5p64x0/Makefile.boot [moved from arch/arm/mach-s5p6440/Makefile.boot with 100% similarity]
arch/arm/mach-s5p64x0/clock-s5p6440.c [new file with mode: 0644]
arch/arm/mach-s5p64x0/clock-s5p6450.c [new file with mode: 0644]
arch/arm/mach-s5p64x0/clock.c [new file with mode: 0644]
arch/arm/mach-s5p64x0/cpu.c [new file with mode: 0644]
arch/arm/mach-s5p64x0/dev-audio.c [new file with mode: 0644]
arch/arm/mach-s5p64x0/dev-spi.c [new file with mode: 0644]
arch/arm/mach-s5p64x0/dma.c [moved from arch/arm/mach-s5p6440/dma.c with 55% similarity]
arch/arm/mach-s5p64x0/gpio.c [moved from arch/arm/mach-s5p6440/gpio.c with 74% similarity]
arch/arm/mach-s5p64x0/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/mach-s5p64x0/include/mach/dma.h [moved from arch/arm/mach-s5p6440/include/mach/dma.h with 100% similarity]
arch/arm/mach-s5p64x0/include/mach/entry-macro.S [moved from arch/arm/mach-s5p6440/include/mach/entry-macro.S with 58% similarity]
arch/arm/mach-s5p64x0/include/mach/gpio.h [new file with mode: 0644]
arch/arm/mach-s5p64x0/include/mach/hardware.h [moved from arch/arm/mach-s5p6440/include/mach/hardware.h with 67% similarity]
arch/arm/mach-s5p64x0/include/mach/i2c.h [new file with mode: 0644]
arch/arm/mach-s5p64x0/include/mach/io.h [new file with mode: 0644]
arch/arm/mach-s5p64x0/include/mach/irqs.h [moved from arch/arm/mach-s5p6440/include/mach/irqs.h with 71% similarity]
arch/arm/mach-s5p64x0/include/mach/map.h [new file with mode: 0644]
arch/arm/mach-s5p64x0/include/mach/memory.h [moved from arch/arm/mach-s5p6440/include/mach/memory.h with 55% similarity]
arch/arm/mach-s5p64x0/include/mach/pwm-clock.h [moved from arch/arm/mach-s5p6440/include/mach/pwm-clock.h with 86% similarity]
arch/arm/mach-s5p64x0/include/mach/regs-clock.h [new file with mode: 0644]
arch/arm/mach-s5p64x0/include/mach/regs-gpio.h [moved from arch/arm/mach-s5p6440/include/mach/regs-gpio.h with 79% similarity]
arch/arm/mach-s5p64x0/include/mach/regs-irq.h [moved from arch/arm/mach-s5p6440/include/mach/regs-irq.h with 66% similarity]
arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h [new file with mode: 0644]
arch/arm/mach-s5p64x0/include/mach/spi-clocks.h [new file with mode: 0644]
arch/arm/mach-s5p64x0/include/mach/system.h [moved from arch/arm/mach-s5p6440/include/mach/system.h with 69% similarity]
arch/arm/mach-s5p64x0/include/mach/tick.h [moved from arch/arm/mach-s5p6440/include/mach/tick.h with 60% similarity]
arch/arm/mach-s5p64x0/include/mach/timex.h [moved from arch/arm/mach-s5p6440/include/mach/timex.h with 80% similarity]
arch/arm/mach-s5p64x0/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/mach-s5p64x0/include/mach/vmalloc.h [moved from arch/arm/mach-s5p6440/include/mach/vmalloc.h with 74% similarity]
arch/arm/mach-s5p64x0/init.c [new file with mode: 0644]
arch/arm/mach-s5p64x0/mach-smdk6440.c [moved from arch/arm/mach-s5p6440/mach-smdk6440.c with 67% similarity]
arch/arm/mach-s5p64x0/mach-smdk6450.c [new file with mode: 0644]
arch/arm/mach-s5p64x0/setup-i2c0.c [moved from arch/arm/mach-s5p6440/setup-i2c0.c with 52% similarity]
arch/arm/mach-s5p64x0/setup-i2c1.c [moved from arch/arm/mach-s5p6440/setup-i2c1.c with 55% similarity]
arch/arm/mach-s5pc100/cpu.c
arch/arm/mach-s5pc100/include/mach/debug-macro.S
arch/arm/mach-s5pc100/include/mach/map.h
arch/arm/mach-s5pc100/mach-smdkc100.c
arch/arm/mach-s5pv210/Kconfig
arch/arm/mach-s5pv210/Makefile
arch/arm/mach-s5pv210/cpu.c
arch/arm/mach-s5pv210/include/mach/debug-macro.S
arch/arm/mach-s5pv210/include/mach/map.h
arch/arm/mach-s5pv210/mach-aquila.c
arch/arm/mach-s5pv210/mach-goni.c
arch/arm/mach-s5pv210/mach-smdkc110.c
arch/arm/mach-s5pv210/mach-smdkv210.c
arch/arm/mach-s5pv310/cpu.c
arch/arm/mach-s5pv310/include/mach/debug-macro.S
arch/arm/mach-s5pv310/include/mach/irqs.h
arch/arm/mach-s5pv310/include/mach/map.h
arch/arm/mach-s5pv310/include/mach/smp.h
arch/arm/mach-s5pv310/mach-smdkv310.c
arch/arm/mach-s5pv310/mach-universal_c210.c
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/badge4.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/collie.c
arch/arm/mach-sa1100/h3100.c
arch/arm/mach-sa1100/h3600.c
arch/arm/mach-sa1100/hackkit.c
arch/arm/mach-sa1100/include/mach/debug-macro.S
arch/arm/mach-sa1100/jornada720.c
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/pleb.c
arch/arm/mach-sa1100/shannon.c
arch/arm/mach-sa1100/simpad.c
arch/arm/mach-shark/core.c
arch/arm/mach-shark/include/mach/debug-macro.S
arch/arm/mach-shark/include/mach/vmalloc.h
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-g3evm.c
arch/arm/mach-shmobile/board-g4evm.c
arch/arm/mach-stmp378x/stmp378x_devb.c
arch/arm/mach-stmp37xx/stmp37xx_devb.c
arch/arm/mach-tcc8k/Kconfig [new file with mode: 0644]
arch/arm/mach-tcc8k/Makefile [new file with mode: 0644]
arch/arm/mach-tcc8k/Makefile.boot [new file with mode: 0644]
arch/arm/mach-tcc8k/board-tcc8000-sdk.c [new file with mode: 0644]
arch/arm/mach-tcc8k/clock.c [new file with mode: 0644]
arch/arm/mach-tcc8k/common.h [new file with mode: 0644]
arch/arm/mach-tcc8k/devices.c [new file with mode: 0644]
arch/arm/mach-tcc8k/io.c [new file with mode: 0644]
arch/arm/mach-tcc8k/irq.c [new file with mode: 0644]
arch/arm/mach-tcc8k/time.c [new file with mode: 0644]
arch/arm/mach-tegra/board-harmony.c
arch/arm/mach-tegra/include/mach/debug-macro.S
arch/arm/mach-tegra/include/mach/smp.h
arch/arm/mach-u300/dummyspichip.c
arch/arm/mach-u300/include/mach/debug-macro.S
arch/arm/mach-u300/spi.c
arch/arm/mach-u300/u300.c
arch/arm/mach-ux500/Kconfig
arch/arm/mach-ux500/Makefile
arch/arm/mach-ux500/board-mop500-regulators.c [new file with mode: 0644]
arch/arm/mach-ux500/board-mop500-sdi.c [new file with mode: 0644]
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/board-mop500.h [new file with mode: 0644]
arch/arm/mach-ux500/board-u5500.c
arch/arm/mach-ux500/cpu-db5500.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/devices-db8500.c
arch/arm/mach-ux500/hotplug.c [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/db5500-regs.h
arch/arm/mach-ux500/include/mach/db8500-regs.h
arch/arm/mach-ux500/include/mach/debug-macro.S
arch/arm/mach-ux500/include/mach/devices.h
arch/arm/mach-ux500/include/mach/hardware.h
arch/arm/mach-ux500/include/mach/irqs-db5500.h
arch/arm/mach-ux500/include/mach/irqs.h
arch/arm/mach-ux500/include/mach/mbox.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/prcmu-regs.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/prcmu.h [new file with mode: 0644]
arch/arm/mach-ux500/include/mach/setup.h
arch/arm/mach-ux500/include/mach/smp.h
arch/arm/mach-ux500/mbox.c [new file with mode: 0644]
arch/arm/mach-ux500/modem_irq.c [new file with mode: 0644]
arch/arm/mach-ux500/pins-db5500.h [new file with mode: 0644]
arch/arm/mach-ux500/pins-db8500.h
arch/arm/mach-ux500/platsmp.c
arch/arm/mach-ux500/prcmu.c [new file with mode: 0644]
arch/arm/mach-ux500/ste-dma40-db5500.h [new file with mode: 0644]
arch/arm/mach-ux500/ste-dma40-db8500.h
arch/arm/mach-versatile/include/mach/debug-macro.S
arch/arm/mach-versatile/include/mach/vmalloc.h
arch/arm/mach-versatile/versatile_ab.c
arch/arm/mach-versatile/versatile_pb.c
arch/arm/mach-vexpress/ct-ca9x4.c
arch/arm/mach-vexpress/include/mach/debug-macro.S
arch/arm/mach-vexpress/include/mach/smp.h
arch/arm/mach-w90x900/mach-nuc910evb.c
arch/arm/mach-w90x900/mach-nuc950evb.c
arch/arm/mach-w90x900/mach-nuc960evb.c
arch/arm/mm/cache-v6.S
arch/arm/mm/cache-v7.S
arch/arm/mm/copypage-v4mc.c
arch/arm/mm/copypage-v6.c
arch/arm/mm/copypage-xscale.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/fault-armv.c
arch/arm/mm/fault.c
arch/arm/mm/flush.c
arch/arm/mm/init.c
arch/arm/mm/mmap.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-arm1020.S
arch/arm/mm/proc-arm1020e.S
arch/arm/mm/proc-arm1022.S
arch/arm/mm/proc-arm1026.S
arch/arm/mm/proc-arm6_7.S
arch/arm/mm/proc-arm720.S
arch/arm/mm/proc-arm740.S
arch/arm/mm/proc-arm7tdmi.S
arch/arm/mm/proc-arm920.S
arch/arm/mm/proc-arm922.S
arch/arm/mm/proc-arm925.S
arch/arm/mm/proc-arm926.S
arch/arm/mm/proc-arm940.S
arch/arm/mm/proc-arm946.S
arch/arm/mm/proc-arm9tdmi.S
arch/arm/mm/proc-fa526.S
arch/arm/mm/proc-feroceon.S
arch/arm/mm/proc-mohawk.S
arch/arm/mm/proc-sa110.S
arch/arm/mm/proc-sa1100.S
arch/arm/mm/proc-v6.S
arch/arm/mm/proc-v7.S
arch/arm/mm/proc-xsc3.S
arch/arm/mm/proc-xscale.S
arch/arm/mm/tlb-v7.S
arch/arm/oprofile/Makefile
arch/arm/oprofile/common.c
arch/arm/plat-mxc/Kconfig
arch/arm/plat-mxc/Makefile
arch/arm/plat-mxc/audmux-v2.c
arch/arm/plat-mxc/devices/Kconfig
arch/arm/plat-mxc/devices/Makefile
arch/arm/plat-mxc/devices/platform-esdhc.c [new file with mode: 0644]
arch/arm/plat-mxc/devices/platform-fec.c [new file with mode: 0644]
arch/arm/plat-mxc/devices/platform-imx-dma.c [new file with mode: 0644]
arch/arm/plat-mxc/devices/platform-imx-i2c.c
arch/arm/plat-mxc/devices/platform-imx-ssi.c [new file with mode: 0644]
arch/arm/plat-mxc/devices/platform-imx-uart.c
arch/arm/plat-mxc/devices/platform-mxc_nand.c
arch/arm/plat-mxc/devices/platform-spi_imx.c
arch/arm/plat-mxc/ehci.c
arch/arm/plat-mxc/epit.c [new file with mode: 0644]
arch/arm/plat-mxc/gpio.c
arch/arm/plat-mxc/include/mach/board-mx31ads.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/common.h
arch/arm/plat-mxc/include/mach/debug-macro.S
arch/arm/plat-mxc/include/mach/devices-common.h
arch/arm/plat-mxc/include/mach/esdhc.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/eukrea-baseboards.h
arch/arm/plat-mxc/include/mach/iomux-mx51.h
arch/arm/plat-mxc/include/mach/iram.h [new file with mode: 0644]
arch/arm/plat-mxc/include/mach/mx21.h
arch/arm/plat-mxc/include/mach/mx25.h
arch/arm/plat-mxc/include/mach/mx27.h
arch/arm/plat-mxc/include/mach/mx31.h
arch/arm/plat-mxc/include/mach/mx35.h
arch/arm/plat-mxc/include/mach/mx3x.h
arch/arm/plat-mxc/include/mach/mx51.h
arch/arm/plat-mxc/include/mach/system.h
arch/arm/plat-mxc/include/mach/uncompress.h
arch/arm/plat-mxc/iram_alloc.c [new file with mode: 0644]
arch/arm/plat-nomadik/gpio.c
arch/arm/plat-nomadik/include/plat/gpio.h
arch/arm/plat-nomadik/include/plat/pincfg.h
arch/arm/plat-omap/fb.c
arch/arm/plat-omap/include/plat/smp.h
arch/arm/plat-pxa/include/plat/pxa27x_keypad.h [moved from arch/arm/mach-pxa/include/mach/pxa27x_keypad.h with 83% similarity]
arch/arm/plat-s5p/Kconfig
arch/arm/plat-s5p/Makefile
arch/arm/plat-s5p/clock.c
arch/arm/plat-s5p/cpu.c
arch/arm/plat-s5p/dev-onenand.c [moved from arch/arm/mach-s5pv210/dev-onenand.c with 59% similarity]
arch/arm/plat-s5p/dev-uart.c
arch/arm/plat-s5p/include/plat/pll.h
arch/arm/plat-s5p/include/plat/s5p-clock.h
arch/arm/plat-s5p/include/plat/s5p6440.h
arch/arm/plat-s5p/include/plat/s5p6450.h [new file with mode: 0644]
arch/arm/plat-samsung/include/plat/cpu.h
arch/arm/plat-samsung/include/plat/devs.h
arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h
arch/arm/plat-samsung/include/plat/s3c64xx-spi.h
arch/arm/plat-spear/include/plat/debug-macro.S
arch/arm/plat-stmp3xxx/include/mach/debug-macro.S
arch/arm/plat-tcc/Kconfig [new file with mode: 0644]
arch/arm/plat-tcc/Makefile [new file with mode: 0644]
arch/arm/plat-tcc/clock.c [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/clkdev.h [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/clock.h [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/debug-macro.S [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/entry-macro.S [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/hardware.h [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/io.h [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/irqs.h [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/memory.h [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/system.h [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/tcc8k-regs.h [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/timex.h [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/uncompress.h [new file with mode: 0644]
arch/arm/plat-tcc/include/mach/vmalloc.h [new file with mode: 0644]
arch/arm/plat-tcc/system.c [new file with mode: 0644]
arch/avr32/Kconfig
arch/avr32/include/asm/irqflags.h
arch/blackfin/include/asm/bfin5xx_spi.h
arch/blackfin/include/asm/ipipe.h
arch/blackfin/include/asm/irqflags.h
arch/blackfin/include/asm/mmu_context.h
arch/blackfin/include/asm/system.h
arch/blackfin/kernel/bfin_gpio.c
arch/blackfin/kernel/cplb-mpu/cplbmgr.c
arch/blackfin/kernel/ipipe.c
arch/blackfin/kernel/process.c
arch/blackfin/kernel/trace.c
arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h
arch/blackfin/mach-bf518/include/mach/pll.h [new file with mode: 0644]
arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h
arch/blackfin/mach-bf527/include/mach/pll.h [new file with mode: 0644]
arch/blackfin/mach-bf533/boards/blackstamp.c
arch/blackfin/mach-bf533/boards/ip0x.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf533/include/mach/cdefBF532.h
arch/blackfin/mach-bf533/include/mach/fio_flag.h [new file with mode: 0644]
arch/blackfin/mach-bf533/include/mach/pll.h [new file with mode: 0644]
arch/blackfin/mach-bf537/include/mach/cdefBF534.h
arch/blackfin/mach-bf537/include/mach/pll.h [new file with mode: 0644]
arch/blackfin/mach-bf538/include/mach/cdefBF538.h
arch/blackfin/mach-bf538/include/mach/pll.h [new file with mode: 0644]
arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h
arch/blackfin/mach-bf548/include/mach/pll.h [new file with mode: 0644]
arch/blackfin/mach-bf561/include/mach/cdefBF561.h
arch/blackfin/mach-bf561/include/mach/pll.h [new file with mode: 0644]
arch/blackfin/mach-common/cpufreq.c
arch/blackfin/mach-common/ints-priority.c
arch/blackfin/mach-common/pm.c
arch/cris/include/arch-v10/arch/irqflags.h [new file with mode: 0644]
arch/cris/include/arch-v10/arch/system.h
arch/cris/include/arch-v32/arch/irqflags.h [new file with mode: 0644]
arch/cris/include/arch-v32/arch/system.h
arch/cris/include/asm/irqflags.h [new file with mode: 0644]
arch/cris/include/asm/system.h
arch/frv/Kconfig
arch/frv/include/asm/irqflags.h [new file with mode: 0644]
arch/frv/include/asm/system.h
arch/frv/lib/Makefile
arch/frv/lib/perf_event.c [deleted file]
arch/h8300/include/asm/irqflags.h [new file with mode: 0644]
arch/h8300/include/asm/system.h
arch/ia64/Kconfig
arch/ia64/include/asm/compat.h [deleted file]
arch/ia64/include/asm/hardirq.h
arch/ia64/include/asm/iommu_table.h [new file with mode: 0644]
arch/ia64/include/asm/irqflags.h [new file with mode: 0644]
arch/ia64/include/asm/system.h
arch/ia64/kernel/Makefile
arch/ia64/kernel/cyclone.c
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/irq_ia64.c
arch/ia64/kernel/mca.c
arch/ia64/kernel/msi_ia64.c
arch/ia64/kernel/palinfo.c
arch/ia64/kernel/perfmon.c
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/stacktrace.c [new file with mode: 0644]
arch/ia64/kernel/unwind.c
arch/ia64/sn/kernel/msi_sn.c
arch/ia64/xen/xen_pv_ops.c
arch/m32r/include/asm/irqflags.h [new file with mode: 0644]
arch/m32r/include/asm/system.h
arch/m32r/kernel/irq.c
arch/m32r/platforms/m32104ut/setup.c
arch/m32r/platforms/m32700ut/setup.c
arch/m32r/platforms/mappi/setup.c
arch/m32r/platforms/mappi2/setup.c
arch/m32r/platforms/mappi3/setup.c
arch/m32r/platforms/oaks32r/setup.c
arch/m32r/platforms/opsput/setup.c
arch/m32r/platforms/usrv/setup.c
arch/m68k/include/asm/entry_no.h
arch/m68k/include/asm/irqflags.h [new file with mode: 0644]
arch/m68k/include/asm/system_mm.h
arch/m68k/include/asm/system_no.h
arch/m68knommu/kernel/asm-offsets.c
arch/m68knommu/platform/coldfire/head.S
arch/microblaze/include/asm/irqflags.h
arch/microblaze/include/asm/memblock.h
arch/microblaze/mm/init.c
arch/mips/Kbuild
arch/mips/alchemy/devboards/bcsr.c
arch/mips/ar7/irq.c
arch/mips/bcm63xx/irq.c
arch/mips/cavium-octeon/serial.c
arch/mips/dec/Platform
arch/mips/dec/setup.c
arch/mips/include/asm/irqflags.h
arch/mips/include/asm/mach-loongson/loongson.h
arch/mips/jazz/irq.c
arch/mips/jz4740/Platform
arch/mips/kernel/cevt-bcm1480.c
arch/mips/kernel/cevt-ds1287.c
arch/mips/kernel/cevt-gt641xx.c
arch/mips/kernel/cevt-r4k.c
arch/mips/kernel/cevt-sb1250.c
arch/mips/kernel/cevt-smtc.c
arch/mips/kernel/cevt-txx9.c
arch/mips/kernel/i8253.c
arch/mips/kernel/i8259.c
arch/mips/kernel/irq-gic.c
arch/mips/kernel/irq-rm7000.c
arch/mips/kernel/irq-rm9000.c
arch/mips/kernel/irq_cpu.c
arch/mips/kernel/irq_txx9.c
arch/mips/kernel/mips-mt-fpaff.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/smtc.c
arch/mips/kernel/traps.c
arch/mips/mti-malta/malta-platform.c
arch/mips/pci/ops-tx3927.c
arch/mips/pci/ops-tx4927.c
arch/mips/pmc-sierra/msp71xx/msp_irq_cic.c
arch/mips/powertv/asic/irq_asic.c
arch/mips/rb532/serial.c
arch/mips/sni/a20r.c
arch/mips/sni/pcimt.c
arch/mips/sni/pcit.c
arch/mips/sni/rm200.c
arch/mips/sni/time.c
arch/mips/txx9/generic/irq_tx4927.c
arch/mips/txx9/generic/irq_tx4938.c
arch/mips/txx9/generic/irq_tx4939.c
arch/mips/txx9/generic/setup.c
arch/mips/txx9/jmr3927/irq.c
arch/mips/txx9/rbtx4927/irq.c
arch/mips/txx9/rbtx4938/irq.c
arch/mips/txx9/rbtx4939/irq.c
arch/mips/vr41xx/common/irq.c
arch/mips/vr41xx/common/siu.c
arch/mn10300/include/asm/irqflags.h [new file with mode: 0644]
arch/mn10300/include/asm/system.h
arch/mn10300/kernel/entry.S
arch/parisc/Kconfig
arch/parisc/include/asm/irqflags.h [new file with mode: 0644]
arch/parisc/include/asm/perf_event.h
arch/parisc/include/asm/system.h
arch/powerpc/Kconfig
arch/powerpc/boot/addnote.c
arch/powerpc/boot/dts/bluestone.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8308_p1m.dts [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8536ds.dts
arch/powerpc/boot/dts/p1022ds.dts
arch/powerpc/boot/dts/p4080ds.dts
arch/powerpc/configs/44x/bluestone_defconfig [new file with mode: 0644]
arch/powerpc/configs/e55xx_smp_defconfig [new file with mode: 0644]
arch/powerpc/configs/ppc44x_defconfig
arch/powerpc/configs/ppc64e_defconfig
arch/powerpc/include/asm/checksum.h
arch/powerpc/include/asm/compat.h
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/elf.h
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/fsl_85xx_cache_sram.h [new file with mode: 0644]
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/irqflags.h
arch/powerpc/include/asm/kexec.h
arch/powerpc/include/asm/kvm_fpu.h
arch/powerpc/include/asm/lppaca.h
arch/powerpc/include/asm/machdep.h
arch/powerpc/include/asm/memblock.h
arch/powerpc/include/asm/mmu-book3e.h
arch/powerpc/include/asm/mmu.h
arch/powerpc/include/asm/paca.h
arch/powerpc/include/asm/page_64.h
arch/powerpc/include/asm/ppc-pci.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/processor.h
arch/powerpc/include/asm/pte-common.h
arch/powerpc/include/asm/rtas.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/system.h
arch/powerpc/include/asm/time.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/align.c
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/cpu_setup_44x.S
arch/powerpc/kernel/cpu_setup_fsl_booke.S
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/crash.c
arch/powerpc/kernel/dma-iommu.c
arch/powerpc/kernel/dma.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/fpu.S
arch/powerpc/kernel/head_40x.S
arch/powerpc/kernel/head_fsl_booke.S
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/lparcfg.c
arch/powerpc/kernel/machine_kexec.c
arch/powerpc/kernel/machine_kexec_32.c
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/perf_callchain.c
arch/powerpc/kernel/perf_event.c
arch/powerpc/kernel/perf_event_fsl_emb.c
arch/powerpc/kernel/ppc970-pmu.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/ptrace.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vdso.c
arch/powerpc/kernel/vdso32/Makefile
arch/powerpc/kernel/vdso64/Makefile
arch/powerpc/kernel/vio.c
arch/powerpc/kvm/Makefile
arch/powerpc/kvm/book3s_paired_singles.c
arch/powerpc/kvm/emulate.c
arch/powerpc/kvm/fpu.S
arch/powerpc/lib/Makefile
arch/powerpc/lib/checksum_64.S
arch/powerpc/lib/checksum_wrappers_64.c [new file with mode: 0644]
arch/powerpc/lib/copy_32.S
arch/powerpc/lib/ldstfp.S
arch/powerpc/lib/locks.c
arch/powerpc/lib/sstep.c
arch/powerpc/math-emu/Makefile
arch/powerpc/mm/40x_mmu.c
arch/powerpc/mm/44x_mmu.c
arch/powerpc/mm/Makefile
arch/powerpc/mm/fault.c
arch/powerpc/mm/fsl_booke_mmu.c
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/init_32.c
arch/powerpc/mm/init_64.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/mmu_context_nohash.c
arch/powerpc/mm/mmu_decl.h
arch/powerpc/mm/numa.c
arch/powerpc/mm/ppc_mmu_32.c
arch/powerpc/mm/tlb_nohash.c
arch/powerpc/mm/tlb_nohash_low.S
arch/powerpc/oprofile/Makefile
arch/powerpc/oprofile/backtrace.c
arch/powerpc/oprofile/op_model_fsl_emb.c
arch/powerpc/platforms/44x/Kconfig
arch/powerpc/platforms/44x/ppc44x_simple.c
arch/powerpc/platforms/83xx/Kconfig
arch/powerpc/platforms/83xx/mpc830x_rdb.c
arch/powerpc/platforms/85xx/Kconfig
arch/powerpc/platforms/85xx/Makefile
arch/powerpc/platforms/85xx/p1022_ds.c
arch/powerpc/platforms/85xx/p3041_ds.c [new file with mode: 0644]
arch/powerpc/platforms/85xx/p5020_ds.c [new file with mode: 0644]
arch/powerpc/platforms/85xx/smp.c
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/cell/axon_msi.c
arch/powerpc/platforms/cell/ras.c
arch/powerpc/platforms/cell/spider-pic.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/chrp/nvram.c
arch/powerpc/platforms/embedded6xx/wii.c
arch/powerpc/platforms/iseries/Makefile
arch/powerpc/platforms/iseries/dt.c
arch/powerpc/platforms/iseries/smp.c
arch/powerpc/platforms/maple/setup.c
arch/powerpc/platforms/powermac/pfunc_core.c
arch/powerpc/platforms/pseries/Makefile
arch/powerpc/platforms/pseries/dlpar.c
arch/powerpc/platforms/pseries/dtl.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/mobility.c [new file with mode: 0644]
arch/powerpc/platforms/pseries/pseries.h
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/pseries/xics.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/dart_iommu.c
arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h [new file with mode: 0644]
arch/powerpc/sysdev/fsl_85xx_cache_sram.c [new file with mode: 0644]
arch/powerpc/sysdev/fsl_85xx_l2ctlr.c [new file with mode: 0644]
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/fsl_pci.h
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/mpc8xxx_gpio.c
arch/powerpc/sysdev/mpic_pasemi_msi.c
arch/powerpc/sysdev/mpic_u3msi.c
arch/powerpc/sysdev/pmi.c
arch/powerpc/xmon/Makefile
arch/s390/Kconfig
arch/s390/include/asm/hardirq.h
arch/s390/include/asm/irqflags.h
arch/s390/include/asm/perf_event.h
arch/s390/include/asm/system.h
arch/s390/include/asm/topology.h
arch/s390/kernel/mem_detect.c
arch/s390/kernel/topology.c
arch/s390/mm/init.c
arch/s390/mm/maccess.c
arch/score/include/asm/irqflags.h
arch/sh/Kconfig
arch/sh/include/asm/irqflags.h
arch/sh/include/asm/memblock.h
arch/sh/include/asm/perf_event.h
arch/sh/include/asm/syscalls_32.h
arch/sh/kernel/irq.c
arch/sh/kernel/irq_32.c
arch/sh/kernel/perf_callchain.c
arch/sh/kernel/perf_event.c
arch/sh/mm/init.c
arch/sh/oprofile/Makefile
arch/sh/oprofile/common.c
arch/sh/oprofile/op_impl.h [deleted file]
arch/sparc/Kconfig
arch/sparc/include/asm/irqflags_32.h
arch/sparc/include/asm/irqflags_64.h
arch/sparc/include/asm/jump_label.h [new file with mode: 0644]
arch/sparc/include/asm/memblock.h
arch/sparc/include/asm/perf_event.h
arch/sparc/kernel/Makefile
arch/sparc/kernel/irq_32.c
arch/sparc/kernel/jump_label.c [new file with mode: 0644]
arch/sparc/kernel/module.c
arch/sparc/kernel/pci_msi.c
arch/sparc/kernel/pcr.c
arch/sparc/kernel/perf_event.c
arch/sparc/mm/init_64.c
arch/sparc/prom/p1275.c
arch/tile/include/asm/irqflags.h
arch/tile/kernel/irq.c
arch/um/kernel/irq.c
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/Makefile
arch/x86/include/asm/alternative.h
arch/x86/include/asm/amd_iommu.h
arch/x86/include/asm/amd_iommu_proto.h
arch/x86/include/asm/amd_iommu_types.h
arch/x86/include/asm/amd_nb.h [moved from arch/x86/include/asm/k8.h with 61% similarity]
arch/x86/include/asm/apb_timer.h
arch/x86/include/asm/apic.h
arch/x86/include/asm/apicdef.h
arch/x86/include/asm/calgary.h
arch/x86/include/asm/cpu.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/dwarf2.h
arch/x86/include/asm/e820.h
arch/x86/include/asm/efi.h
arch/x86/include/asm/entry_arch.h
arch/x86/include/asm/fixmap.h
arch/x86/include/asm/gart.h
arch/x86/include/asm/hardirq.h
arch/x86/include/asm/hpet.h
arch/x86/include/asm/hw_irq.h
arch/x86/include/asm/i387.h
arch/x86/include/asm/i8259.h
arch/x86/include/asm/io.h
arch/x86/include/asm/io_apic.h
arch/x86/include/asm/iommu_table.h [new file with mode: 0644]
arch/x86/include/asm/irq_remapping.h
arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/irqflags.h
arch/x86/include/asm/jump_label.h [new file with mode: 0644]
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/memblock.h [new file with mode: 0644]
arch/x86/include/asm/mrst.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/mwait.h [new file with mode: 0644]
arch/x86/include/asm/olpc_ofw.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/perf_event_p4.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_64.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/setup.h
arch/x86/include/asm/swiotlb.h
arch/x86/include/asm/vmi.h [deleted file]
arch/x86/include/asm/vmi_time.h [deleted file]
arch/x86/kernel/Makefile
arch/x86/kernel/acpi/cstate.c
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/alternative.c
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/amd_iommu_init.c
arch/x86/kernel/amd_nb.c [moved from arch/x86/kernel/k8.c with 66% similarity]
arch/x86/kernel/apb_timer.c
arch/x86/kernel/aperture_64.c
arch/x86/kernel/apic/apic.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/apic/nmi.c
arch/x86/kernel/apic/numaq_32.c
arch/x86/kernel/apic/probe_64.c
arch/x86/kernel/check.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce_amd.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/mtrr/cleanup.c
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event_amd.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_p4.c
arch/x86/kernel/cpu/perfctr-watchdog.c
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/crash_dump_64.c
arch/x86/kernel/e820.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/early_printk.c
arch/x86/kernel/early_printk_mrst.c [new file with mode: 0644]
arch/x86/kernel/efi.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/ftrace.c
arch/x86/kernel/head.c
arch/x86/kernel/head32.c
arch/x86/kernel/head64.c
arch/x86/kernel/hpet.c
arch/x86/kernel/i387.c
arch/x86/kernel/i8259.c
arch/x86/kernel/irq.c
arch/x86/kernel/irq_work.c [new file with mode: 0644]
arch/x86/kernel/irqinit.c
arch/x86/kernel/jump_label.c [new file with mode: 0644]
arch/x86/kernel/kprobes.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/module.c
arch/x86/kernel/mpparse.c
arch/x86/kernel/olpc-xo1.c [new file with mode: 0644]
arch/x86/kernel/olpc.c
arch/x86/kernel/olpc_ofw.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pci-dma.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/pci-iommu_table.c [new file with mode: 0644]
arch/x86/kernel/pci-swiotlb.c
arch/x86/kernel/pmtimer_64.c [deleted file]
arch/x86/kernel/process_64.c
arch/x86/kernel/reboot.c
arch/x86/kernel/setup.c
arch/x86/kernel/setup_percpu.c
arch/x86/kernel/sfi.c
arch/x86/kernel/smpboot.c
arch/x86/kernel/sys_i386_32.c
arch/x86/kernel/trampoline.c
arch/x86/kernel/traps.c
arch/x86/kernel/tsc.c
arch/x86/kernel/uv_irq.c
arch/x86/kernel/visws_quirks.c
arch/x86/kernel/vmi_32.c [deleted file]
arch/x86/kernel/vmiclock_32.c [deleted file]
arch/x86/kernel/vmlinux.lds.S
arch/x86/kvm/lapic.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lguest/boot.c
arch/x86/lib/memcpy_32.c
arch/x86/lib/memcpy_64.S
arch/x86/lib/memmove_64.c
arch/x86/mm/Makefile
arch/x86/mm/fault.c
arch/x86/mm/init.c
arch/x86/mm/init_32.c
arch/x86/mm/init_64.c
arch/x86/mm/ioremap.c
arch/x86/mm/k8topology_64.c
arch/x86/mm/kmemcheck/kmemcheck.c
arch/x86/mm/kmemcheck/opcode.c
arch/x86/mm/memblock.c [new file with mode: 0644]
arch/x86/mm/memtest.c
arch/x86/mm/numa_32.c
arch/x86/mm/numa_64.c
arch/x86/mm/pgtable.c
arch/x86/mm/srat_32.c
arch/x86/mm/srat_64.c
arch/x86/mm/tlb.c
arch/x86/oprofile/backtrace.c
arch/x86/oprofile/nmi_int.c
arch/x86/oprofile/op_model_amd.c
arch/x86/pci/olpc.c
arch/x86/xen/enlighten.c
arch/x86/xen/mmu.c
arch/x86/xen/pci-swiotlb-xen.c
arch/x86/xen/setup.c
arch/x86/xen/spinlock.c
arch/xtensa/include/asm/irqflags.h [new file with mode: 0644]
arch/xtensa/include/asm/system.h
arch/xtensa/kernel/irq.c
block/bsg.c
crypto/des_generic.c
drivers/acpi/acpi_pad.c
drivers/amba/bus.c
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_platform.c
drivers/ata/ata_generic.c
drivers/ata/ata_piix.c
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-pmp.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/libata-transport.c [new file with mode: 0644]
drivers/ata/libata-transport.h [new file with mode: 0644]
drivers/ata/libata.h
drivers/ata/pata_bf54x.c
drivers/ata/pata_cmd640.c
drivers/ata/pata_pcmcia.c
drivers/ata/pata_pdc202xx_old.c
drivers/ata/pata_samsung_cf.c
drivers/ata/pata_scc.c
drivers/ata/pata_sil680.c
drivers/ata/pata_sl82c105.c
drivers/ata/sata_fsl.c
drivers/ata/sata_inic162x.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/ata/sata_sil24.c
drivers/ata/sata_via.c
drivers/base/power/Makefile
drivers/base/power/generic_ops.c
drivers/base/power/main.c
drivers/base/power/opp.c [new file with mode: 0644]
drivers/base/power/power.h
drivers/base/power/runtime.c
drivers/base/power/sysfs.c
drivers/base/power/trace.c
drivers/base/power/wakeup.c
drivers/base/topology.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/rbd.c [new file with mode: 0644]
drivers/block/rbd_types.h [new file with mode: 0644]
drivers/block/virtio_blk.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/dtl1_cs.c
drivers/char/agp/Kconfig
drivers/char/agp/amd64-agp.c
drivers/char/agp/generic.c
drivers/char/pcmcia/cm4000_cs.c
drivers/char/pcmcia/cm4040_cs.c
drivers/char/pcmcia/ipwireless/main.c
drivers/char/pcmcia/ipwireless/main.h
drivers/char/pcmcia/ipwireless/tty.h
drivers/char/pcmcia/synclink_cs.c
drivers/char/tpm/tpm.c
drivers/char/virtio_console.c
drivers/edac/Kconfig
drivers/edac/Makefile
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h
drivers/edac/amd64_edac_dbg.c
drivers/edac/edac_device_sysfs.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_mce_amd.c [deleted file]
drivers/edac/edac_module.c
drivers/edac/edac_module.h
drivers/edac/edac_pci_sysfs.c
drivers/edac/edac_stub.c
drivers/edac/mce_amd.c [new file with mode: 0644]
drivers/edac/mce_amd.h [moved from drivers/edac/edac_mce_amd.h with 65% similarity]
drivers/edac/mce_amd_inj.c [new file with mode: 0644]
drivers/firmware/Kconfig
drivers/gpio/tc35892-gpio.c
drivers/i2c/busses/i2c-pasemi.c
drivers/ide/ide-cs.c
drivers/idle/intel_idle.c
drivers/input/evdev.c
drivers/input/keyboard/Kconfig
drivers/input/keyboard/pxa27x_keypad.c
drivers/input/misc/hp_sdc_rtc.c
drivers/input/serio/hil_mlc.c
drivers/input/serio/hp_sdc.c
drivers/isdn/act2000/act2000.h
drivers/isdn/hardware/avm/avm_cs.c
drivers/isdn/hisax/avma1_cs.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/elsa_cs.c
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/sedlbauer_cs.c
drivers/isdn/hisax/teles_cs.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-netxbig.c [new file with mode: 0644]
drivers/leds/leds-ns2.c
drivers/macintosh/adb.c
drivers/macintosh/via-pmu-led.c
drivers/mfd/ab8500-spi.c
drivers/mfd/twl4030-irq.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
drivers/mmc/host/sdricoh_cs.c
drivers/mtd/maps/pcmciamtd.c
drivers/net/3c527.c
drivers/net/Kconfig
drivers/net/bfin_mac.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/mkiss.c
drivers/net/irda/sir_dev.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/com20020_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/ppp_async.c
drivers/net/smc91x.c
drivers/net/wan/cosa.c
drivers/net/wireless/airo_cs.c
drivers/net/wireless/atmel_cs.c
drivers/net/wireless/b43/pcmcia.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/orinoco/orinoco_cs.c
drivers/net/wireless/orinoco/spectrum_cs.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/ray_cs.h
drivers/net/wireless/wl3501_cs.c
drivers/oprofile/oprof.c
drivers/oprofile/oprof.h
drivers/oprofile/oprofile_files.c
drivers/oprofile/oprofile_perf.c [new file with mode: 0644]
drivers/oprofile/oprofilefs.c
drivers/parport/parport_cs.c
drivers/parport/share.c
drivers/pci/dmar.c
drivers/pci/htirq.c
drivers/pci/intr_remapping.c
drivers/pci/msi.c
drivers/pcmcia/au1000_generic.c
drivers/pcmcia/au1000_generic.h
drivers/pcmcia/au1000_pb1x00.c
drivers/pcmcia/cistpl.c
drivers/pcmcia/cs.c
drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
drivers/pcmcia/i82092.c
drivers/pcmcia/i82365.c
drivers/pcmcia/m32r_cfc.c
drivers/pcmcia/m32r_pcc.c
drivers/pcmcia/m8xx_pcmcia.c
drivers/pcmcia/o2micro.h
drivers/pcmcia/pcmcia_cis.c
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/pd6729.c
drivers/pcmcia/rsrc_iodyn.c
drivers/pcmcia/rsrc_mgr.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/sa1100_generic.c
drivers/pcmcia/soc_common.c
drivers/pcmcia/soc_common.h
drivers/pcmcia/socket_sysfs.c
drivers/pcmcia/tcic.c
drivers/pcmcia/vrc4173_cardu.c
drivers/pcmcia/xxs1500_ss.c
drivers/pcmcia/yenta_socket.c
drivers/s390/char/sclp.c
drivers/scsi/pcmcia/aha152x_stub.c
drivers/scsi/pcmcia/fdomain_stub.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pcmcia/qlogic_stub.c
drivers/scsi/pcmcia/sym53c500_cs.c
drivers/scsi/scsi.c
drivers/serial/Kconfig
drivers/serial/ioc3_serial.c
drivers/serial/samsung.c
drivers/serial/serial_cs.c
drivers/spi/Kconfig
drivers/spi/Makefile
drivers/spi/amba-pl022.c
drivers/spi/atmel_spi.c
drivers/spi/omap2_mcspi.c
drivers/spi/orion_spi.c
drivers/spi/spi_bfin5xx.c
drivers/spi/spi_fsl_espi.c [new file with mode: 0644]
drivers/spi/spi_fsl_lib.c [new file with mode: 0644]
drivers/spi/spi_fsl_lib.h [new file with mode: 0644]
drivers/spi/spi_fsl_spi.c [moved from drivers/spi/spi_mpc8xxx.c with 64% similarity]
drivers/spi/spi_imx.c
drivers/spi/spi_s3c64xx.c
drivers/spi/spi_topcliff_pch.c [new file with mode: 0644]
drivers/ssb/main.c
drivers/ssb/pcmcia.c
drivers/ssb/scan.c
drivers/staging/comedi/drivers/cb_das16_cs.c
drivers/staging/comedi/drivers/das08_cs.c
drivers/staging/comedi/drivers/ni_daq_700.c
drivers/staging/comedi/drivers/ni_daq_dio24.c
drivers/staging/comedi/drivers/ni_labpc_cs.c
drivers/staging/comedi/drivers/ni_mio_cs.c
drivers/staging/comedi/drivers/quatech_daqp_cs.c
drivers/staging/wlags49_h2/wl_cs.c
drivers/staging/wlags49_h2/wl_internal.h
drivers/staging/wlags49_h2/wl_main.c
drivers/telephony/ixj_pcmcia.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/sl811_cs.c
drivers/vhost/net.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/video/omap2/vram.c
drivers/video/pxa168fb.c
drivers/vlynq/vlynq.c
drivers/watchdog/Kconfig
drivers/watchdog/booke_wdt.c
drivers/watchdog/octeon-wdt-main.c
drivers/xen/events.c
fs/affs/super.c
fs/binfmt_elf.c
fs/ceph/Kconfig
fs/ceph/Makefile
fs/ceph/README [deleted file]
fs/ceph/addr.c
fs/ceph/caps.c
fs/ceph/ceph_frag.c
fs/ceph/debugfs.c
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/ceph/ioctl.h
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/mdsmap.c
fs/ceph/pagelist.c [deleted file]
fs/ceph/snap.c
fs/ceph/strings.c [moved from fs/ceph/ceph_strings.c with 59% similarity]
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/ext3/super.c
fs/ext4/super.c
fs/gfs2/Kconfig
fs/gfs2/aops.c
fs/gfs2/bmap.c
fs/gfs2/bmap.h
fs/gfs2/dentry.c
fs/gfs2/dir.c
fs/gfs2/dir.h
fs/gfs2/export.c
fs/gfs2/file.c
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/glops.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/inode.h
fs/gfs2/lock_dlm.c
fs/gfs2/main.c
fs/gfs2/ops_fstype.c
fs/gfs2/ops_inode.c
fs/gfs2/quota.c
fs/gfs2/recovery.c
fs/gfs2/rgrp.c
fs/gfs2/rgrp.h
fs/gfs2/super.c
fs/gfs2/sys.c
fs/gfs2/trace_gfs2.h
fs/gfs2/trans.h
fs/gfs2/xattr.c
fs/hfs/bfind.c
fs/hfs/btree.c
fs/hfs/btree.h
fs/hfsplus/bfind.c
fs/hfsplus/bitmap.c
fs/hfsplus/brec.c
fs/hfsplus/btree.c
fs/hfsplus/catalog.c
fs/hfsplus/dir.c
fs/hfsplus/extents.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/hfsplus_raw.h
fs/hfsplus/inode.c
fs/hfsplus/ioctl.c
fs/hfsplus/options.c
fs/hfsplus/part_tbl.c
fs/hfsplus/super.c
fs/hfsplus/unicode.c
fs/hfsplus/wrapper.c
fs/jbd2/journal.c
fs/libfs.c
fs/ocfs2/aops.c
fs/ocfs2/aops.h
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/heartbeat.h
fs/ocfs2/cluster/masklog.h
fs/ocfs2/cluster/nodemanager.c
fs/ocfs2/cluster/ocfs2_nodemanager.h
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dcache.c
fs/ocfs2/dcache.h
fs/ocfs2/dlm/dlmcommon.h
fs/ocfs2/dlm/dlmdebug.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlmglue.c
fs/ocfs2/file.c
fs/ocfs2/inode.c
fs/ocfs2/inode.h
fs/ocfs2/ioctl.c
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/mmap.c
fs/ocfs2/namei.c
fs/ocfs2/ocfs2.h
fs/ocfs2/ocfs2_fs.h
fs/ocfs2/ocfs2_ioctl.h
fs/ocfs2/refcounttree.c
fs/ocfs2/refcounttree.h
fs/ocfs2/slot_map.c
fs/ocfs2/stack_o2cb.c
fs/ocfs2/suballoc.c
fs/ocfs2/super.c
fs/ocfs2/sysfile.c
fs/ocfs2/xattr.c
fs/sysfs/group.c
include/asm-generic/atomic.h
include/asm-generic/cmpxchg-local.h
include/asm-generic/hardirq.h
include/asm-generic/irqflags.h
include/asm-generic/pgtable.h
include/asm-generic/vmlinux.lds.h
include/linux/acpi_pmtmr.h
include/linux/amba/bus.h
include/linux/amba/mmci.h
include/linux/amba/pl022.h
include/linux/amba/serial.h
include/linux/ata.h
include/linux/ceph/auth.h [moved from fs/ceph/auth.h with 97% similarity]
include/linux/ceph/buffer.h [moved from fs/ceph/buffer.h with 100% similarity]
include/linux/ceph/ceph_debug.h [moved from fs/ceph/ceph_debug.h with 86% similarity]
include/linux/ceph/ceph_frag.h [moved from fs/ceph/ceph_frag.h with 100% similarity]
include/linux/ceph/ceph_fs.h [moved from fs/ceph/ceph_fs.h with 99% similarity]
include/linux/ceph/ceph_hash.h [moved from fs/ceph/ceph_hash.h with 100% similarity]
include/linux/ceph/debugfs.h [new file with mode: 0644]
include/linux/ceph/decode.h [moved from fs/ceph/decode.h with 96% similarity]
include/linux/ceph/libceph.h [new file with mode: 0644]
include/linux/ceph/mdsmap.h [moved from fs/ceph/mdsmap.h with 100% similarity]
include/linux/ceph/messenger.h [moved from fs/ceph/messenger.h with 95% similarity]
include/linux/ceph/mon_client.h [moved from fs/ceph/mon_client.h with 99% similarity]
include/linux/ceph/msgpool.h [moved from fs/ceph/msgpool.h with 100% similarity]
include/linux/ceph/msgr.h [moved from fs/ceph/msgr.h with 100% similarity]
include/linux/ceph/osd_client.h [moved from fs/ceph/osd_client.h with 76% similarity]
include/linux/ceph/osdmap.h [moved from fs/ceph/osdmap.h with 97% similarity]
include/linux/ceph/pagelist.h [moved from fs/ceph/pagelist.h with 62% similarity]
include/linux/ceph/rados.h [moved from fs/ceph/rados.h with 100% similarity]
include/linux/ceph/types.h [moved from fs/ceph/types.h with 100% similarity]
include/linux/cgroup.h
include/linux/compiler.h
include/linux/cred.h
include/linux/crush/crush.h [moved from fs/ceph/crush/crush.h with 100% similarity]
include/linux/crush/hash.h [moved from fs/ceph/crush/hash.h with 100% similarity]
include/linux/crush/mapper.h [moved from fs/ceph/crush/mapper.h with 100% similarity]
include/linux/debug_locks.h
include/linux/dmar.h
include/linux/dynamic_debug.h
include/linux/early_res.h [deleted file]
include/linux/edac.h
include/linux/fdtable.h
include/linux/fs.h
include/linux/ftrace_event.h
include/linux/genhd.h
include/linux/hardirq.h
include/linux/htirq.h
include/linux/idr.h
include/linux/init_task.h
include/linux/input.h
include/linux/interrupt.h
include/linux/iocontext.h
include/linux/irq.h
include/linux/irq_work.h [new file with mode: 0644]
include/linux/irqdesc.h [new file with mode: 0644]
include/linux/irqflags.h
include/linux/irqnr.h
include/linux/jump_label.h [new file with mode: 0644]
include/linux/jump_label_ref.h [new file with mode: 0644]
include/linux/kernel.h
include/linux/key.h
include/linux/kvm_host.h
include/linux/libata.h
include/linux/list.h
include/linux/lockdep.h
include/linux/memblock.h
include/linux/mfd/tc35892.h
include/linux/mm.h
include/linux/mm_types.h
include/linux/module.h
include/linux/msi.h
include/linux/netfilter/nfnetlink_conntrack.h
include/linux/netfilter/xt_SECMARK.h
include/linux/nfs_fs.h
include/linux/notifier.h
include/linux/opp.h [new file with mode: 0644]
include/linux/oprofile.h
include/linux/pci_ids.h
include/linux/percpu-defs.h
include/linux/percpu.h
include/linux/perf_event.h
include/linux/pm.h
include/linux/pm_runtime.h
include/linux/pm_wakeup.h
include/linux/radix-tree.h
include/linux/rculist.h
include/linux/rculist_nulls.h
include/linux/rcupdate.h
include/linux/rcutiny.h
include/linux/rcutree.h
include/linux/resume-trace.h
include/linux/sched.h
include/linux/security.h
include/linux/selinux.h
include/linux/spinlock.h
include/linux/srcu.h
include/linux/stop_machine.h
include/linux/sunrpc/auth_gss.h
include/linux/suspend.h
include/linux/sysfs.h
include/linux/thread_info.h
include/linux/topology.h
include/linux/tracepoint.h
include/net/cls_cgroup.h
include/net/netfilter/nf_conntrack.h
include/pcmcia/cs.h [deleted file]
include/pcmcia/ds.h
include/pcmcia/ss.h
include/trace/events/irq.h
include/trace/events/napi.h
include/trace/events/net.h [new file with mode: 0644]
include/trace/events/power.h
include/trace/events/sched.h
include/trace/events/skb.h
init/Kconfig
init/main.c
kernel/Makefile
kernel/cgroup.c
kernel/cpuset.c
kernel/early_res.c [deleted file]
kernel/exit.c
kernel/futex.c
kernel/futex_compat.c
kernel/hung_task.c
kernel/hw_breakpoint.c
kernel/irq/Kconfig [new file with mode: 0644]
kernel/irq/Makefile
kernel/irq/autoprobe.c
kernel/irq/chip.c
kernel/irq/dummychip.c [new file with mode: 0644]
kernel/irq/handle.c
kernel/irq/internals.h
kernel/irq/irqdesc.c [new file with mode: 0644]
kernel/irq/manage.c
kernel/irq/migration.c
kernel/irq/numa_migrate.c [deleted file]
kernel/irq/proc.c
kernel/irq/resend.c
kernel/irq/spurious.c
kernel/irq_work.c [new file with mode: 0644]
kernel/jump_label.c [new file with mode: 0644]
kernel/kprobes.c
kernel/lockdep.c
kernel/module.c
kernel/perf_event.c
kernel/pid.c
kernel/power/Kconfig
kernel/power/hibernate.c
kernel/power/main.c
kernel/power/power.h
kernel/power/process.c
kernel/power/snapshot.c
kernel/power/swap.c
kernel/printk.c
kernel/rcupdate.c
kernel/rcutiny.c
kernel/rcutiny_plugin.h
kernel/rcutorture.c
kernel/rcutree.c
kernel/rcutree.h
kernel/rcutree_plugin.h
kernel/rcutree_trace.c
kernel/sched.c
kernel/sched_fair.c
kernel/sched_features.h
kernel/sched_rt.c
kernel/sched_stoptask.c [new file with mode: 0644]
kernel/softirq.c
kernel/srcu.c
kernel/stop_machine.c
kernel/sys_ni.c
kernel/test_kprobes.c
kernel/time/ntp.c
kernel/timer.c
kernel/trace/Kconfig
kernel/trace/ftrace.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_event_perf.c
kernel/trace/trace_events.c
kernel/trace/trace_functions_graph.c
kernel/trace/trace_irqsoff.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_sched_wakeup.c
kernel/trace/trace_workqueue.c
kernel/tracepoint.c
kernel/watchdog.c
lib/Kconfig.debug
lib/dynamic_debug.c
lib/radix-tree.c
lib/swiotlb.c
mm/bootmem.c
mm/memblock.c
mm/memory.c
mm/page_alloc.c
mm/sparse-vmemmap.c
mm/vmalloc.c
net/Kconfig
net/Makefile
net/ceph/Kconfig [new file with mode: 0644]
net/ceph/Makefile [new file with mode: 0644]
net/ceph/armor.c [moved from fs/ceph/armor.c with 100% similarity]
net/ceph/auth.c [moved from fs/ceph/auth.c with 97% similarity]
net/ceph/auth_none.c [moved from fs/ceph/auth_none.c with 96% similarity]
net/ceph/auth_none.h [moved from fs/ceph/auth_none.h with 94% similarity]
net/ceph/auth_x.c [moved from fs/ceph/auth_x.c with 99% similarity]
net/ceph/auth_x.h [moved from fs/ceph/auth_x.h with 96% similarity]
net/ceph/auth_x_protocol.h [moved from fs/ceph/auth_x_protocol.h with 100% similarity]
net/ceph/buffer.c [moved from fs/ceph/buffer.c with 86% similarity]
net/ceph/ceph_common.c [new file with mode: 0644]
net/ceph/ceph_fs.c [moved from fs/ceph/ceph_fs.c with 92% similarity]
net/ceph/ceph_hash.c [moved from fs/ceph/ceph_hash.c with 98% similarity]
net/ceph/ceph_strings.c [new file with mode: 0644]
net/ceph/crush/crush.c [moved from fs/ceph/crush/crush.c with 99% similarity]
net/ceph/crush/hash.c [moved from fs/ceph/crush/hash.c with 99% similarity]
net/ceph/crush/mapper.c [moved from fs/ceph/crush/mapper.c with 99% similarity]
net/ceph/crypto.c [moved from fs/ceph/crypto.c with 99% similarity]
net/ceph/crypto.h [moved from fs/ceph/crypto.h with 95% similarity]
net/ceph/debugfs.c [new file with mode: 0644]
net/ceph/messenger.c [moved from fs/ceph/messenger.c with 89% similarity]
net/ceph/mon_client.c [moved from fs/ceph/mon_client.c with 94% similarity]
net/ceph/msgpool.c [moved from fs/ceph/msgpool.c with 95% similarity]
net/ceph/osd_client.c [moved from fs/ceph/osd_client.c with 84% similarity]
net/ceph/osdmap.c [moved from fs/ceph/osdmap.c with 97% similarity]
net/ceph/pagelist.c [new file with mode: 0644]
net/ceph/pagevec.c [new file with mode: 0644]
net/core/datagram.c
net/core/dev.c
net/core/net-traces.c
net/core/skbuff.c
net/core/sock.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
net/ipv4/netfilter/nf_nat_core.c
net/netfilter/core.c
net/netfilter/nf_conntrack_ecache.c
net/netfilter/nf_conntrack_extend.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_log.c
net/netfilter/nf_queue.c
net/netfilter/xt_CT.c
net/netfilter/xt_SECMARK.c
net/sched/cls_cgroup.c
scripts/Makefile
scripts/Makefile.build
scripts/Makefile.lib
scripts/basic/Makefile
scripts/basic/hash.c [deleted file]
scripts/gcc-goto.sh [new file with mode: 0644]
scripts/recordmcount.c [new file with mode: 0644]
scripts/recordmcount.h [new file with mode: 0644]
scripts/recordmcount.pl
security/apparmor/.gitignore
security/apparmor/apparmorfs.c
security/capability.c
security/commoncap.c
security/security.c
security/selinux/Makefile
security/selinux/exports.c
security/selinux/hooks.c
security/selinux/include/classmap.h
security/selinux/include/security.h
security/selinux/selinuxfs.c
security/selinux/ss/Makefile [deleted file]
security/selinux/ss/avtab.c
security/selinux/ss/avtab.h
security/selinux/ss/conditional.c
security/selinux/ss/conditional.h
security/selinux/ss/ebitmap.c
security/selinux/ss/ebitmap.h
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c
security/selinux/ss/status.c [new file with mode: 0644]
security/smack/smack_lsm.c
security/tomoyo/common.c
sound/pcmcia/pdaudiocf/pdaudiocf.c
sound/pcmcia/pdaudiocf/pdaudiocf.h
sound/pcmcia/vx/vxpocket.c
sound/pcmcia/vx/vxpocket.h
tools/perf/Documentation/perf-annotate.txt
tools/perf/Documentation/perf-list.txt
tools/perf/Documentation/perf-probe.txt
tools/perf/Documentation/perf-report.txt
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-probe.c
tools/perf/builtin-report.c
tools/perf/builtin-trace.c
tools/perf/feature-tests.mak
tools/perf/scripts/perl/bin/failed-syscalls-report
tools/perf/scripts/perl/bin/rw-by-file-report
tools/perf/scripts/perl/bin/rw-by-pid-report
tools/perf/scripts/perl/bin/rwtop-report
tools/perf/scripts/perl/bin/wakeup-latency-report
tools/perf/scripts/perl/bin/workqueue-stats-report
tools/perf/scripts/python/Perf-Trace-Util/lib/Perf/Trace/Util.py
tools/perf/scripts/python/bin/failed-syscalls-by-pid-report
tools/perf/scripts/python/bin/netdev-times-record [new file with mode: 0644]
tools/perf/scripts/python/bin/netdev-times-report [new file with mode: 0644]
tools/perf/scripts/python/bin/sched-migration-report
tools/perf/scripts/python/bin/sctop-report
tools/perf/scripts/python/bin/syscall-counts-by-pid-report
tools/perf/scripts/python/bin/syscall-counts-report
tools/perf/scripts/python/failed-syscalls-by-pid.py
tools/perf/scripts/python/netdev-times.py [new file with mode: 0644]
tools/perf/scripts/python/sctop.py
tools/perf/scripts/python/syscall-counts-by-pid.py
tools/perf/scripts/python/syscall-counts.py
tools/perf/util/cache.h
tools/perf/util/callchain.c
tools/perf/util/callchain.h
tools/perf/util/hist.c
tools/perf/util/map.h
tools/perf/util/path.c
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h
tools/perf/util/probe-finder.c
tools/perf/util/probe-finder.h
tools/perf/util/sort.h
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/ui/browser.c
tools/perf/util/ui/browser.h
tools/perf/util/ui/browsers/annotate.c
tools/perf/util/ui/browsers/hists.c
tools/perf/util/ui/browsers/map.c
tools/perf/util/ui/util.c
tools/perf/util/util.h

diff --git a/Documentation/ABI/testing/sysfs-ata b/Documentation/ABI/testing/sysfs-ata
new file mode 100644 (file)
index 0000000..0a93215
--- /dev/null
@@ -0,0 +1,99 @@
+What:          /sys/class/ata_...
+Date:          August 2008
+Contact:       Gwendal Grignou<gwendal@google.com>
+Description:
+
+Provide a place in sysfs for storing the ATA topology of the system.  This allows
+retrieving various information about ATA objects.
+
+Files under /sys/class/ata_port
+-------------------------------
+
+       For each port, a directory ataX is created where X is the ata_port_id of
+       the port. The device parent is the ata host device.
+
+idle_irq (read)
+
+       Number of IRQ received by the port while idle [some ata HBA only].
+
+nr_pmp_links (read)
+
+       If a SATA Port Multiplier (PM) is connected, number of link behind it.
+
+Files under /sys/class/ata_link
+-------------------------------
+
+       Behind each port, there is a ata_link. If there is a SATA PM in the
+       topology, 15 ata_link objects are created.
+
+       If a link is behind a port, the directory name is linkX, where X is
+       ata_port_id of the port.
+       If a link is behind a PM, its name is linkX.Y where X is ata_port_id
+       of the parent port and Y the PM port.
+
+hw_sata_spd_limit
+
+       Maximum speed supported by the connected SATA device.
+
+sata_spd_limit
+
+       Maximum speed imposed by libata.
+
+sata_spd
+
+       Current speed of the link [1.5, 3Gps,...].
+
+Files under /sys/class/ata_device
+---------------------------------
+
+       Behind each link, up to two ata device are created.
+       The name of the directory is devX[.Y].Z where:
+       - X is ata_port_id of the port where the device is connected,
+       - Y the port of the PM if any, and
+       - Z the device id: for PATA, there is usually 2 devices [0,1],
+       only 1 for SATA.
+
+class
+       Device class. Can be "ata" for disk, "atapi" for packet device,
+       "pmp" for PM, or "none" if no device was found behind the link.
+
+dma_mode
+
+       Transfer modes supported by the device when in DMA mode.
+       Mostly used by PATA device.
+
+pio_mode
+
+       Transfer modes supported by the device when in PIO mode.
+       Mostly used by PATA device.
+
+xfer_mode
+
+       Current transfer mode.
+
+id
+
+       Cached result of IDENTIFY command, as described in ATA8 7.16 and 7.17.
+       Only valid if the device is not a PM.
+
+gscr
+
+       Cached result of the dump of PM GSCR register.
+       Valid registers are:
+       0:      SATA_PMP_GSCR_PROD_ID,
+       1:      SATA_PMP_GSCR_REV,
+       2:      SATA_PMP_GSCR_PORT_INFO,
+       32:     SATA_PMP_GSCR_ERROR,
+       33:     SATA_PMP_GSCR_ERROR_EN,
+       64:     SATA_PMP_GSCR_FEAT,
+       96:     SATA_PMP_GSCR_FEAT_EN,
+       130:    SATA_PMP_GSCR_SII_GPIO
+       Only valid if the device is a PM.
+
+spdn_cnt
+
+       Number of time libata decided to lower the speed of link due to errors.
+
+ering
+
+       Formatted output of the error ring of the device.
index 6123c523bfd7961c8cdc235aee2b96367062faf5..7628cd1bc36a5e8080a646da492736c3e43b917d 100644 (file)
@@ -77,3 +77,91 @@ Description:
                devices this attribute is set to "enabled" by bus type code or
                device drivers and in that cases it should be safe to leave the
                default value.
+
+What:          /sys/devices/.../power/wakeup_count
+Date:          September 2010
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/devices/.../wakeup_count attribute contains the number
+               of signaled wakeup events associated with the device.  This
+               attribute is read-only.  If the device is not enabled to wake up
+               the system from sleep states, this attribute is empty.
+
+What:          /sys/devices/.../power/wakeup_active_count
+Date:          September 2010
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/devices/.../wakeup_active_count attribute contains the
+               number of times the processing of wakeup events associated with
+               the device was completed (at the kernel level).  This attribute
+               is read-only.  If the device is not enabled to wake up the
+               system from sleep states, this attribute is empty.
+
+What:          /sys/devices/.../power/wakeup_hit_count
+Date:          September 2010
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/devices/.../wakeup_hit_count attribute contains the
+               number of times the processing of a wakeup event associated with
+               the device might prevent the system from entering a sleep state.
+               This attribute is read-only.  If the device is not enabled to
+               wake up the system from sleep states, this attribute is empty.
+
+What:          /sys/devices/.../power/wakeup_active
+Date:          September 2010
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/devices/.../wakeup_active attribute contains either 1,
+               or 0, depending on whether or not a wakeup event associated with
+               the device is being processed (1).  This attribute is read-only.
+               If the device is not enabled to wake up the system from sleep
+               states, this attribute is empty.
+
+What:          /sys/devices/.../power/wakeup_total_time_ms
+Date:          September 2010
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/devices/.../wakeup_total_time_ms attribute contains
+               the total time of processing wakeup events associated with the
+               device, in milliseconds.  This attribute is read-only.  If the
+               device is not enabled to wake up the system from sleep states,
+               this attribute is empty.
+
+What:          /sys/devices/.../power/wakeup_max_time_ms
+Date:          September 2010
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/devices/.../wakeup_max_time_ms attribute contains
+               the maximum time of processing a single wakeup event associated
+               with the device, in milliseconds.  This attribute is read-only.
+               If the device is not enabled to wake up the system from sleep
+               states, this attribute is empty.
+
+What:          /sys/devices/.../power/wakeup_last_time_ms
+Date:          September 2010
+Contact:       Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+               The /sys/devices/.../wakeup_last_time_ms attribute contains
+               the value of the monotonic clock corresponding to the time of
+               signaling the last wakeup event associated with the device, in
+               milliseconds.  This attribute is read-only.  If the device is
+               not enabled to wake up the system from sleep states, this
+               attribute is empty.
+
+What:          /sys/devices/.../power/autosuspend_delay_ms
+Date:          September 2010
+Contact:       Alan Stern <stern@rowland.harvard.edu>
+Description:
+               The /sys/devices/.../power/autosuspend_delay_ms attribute
+               contains the autosuspend delay value (in milliseconds).  Some
+               drivers do not want their device to suspend as soon as it
+               becomes idle at run time; they want the device to remain
+               inactive for a certain minimum period of time first.  That
+               period is called the autosuspend delay.  Negative values will
+               prevent the device from being suspended at run time (similar
+               to writing "on" to the power/control attribute).  Values >=
+               1000 will cause the autosuspend timer expiration to be rounded
+               up to the nearest second.
+
+               Not all drivers support this attribute.  If it isn't supported,
+               attempts to read or write it will yield I/O errors.
index 2875f1f74a0792c48402cdc8f33e3e545e0df5ad..194ca446ac287692333040ca76235503af8738a9 100644 (file)
@@ -99,9 +99,38 @@ Description:
 
                dmesg -s 1000000 | grep 'hash matches'
 
+               If you do not get any matches (or they appear to be false
+               positives), it is possible that the last PM event point
+               referred to a device created by a loadable kernel module.  In
+               this case cat /sys/power/pm_trace_dev_match (see below) after
+               your system is started up and the kernel modules are loaded.
+
                CAUTION: Using it will cause your machine's real-time (CMOS)
                clock to be set to a random invalid time after a resume.
 
+What;          /sys/power/pm_trace_dev_match
+Date:          October 2010
+Contact:       James Hogan <james@albanarts.com>
+Description:
+               The /sys/power/pm_trace_dev_match file contains the name of the
+               device associated with the last PM event point saved in the RTC
+               across reboots when pm_trace has been used.  More precisely it
+               contains the list of current devices (including those
+               registered by loadable kernel modules since boot) which match
+               the device hash in the RTC at boot, with a newline after each
+               one.
+
+               The advantage of this file over the hash matches printed to the
+               kernel log (see /sys/power/pm_trace), is that it includes
+               devices created after boot by loadable kernel modules.
+
+               Due to the small hash size necessary to fit in the RTC, it is
+               possible that more than one device matches the hash, in which
+               case further investigation is required to determine which
+               device is causing the problem.  Note that genuine RTC clock
+               values (such as when pm_trace has not been used), can still
+               match a device and output it's name here.
+
 What:          /sys/power/pm_async
 Date:          January 2009
 Contact:       Rafael J. Wysocki <rjw@sisk.pl>
index 1448b33fd22272e457e150234a877a54e5082571..fb10fd08c05cd00a49a4276f06842299e092b4a7 100644 (file)
@@ -28,7 +28,7 @@
   </authorgroup>
 
   <copyright>
-   <year>2005-2006</year>
+   <year>2005-2010</year>
    <holder>Thomas Gleixner</holder>
   </copyright>
   <copyright>
          <listitem><para>Edge type</para></listitem>
          <listitem><para>Simple type</para></listitem>
        </itemizedlist>
+       During the implementation we identified another type:
+       <itemizedlist>
+         <listitem><para>Fast EOI type</para></listitem>
+       </itemizedlist>
        In the SMP world of the __do_IRQ() super-handler another type
        was identified:
        <itemizedlist>
        is still available. This leads to a kind of duality for the time
        being. Over time the new model should be used in more and more
        architectures, as it enables smaller and cleaner IRQ subsystems.
+       It's deprecated for three years now and about to be removed.
        </para>
   </chapter>
   <chapter id="bugs">
          <itemizedlist>
          <listitem><para>handle_level_irq</para></listitem>
          <listitem><para>handle_edge_irq</para></listitem>
+         <listitem><para>handle_fasteoi_irq</para></listitem>
          <listitem><para>handle_simple_irq</para></listitem>
          <listitem><para>handle_percpu_irq</para></listitem>
          </itemizedlist>
                are used by the default flow implementations.
                The following helper functions are implemented (simplified excerpt):
                <programlisting>
-default_enable(irq)
+default_enable(struct irq_data *data)
 {
-       desc->chip->unmask(irq);
+       desc->chip->irq_unmask(data);
 }
 
-default_disable(irq)
+default_disable(struct irq_data *data)
 {
-       if (!delay_disable(irq))
-               desc->chip->mask(irq);
+       if (!delay_disable(data))
+               desc->chip->irq_mask(data);
 }
 
-default_ack(irq)
+default_ack(struct irq_data *data)
 {
-       chip->ack(irq);
+       chip->irq_ack(data);
 }
 
-default_mask_ack(irq)
+default_mask_ack(struct irq_data *data)
 {
-       if (chip->mask_ack) {
-               chip->mask_ack(irq);
+       if (chip->irq_mask_ack) {
+               chip->irq_mask_ack(data);
        } else {
-               chip->mask(irq);
-               chip->ack(irq);
+               chip->irq_mask(data);
+               chip->irq_ack(data);
        }
 }
 
-noop(irq)
+noop(struct irq_data *data))
 {
 }
 
@@ -278,12 +284,27 @@ noop(irq)
                <para>
                The following control flow is implemented (simplified excerpt):
                <programlisting>
-desc->chip->start();
+desc->chip->irq_mask();
 handle_IRQ_event(desc->action);
-desc->chip->end();
+desc->chip->irq_unmask();
                </programlisting>
                </para>
-           </sect3>
+           </sect3>
+           <sect3 id="Default_FASTEOI_IRQ_flow_handler">
+               <title>Default Fast EOI IRQ flow handler</title>
+               <para>
+               handle_fasteoi_irq provides a generic implementation
+               for interrupts, which only need an EOI at the end of
+               the handler
+               </para>
+               <para>
+               The following control flow is implemented (simplified excerpt):
+               <programlisting>
+handle_IRQ_event(desc->action);
+desc->chip->irq_eoi();
+               </programlisting>
+               </para>
+           </sect3>
            <sect3 id="Default_Edge_IRQ_flow_handler">
                <title>Default Edge IRQ flow handler</title>
                <para>
@@ -294,20 +315,19 @@ desc->chip->end();
                The following control flow is implemented (simplified excerpt):
                <programlisting>
 if (desc->status &amp; running) {
-       desc->chip->hold();
+       desc->chip->irq_mask();
        desc->status |= pending | masked;
        return;
 }
-desc->chip->start();
+desc->chip->irq_ack();
 desc->status |= running;
 do {
        if (desc->status &amp; masked)
-               desc->chip->enable();
+               desc->chip->irq_unmask();
        desc->status &amp;= ~pending;
        handle_IRQ_event(desc->action);
 } while (status &amp; pending);
 desc->status &amp;= ~running;
-desc->chip->end();
                </programlisting>
                </para>
            </sect3>
@@ -342,9 +362,9 @@ handle_IRQ_event(desc->action);
                <para>
                The following control flow is implemented (simplified excerpt):
                <programlisting>
-desc->chip->start();
 handle_IRQ_event(desc->action);
-desc->chip->end();
+if (desc->chip->irq_eoi)
+        desc->chip->irq_eoi();
                </programlisting>
                </para>
            </sect3>
@@ -375,8 +395,7 @@ desc->chip->end();
        mechanism. (It's necessary to enable CONFIG_HARDIRQS_SW_RESEND when
        you want to use the delayed interrupt disable feature and your
        hardware is not capable of retriggering an interrupt.)
-       The delayed interrupt disable can be runtime enabled, per interrupt,
-       by setting the IRQ_DELAYED_DISABLE flag in the irq_desc status field.
+       The delayed interrupt disable is not configurable.
        </para>
        </sect2>
     </sect1>
@@ -387,13 +406,13 @@ desc->chip->end();
        contains all the direct chip relevant functions, which
        can be utilized by the irq flow implementations.
          <itemizedlist>
-         <listitem><para>ack()</para></listitem>
-         <listitem><para>mask_ack() - Optional, recommended for performance</para></listitem>
-         <listitem><para>mask()</para></listitem>
-         <listitem><para>unmask()</para></listitem>
-         <listitem><para>retrigger() - Optional</para></listitem>
-         <listitem><para>set_type() - Optional</para></listitem>
-         <listitem><para>set_wake() - Optional</para></listitem>
+         <listitem><para>irq_ack()</para></listitem>
+         <listitem><para>irq_mask_ack() - Optional, recommended for performance</para></listitem>
+         <listitem><para>irq_mask()</para></listitem>
+         <listitem><para>irq_unmask()</para></listitem>
+         <listitem><para>irq_retrigger() - Optional</para></listitem>
+         <listitem><para>irq_set_type() - Optional</para></listitem>
+         <listitem><para>irq_set_wake() - Optional</para></listitem>
          </itemizedlist>
        These primitives are strictly intended to mean what they say: ack means
        ACK, masking means masking of an IRQ line, etc. It is up to the flow
@@ -458,6 +477,7 @@ desc->chip->end();
      <para>
      This chapter contains the autogenerated documentation of the internal functions.
      </para>
+!Ikernel/irq/irqdesc.c
 !Ikernel/irq/handle.c
 !Ikernel/irq/chip.c
   </chapter>
index a0d479d1e1dd872bd1ae7b4d17d4582df03a384c..f66f4df186908f5d6ba79171e303949683107a1e 100644 (file)
@@ -1645,7 +1645,9 @@ the amount of locking which needs to be done.
       all the readers who were traversing the list when we deleted the
       element are finished.  We use <function>call_rcu()</function> to
       register a callback which will actually destroy the object once
-      the readers are finished.
+      all pre-existing readers are finished.  Alternatively,
+      <function>synchronize_rcu()</function> may be used to block until
+      all pre-existing are finished.
     </para>
     <para>
       But how does Read Copy Update know when the readers are
@@ -1714,7 +1716,7 @@ the amount of locking which needs to be done.
 -        object_put(obj);
 +        list_del_rcu(&amp;obj-&gt;list);
          cache_num--;
-+        call_rcu(&amp;obj-&gt;rcu, cache_delete_rcu, obj);
++        call_rcu(&amp;obj-&gt;rcu, cache_delete_rcu);
  }
 
  /* Must be holding cache_lock */
@@ -1725,14 +1727,6 @@ the amount of locking which needs to be done.
          if (++cache_num > MAX_CACHE_SIZE) {
                  struct object *i, *outcast = NULL;
                  list_for_each_entry(i, &amp;cache, list) {
-@@ -85,6 +94,7 @@
-         obj-&gt;popularity = 0;
-         atomic_set(&amp;obj-&gt;refcnt, 1); /* The cache holds a reference */
-         spin_lock_init(&amp;obj-&gt;lock);
-+        INIT_RCU_HEAD(&amp;obj-&gt;rcu);
-
-         spin_lock_irqsave(&amp;cache_lock, flags);
-         __cache_add(obj);
 @@ -104,12 +114,11 @@
  struct object *cache_find(int id)
  {
index 790d1a8123760211bdcb6427b75c1b4abf2b7210..0c134f8afc6f60b1316b9551577179f1b6dc3961 100644 (file)
@@ -218,13 +218,22 @@ over a rather long period of time, but improvements are always welcome!
        include:
 
        a.      Keeping a count of the number of data-structure elements
-               used by the RCU-protected data structure, including those
-               waiting for a grace period to elapse.  Enforce a limit
-               on this number, stalling updates as needed to allow
-               previously deferred frees to complete.
-
-               Alternatively, limit only the number awaiting deferred
-               free rather than the total number of elements.
+               used by the RCU-protected data structure, including
+               those waiting for a grace period to elapse.  Enforce a
+               limit on this number, stalling updates as needed to allow
+               previously deferred frees to complete.  Alternatively,
+               limit only the number awaiting deferred free rather than
+               the total number of elements.
+
+               One way to stall the updates is to acquire the update-side
+               mutex.  (Don't try this with a spinlock -- other CPUs
+               spinning on the lock could prevent the grace period
+               from ever ending.)  Another way to stall the updates
+               is for the updates to use a wrapper function around
+               the memory allocator, so that this wrapper function
+               simulates OOM when there is too much memory awaiting an
+               RCU grace period.  There are of course many other
+               variations on this theme.
 
        b.      Limiting update rate.  For example, if updates occur only
                once per hour, then no explicit rate limiting is required,
@@ -365,3 +374,26 @@ over a rather long period of time, but improvements are always welcome!
        and the compiler to freely reorder code into and out of RCU
        read-side critical sections.  It is the responsibility of the
        RCU update-side primitives to deal with this.
+
+17.    Use CONFIG_PROVE_RCU, CONFIG_DEBUG_OBJECTS_RCU_HEAD, and
+       the __rcu sparse checks to validate your RCU code.  These
+       can help find problems as follows:
+
+       CONFIG_PROVE_RCU: check that accesses to RCU-protected data
+               structures are carried out under the proper RCU
+               read-side critical section, while holding the right
+               combination of locks, or whatever other conditions
+               are appropriate.
+
+       CONFIG_DEBUG_OBJECTS_RCU_HEAD: check that you don't pass the
+               same object to call_rcu() (or friends) before an RCU
+               grace period has elapsed since the last time that you
+               passed that same object to call_rcu() (or friends).
+
+       __rcu sparse checks: tag the pointer to the RCU-protected data
+               structure with __rcu, and sparse will warn you if you
+               access that pointer without the services of one of the
+               variants of rcu_dereference().
+
+       These debugging aids can help you find problems that are
+       otherwise extremely difficult to spot.
index 44c6dcc93d6dad8e9cee2cadb9f49fa992c5eb00..862c08ef1fde4436ddac8010ba4a1aae40328719 100644 (file)
@@ -80,6 +80,24 @@ o    A CPU looping with bottom halves disabled.  This condition can
 o      For !CONFIG_PREEMPT kernels, a CPU looping anywhere in the kernel
        without invoking schedule().
 
+o      A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might
+       happen to preempt a low-priority task in the middle of an RCU
+       read-side critical section.   This is especially damaging if
+       that low-priority task is not permitted to run on any other CPU,
+       in which case the next RCU grace period can never complete, which
+       will eventually cause the system to run out of memory and hang.
+       While the system is in the process of running itself out of
+       memory, you might see stall-warning messages.
+
+o      A CPU-bound real-time task in a CONFIG_PREEMPT_RT kernel that
+       is running at a higher priority than the RCU softirq threads.
+       This will prevent RCU callbacks from ever being invoked,
+       and in a CONFIG_TREE_PREEMPT_RCU kernel will further prevent
+       RCU grace periods from ever completing.  Either way, the
+       system will eventually run out of memory and hang.  In the
+       CONFIG_TREE_PREEMPT_RCU case, you might see stall-warning
+       messages.
+
 o      A bug in the RCU implementation.
 
 o      A hardware failure.  This is quite unlikely, but has occurred
index efd8cc95c06b1470db165a74a0d99fd33ee17dea..a851118775d84c7a1d2356ba6a6c8e6208292887 100644 (file)
@@ -125,6 +125,17 @@ o  "b" is the batch limit for this CPU.  If more than this number
        of RCU callbacks is ready to invoke, then the remainder will
        be deferred.
 
+o      "ci" is the number of RCU callbacks that have been invoked for
+       this CPU.  Note that ci+ql is the number of callbacks that have
+       been registered in absence of CPU-hotplug activity.
+
+o      "co" is the number of RCU callbacks that have been orphaned due to
+       this CPU going offline.
+
+o      "ca" is the number of RCU callbacks that have been adopted due to
+       other CPUs going offline.  Note that ci+co-ca+ql is the number of
+       RCU callbacks registered on this CPU.
+
 There is also an rcu/rcudata.csv file with the same information in
 comma-separated-variable spreadsheet format.
 
@@ -180,7 +191,7 @@ o   "s" is the "signaled" state that drives force_quiescent_state()'s
 
 o      "jfq" is the number of jiffies remaining for this grace period
        before force_quiescent_state() is invoked to help push things
-       along.  Note that CPUs in dyntick-idle mode thoughout the grace
+       along.  Note that CPUs in dyntick-idle mode throughout the grace
        period will not report on their own, but rather must be check by
        some other CPU via force_quiescent_state().
 
index 7f5fc3ba9c912daf7824d96621b52121e6cae873..ecf7d04bca2601d79e8239b08a777c207198b451 100644 (file)
@@ -6,6 +6,8 @@ Interrupts
        - ARM Interrupt subsystem documentation
 IXP2000
        - Release Notes for Linux on Intel's IXP2000 Network Processor
+msm
+       - MSM specific documentation
 Netwinder
        - Netwinder specific documentation
 Porting
diff --git a/Documentation/arm/msm/gpiomux.txt b/Documentation/arm/msm/gpiomux.txt
new file mode 100644 (file)
index 0000000..67a8162
--- /dev/null
@@ -0,0 +1,176 @@
+This document provides an overview of the msm_gpiomux interface, which
+is used to provide gpio pin multiplexing and configuration on mach-msm
+targets.
+
+History
+=======
+
+The first-generation API for gpio configuration & multiplexing on msm
+is the function gpio_tlmm_config().  This function has a few notable
+shortcomings, which led to its deprecation and replacement by gpiomux:
+
+The 'disable' parameter:  Setting the second parameter to
+gpio_tlmm_config to GPIO_CFG_DISABLE tells the peripheral
+processor in charge of the subsystem to perform a look-up into a
+low-power table and apply the low-power/sleep setting for the pin.
+As the msm family evolved this became problematic. Not all pins
+have sleep settings, not all peripheral processors will accept requests
+to apply said sleep settings, and not all msm targets have their gpio
+subsystems managed by a peripheral processor. In order to get consistent
+behavior on all targets, drivers are forced to ignore this parameter,
+rendering it useless.
+
+The 'direction' flag: for all mux-settings other than raw-gpio (0),
+the output-enable bit of a gpio is hard-wired to a known
+input (usually VDD or ground).  For those settings, the direction flag
+is meaningless at best, and deceptive at worst.  In addition, using the
+direction flag to change output-enable (OE) directly can cause trouble in
+gpiolib, which has no visibility into gpio direction changes made
+in this way.  Direction control in gpio mode should be made through gpiolib.
+
+Key Features of gpiomux
+=======================
+
+- A consistent interface across all generations of msm.  Drivers can expect
+the same results on every target.
+- gpiomux plays nicely with gpiolib.  Functions that should belong to gpiolib
+are left to gpiolib and not duplicated here.  gpiomux is written with the
+intent that gpio_chips will call gpiomux reference-counting methods
+from their request() and free() hooks, providing full integration.
+- Tabular configuration.  Instead of having to call gpio_tlmm_config
+hundreds of times, gpio configuration is placed in a single table.
+- Per-gpio sleep.  Each gpio is individually reference counted, allowing only
+those lines which are in use to be put in high-power states.
+- 0 means 'do nothing': all flags are designed so that the default memset-zero
+equates to a sensible default of 'no configuration', preventing users
+from having to provide hundreds of 'no-op' configs for unused or
+unwanted lines.
+
+Usage
+=====
+
+To use gpiomux, provide configuration information for relevant gpio lines
+in the msm_gpiomux_configs table.  Since a 0 equates to "unconfigured",
+only those lines to be managed by gpiomux need to be specified.  Here
+is a completely fictional example:
+
+struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
+       [12] = {
+               .active = GPIOMUX_VALID | GPIOMUX_DRV_8MA | GPIOMUX_FUNC_1,
+               .suspended = GPIOMUX_VALID | GPIOMUX_PULL_DOWN,
+       },
+       [34] = {
+               .suspended = GPIOMUX_VALID | GPIOMUX_PULL_DOWN,
+       },
+};
+
+To indicate that a gpio is in use, call msm_gpiomux_get() to increase
+its reference count.  To decrease the reference count, call msm_gpiomux_put().
+
+The effect of this configuration is as follows:
+
+When the system boots, gpios 12 and 34 will be initialized with their
+'suspended' configurations.  All other gpios, which were left unconfigured,
+will not be touched.
+
+When msm_gpiomux_get() is called on gpio 12 to raise its reference count
+above 0, its active configuration will be applied.  Since no other gpio
+line has a valid active configuration, msm_gpiomux_get() will have no
+effect on any other line.
+
+When msm_gpiomux_put() is called on gpio 12 or 34 to drop their reference
+count to 0, their suspended configurations will be applied.
+Since no other gpio line has a valid suspended configuration, no other
+gpio line will be effected by msm_gpiomux_put().  Since gpio 34 has no valid
+active configuration, this is effectively a no-op for gpio 34 as well,
+with one small caveat, see the section "About Output-Enable Settings".
+
+All of the GPIOMUX_VALID flags may seem like unnecessary overhead, but
+they address some important issues.  As unused entries (all those
+except 12 and 34) are zero-filled, gpiomux needs a way to distinguish
+the used fields from the unused.  In addition, the all-zero pattern
+is a valid configuration!  Therefore, gpiomux defines an additional bit
+which is used to indicate when a field is used.  This has the pleasant
+side-effect of allowing calls to msm_gpiomux_write to use '0' to indicate
+that a value should not be changed:
+
+  msm_gpiomux_write(0, GPIOMUX_VALID, 0);
+
+replaces the active configuration of gpio 0 with an all-zero configuration,
+but leaves the suspended configuration as it was.
+
+Static Configurations
+=====================
+
+To install a static configuration, which is applied at boot and does
+not change after that, install a configuration with a suspended component
+but no active component, as in the previous example:
+
+       [34] = {
+               .suspended = GPIOMUX_VALID | GPIOMUX_PULL_DOWN,
+       },
+
+The suspended setting is applied during boot, and the lack of any valid
+active setting prevents any other setting from being applied at runtime.
+If other subsystems attempting to access the line is a concern, one could
+*really* anchor the configuration down by calling msm_gpiomux_get on the
+line at initialization to move the line into active mode.  With the line
+held, it will never be re-suspended, and with no valid active configuration,
+no new configurations will be applied.
+
+But then, if having other subsystems grabbing for the line is truly a concern,
+it should be reserved with gpio_request instead, which carries an implicit
+msm_gpiomux_get.
+
+gpiomux and gpiolib
+===================
+
+It is expected that msm gpio_chips will call msm_gpiomux_get() and
+msm_gpiomux_put() from their request and free hooks, like this fictional
+example:
+
+static int request(struct gpio_chip *chip, unsigned offset)
+{
+        return msm_gpiomux_get(chip->base + offset);
+}
+
+static void free(struct gpio_chip *chip, unsigned offset)
+{
+        msm_gpiomux_put(chip->base + offset);
+}
+
+       ...somewhere in a gpio_chip declaration...
+       .request = request,
+       .free    = free,
+
+This provides important functionality:
+- It guarantees that a gpio line will have its 'active' config applied
+  when the line is requested, and will not be suspended while the line
+  remains requested; and
+- It guarantees that gpio-direction settings from gpiolib behave sensibly.
+  See "About Output-Enable Settings."
+
+This mechanism allows for "auto-request" of gpiomux lines via gpiolib
+when it is suitable.  Drivers wishing more exact control are, of course,
+free to also use msm_gpiomux_set and msm_gpiomux_get.
+
+About Output-Enable Settings
+============================
+
+Some msm targets do not have the ability to query the current gpio
+configuration setting.  This means that changes made to the output-enable
+(OE) bit by gpiolib cannot be consistently detected and preserved by gpiomux.
+Therefore, when gpiomux applies a configuration setting, any direction
+settings which may have been applied by gpiolib are lost and the default
+input settings are re-applied.
+
+For this reason, drivers should not assume that gpio direction settings
+continue to hold if they free and then re-request a gpio.  This seems like
+common sense - after all, anybody could have obtained the line in the
+meantime - but it needs saying.
+
+This also means that calls to msm_gpiomux_write will reset the OE bit,
+which means that if the gpio line is held by a client of gpiolib and
+msm_gpiomux_write is called, the direction setting has been lost and
+gpiolib's internal state has been broken.
+Release gpio lines before reconfiguring them.
index f1c5c4bccd3e8ed6674903eedbc59db3cf76ff9e..902d3151f527919ab190d8f30ff9253e3da2c8d0 100644 (file)
@@ -14,25 +14,39 @@ to /proc/cpuinfo.
        identifier (rather than the kernel's).  The actual value is
        architecture and platform dependent.
 
-3) /sys/devices/system/cpu/cpuX/topology/thread_siblings:
+3) /sys/devices/system/cpu/cpuX/topology/book_id:
+
+       the book ID of cpuX. Typically it is the hardware platform's
+       identifier (rather than the kernel's).  The actual value is
+       architecture and platform dependent.
+
+4) /sys/devices/system/cpu/cpuX/topology/thread_siblings:
 
        internel kernel map of cpuX's hardware threads within the same
        core as cpuX
 
-4) /sys/devices/system/cpu/cpuX/topology/core_siblings:
+5) /sys/devices/system/cpu/cpuX/topology/core_siblings:
 
        internal kernel map of cpuX's hardware threads within the same
        physical_package_id.
 
+6) /sys/devices/system/cpu/cpuX/topology/book_siblings:
+
+       internal kernel map of cpuX's hardware threads within the same
+       book_id.
+
 To implement it in an architecture-neutral way, a new source file,
-drivers/base/topology.c, is to export the 4 attributes.
+drivers/base/topology.c, is to export the 4 or 6 attributes. The two book
+related sysfs files will only be created if CONFIG_SCHED_BOOK is selected.
 
 For an architecture to support this feature, it must define some of
 these macros in include/asm-XXX/topology.h:
 #define topology_physical_package_id(cpu)
 #define topology_core_id(cpu)
+#define topology_book_id(cpu)
 #define topology_thread_cpumask(cpu)
 #define topology_core_cpumask(cpu)
+#define topology_book_cpumask(cpu)
 
 The type of **_id is int.
 The type of siblings is (const) struct cpumask *.
@@ -45,6 +59,9 @@ not defined by include/asm-XXX/topology.h:
 3) thread_siblings: just the given CPU
 4) core_siblings: just the given CPU
 
+For architectures that don't support books (CONFIG_SCHED_BOOK) there are no
+default definitions for topology_book_id() and topology_book_cpumask().
+
 Additionally, CPU topology information is provided under
 /sys/devices/system/cpu and includes these files.  The internal
 source for the output is in brackets ("[]").
index 842aa9de84a603298f74f9f4b8c036e0104001cf..5e2bc4ab897a1df72aa03849809747afa68ec142 100644 (file)
@@ -386,34 +386,6 @@ Who:       Tejun Heo <tj@kernel.org>
 
 ----------------------------
 
-What:  Support for VMware's guest paravirtuliazation technique [VMI] will be
-       dropped.
-When:  2.6.37 or earlier.
-Why:   With the recent innovations in CPU hardware acceleration technologies
-       from Intel and AMD, VMware ran a few experiments to compare these
-       techniques to guest paravirtualization technique on VMware's platform.
-       These hardware assisted virtualization techniques have outperformed the
-       performance benefits provided by VMI in most of the workloads. VMware
-       expects that these hardware features will be ubiquitous in a couple of
-       years, as a result, VMware has started a phased retirement of this
-       feature from the hypervisor. We will be removing this feature from the
-       Kernel too. Right now we are targeting 2.6.37 but can retire earlier if
-       technical reasons (read opportunity to remove major chunk of pvops)
-       arise.
-
-       Please note that VMI has always been an optimization and non-VMI kernels
-       still work fine on VMware's platform.
-       Latest versions of VMware's product which support VMI are,
-       Workstation 7.0 and VSphere 4.0 on ESX side, future maintainence
-       releases for these products will continue supporting VMI.
-
-       For more details about VMI retirement take a look at this,
-       http://blogs.vmware.com/guestosguide/2009/09/vmi-retirement.html
-
-Who:   Alok N Kataria <akataria@vmware.com>
-
-----------------------------
-
 What:  Support for lcd_switch and display_get in asus-laptop driver
 When:  March 2010
 Why:   These two features use non-standard interfaces. There are the
index 1f7ae144f6d89bc351c8aa34076262bf366f4a4d..5393e6611691617db6c933a945df25baa0bd1090 100644 (file)
@@ -87,3 +87,10 @@ dir_resv_level=      (*)     By default, directory reservations will scale with file
                        reservations - users should rarely need to change this
                        value. If allocation reservations are turned off, this
                        option will have no effect.
+coherency=full  (*)    Disallow concurrent O_DIRECT writes, cluster inode
+                       lock will be taken to force other nodes drop cache,
+                       therefore full cluster coherency is guaranteed even
+                       for O_DIRECT writes.
+coherency=buffered     Allow concurrent O_DIRECT writes without EX lock among
+                       nodes, which gains high performance at risk of getting
+                       stale data on other nodes.
index 8dd7248508a9e12ac8908c24fb4a3649f157697a..02f21d9220ce8e5749ce7eb811039d4d396aaf80 100644 (file)
@@ -455,7 +455,7 @@ and is between 256 and 4096 characters. It is defined in the file
                        [ARM] imx_timer1,OSTS,netx_timer,mpu_timer2,
                                pxa_timer,timer3,32k_counter,timer0_1
                        [AVR32] avr32
-                       [X86-32] pit,hpet,tsc,vmi-timer;
+                       [X86-32] pit,hpet,tsc;
                                scx200_hrt on Geode; cyclone on IBM x440
                        [MIPS] MIPS
                        [PARISC] cr16
@@ -2153,6 +2153,11 @@ and is between 256 and 4096 characters. It is defined in the file
                        Reserves a hole at the top of the kernel virtual
                        address space.
 
+       reservelow=     [X86]
+                       Format: nn[K]
+                       Set the amount of memory to reserve for BIOS at
+                       the bottom of the address space.
+
        reset_devices   [KNL] Force drivers to reset the underlying device
                        during initialization.
 
@@ -2165,6 +2170,11 @@ and is between 256 and 4096 characters. It is defined in the file
                        in <PAGE_SIZE> units (needed only for swap files).
                        See  Documentation/power/swsusp-and-swap-files.txt
 
+       hibernate=      [HIBERNATION]
+               noresume        Don't check if there's a hibernation image
+                               present during boot.
+               nocompress      Don't compress/decompress hibernation images.
+
        retain_initrd   [RAM] Keep initrd memory after extraction
 
        rhash_entries=  [KNL,NET]
@@ -2435,6 +2445,10 @@ and is between 256 and 4096 characters. It is defined in the file
                        disables clocksource verification at runtime.
                        Used to enable high-resolution timer mode on older
                        hardware, and in virtualized environment.
+                       [x86] noirqtime: Do not use TSC to do irq accounting.
+                       Used to run time disable IRQ_TIME_ACCOUNTING on any
+                       platforms where RDTSC is slow and this accounting
+                       can add overhead.
 
        turbografx.map[2|3]=    [HW,JOY]
                        TurboGraFX parallel port interface
index 1762b81fcdf2ec4a235423687865453a16196aed..741fe66d6eca4852894cac79d6ad2d3162486c7a 100644 (file)
@@ -542,9 +542,11 @@ Kprobes does not use mutexes or allocate memory except during
 registration and unregistration.
 
 Probe handlers are run with preemption disabled.  Depending on the
-architecture, handlers may also run with interrupts disabled.  In any
-case, your handler should not yield the CPU (e.g., by attempting to
-acquire a semaphore).
+architecture and optimization state, handlers may also run with
+interrupts disabled (e.g., kretprobe handlers and optimized kprobe
+handlers run without interrupt disabled on x86/x86-64).  In any case,
+your handler should not yield the CPU (e.g., by attempting to acquire
+a semaphore).
 
 Since a return probe is implemented by replacing the return
 address with the trampoline's address, stack backtraces and calls
index 26c0f9c00545300aeef860eba18422ba79bd2e75..dd04361dd361afe814b98eb46942924bda757f17 100644 (file)
@@ -1,4 +1,29 @@
 This file details changes in 2.6 which affect PCMCIA card driver authors:
+* pcmcia_loop_config() and autoconfiguration (as of 2.6.36)
+   If struct pcmcia_device *p_dev->config_flags is set accordingly,
+   pcmcia_loop_config() now sets up certain configuration values
+   automatically, though the driver may still override the settings
+   in the callback function. The following autoconfiguration options
+   are provided at the moment:
+       CONF_AUTO_CHECK_VCC : check for matching Vcc
+       CONF_AUTO_SET_VPP   : set Vpp
+       CONF_AUTO_AUDIO     : auto-enable audio line, if required
+       CONF_AUTO_SET_IO    : set ioport resources (->resource[0,1])
+       CONF_AUTO_SET_IOMEM : set first iomem resource (->resource[2])
+
+* pcmcia_request_configuration -> pcmcia_enable_device (as of 2.6.36)
+   pcmcia_request_configuration() got renamed to pcmcia_enable_device(),
+   as it mirrors pcmcia_disable_device(). Configuration settings are now
+   stored in struct pcmcia_device, e.g. in the fields config_flags,
+   config_index, config_base, vpp.
+
+* pcmcia_request_window changes (as of 2.6.36)
+   Instead of win_req_t, drivers are now requested to fill out
+   struct pcmcia_device *p_dev->resource[2,3,4,5] for up to four ioport
+   ranges. After a call to pcmcia_request_window(), the regions found there
+   are reserved and may be used immediately -- until pcmcia_release_window()
+   is called.
+
 * pcmcia_request_io changes (as of 2.6.36)
    Instead of io_req_t, drivers are now requested to fill out
    struct pcmcia_device *p_dev->resource[0,1] for up to two ioport
index fb742c213c9eb37b9e8216c96f029bebed6a86e9..45e9d4a91284678e9a9acf55ab5a23b07d17ce33 100644 (file)
@@ -14,6 +14,8 @@ interface.txt
        - Power management user interface in /sys/power
 notifiers.txt
        - Registering suspend notifiers in device drivers
+opp.txt
+       - Operating Performance Point library
 pci.txt
        - How the PCI Subsystem Does Power Management
 pm_qos_interface.txt
index e67211fe0ee2f432044efe62e8909702f0b46fc9..c537834af00566e0fee8058a9643803d2c2b3954 100644 (file)
@@ -57,7 +57,7 @@ smallest image possible.  In particular, if "0" is written to this file, the
 suspend image will be as small as possible.
 
 Reading from this file will display the current image size limit, which
-is set to 500 MB by default.
+is set to 2/5 of available RAM by default.
 
 /sys/power/pm_trace controls the code which saves the last PM event point in
 the RTC across reboots, so that you can debug a machine that just hangs
diff --git a/Documentation/power/opp.txt b/Documentation/power/opp.txt
new file mode 100644 (file)
index 0000000..44d87ad
--- /dev/null
@@ -0,0 +1,375 @@
+*=============*
+* OPP Library *
+*=============*
+
+(C) 2009-2010 Nishanth Menon <nm@ti.com>, Texas Instruments Incorporated
+
+Contents
+--------
+1. Introduction
+2. Initial OPP List Registration
+3. OPP Search Functions
+4. OPP Availability Control Functions
+5. OPP Data Retrieval Functions
+6. Cpufreq Table Generation
+7. Data Structures
+
+1. Introduction
+===============
+Complex SoCs of today consists of a multiple sub-modules working in conjunction.
+In an operational system executing varied use cases, not all modules in the SoC
+need to function at their highest performing frequency all the time. To
+facilitate this, sub-modules in a SoC are grouped into domains, allowing some
+domains to run at lower voltage and frequency while other domains are loaded
+more. The set of discrete tuples consisting of frequency and voltage pairs that
+the device will support per domain are called Operating Performance Points or
+OPPs.
+
+OPP library provides a set of helper functions to organize and query the OPP
+information. The library is located in drivers/base/power/opp.c and the header
+is located in include/linux/opp.h. OPP library can be enabled by enabling
+CONFIG_PM_OPP from power management menuconfig menu. OPP library depends on
+CONFIG_PM as certain SoCs such as Texas Instrument's OMAP framework allows to
+optionally boot at a certain OPP without needing cpufreq.
+
+Typical usage of the OPP library is as follows:
+(users)                -> registers a set of default OPPs              -> (library)
+SoC framework  -> modifies on required cases certain OPPs      -> OPP layer
+               -> queries to search/retrieve information       ->
+
+OPP layer expects each domain to be represented by a unique device pointer. SoC
+framework registers a set of initial OPPs per device with the OPP layer. This
+list is expected to be an optimally small number typically around 5 per device.
+This initial list contains a set of OPPs that the framework expects to be safely
+enabled by default in the system.
+
+Note on OPP Availability:
+------------------------
+As the system proceeds to operate, SoC framework may choose to make certain
+OPPs available or not available on each device based on various external
+factors. Example usage: Thermal management or other exceptional situations where
+SoC framework might choose to disable a higher frequency OPP to safely continue
+operations until that OPP could be re-enabled if possible.
+
+OPP library facilitates this concept in it's implementation. The following
+operational functions operate only on available opps:
+opp_find_freq_{ceil, floor}, opp_get_voltage, opp_get_freq, opp_get_opp_count
+and opp_init_cpufreq_table
+
+opp_find_freq_exact is meant to be used to find the opp pointer which can then
+be used for opp_enable/disable functions to make an opp available as required.
+
+WARNING: Users of OPP library should refresh their availability count using
+get_opp_count if opp_enable/disable functions are invoked for a device, the
+exact mechanism to trigger these or the notification mechanism to other
+dependent subsystems such as cpufreq are left to the discretion of the SoC
+specific framework which uses the OPP library. Similar care needs to be taken
+care to refresh the cpufreq table in cases of these operations.
+
+WARNING on OPP List locking mechanism:
+-------------------------------------------------
+OPP library uses RCU for exclusivity. RCU allows the query functions to operate
+in multiple contexts and this synchronization mechanism is optimal for a read
+intensive operations on data structure as the OPP library caters to.
+
+To ensure that the data retrieved are sane, the users such as SoC framework
+should ensure that the section of code operating on OPP queries are locked
+using RCU read locks. The opp_find_freq_{exact,ceil,floor},
+opp_get_{voltage, freq, opp_count} fall into this category.
+
+opp_{add,enable,disable} are updaters which use mutex and implement it's own
+RCU locking mechanisms. opp_init_cpufreq_table acts as an updater and uses
+mutex to implment RCU updater strategy. These functions should *NOT* be called
+under RCU locks and other contexts that prevent blocking functions in RCU or
+mutex operations from working.
+
+2. Initial OPP List Registration
+================================
+The SoC implementation calls opp_add function iteratively to add OPPs per
+device. It is expected that the SoC framework will register the OPP entries
+optimally- typical numbers range to be less than 5. The list generated by
+registering the OPPs is maintained by OPP library throughout the device
+operation. The SoC framework can subsequently control the availability of the
+OPPs dynamically using the opp_enable / disable functions.
+
+opp_add - Add a new OPP for a specific domain represented by the device pointer.
+       The OPP is defined using the frequency and voltage. Once added, the OPP
+       is assumed to be available and control of it's availability can be done
+       with the opp_enable/disable functions. OPP library internally stores
+       and manages this information in the opp struct. This function may be
+       used by SoC framework to define a optimal list as per the demands of
+       SoC usage environment.
+
+       WARNING: Do not use this function in interrupt context.
+
+       Example:
+        soc_pm_init()
+        {
+               /* Do things */
+               r = opp_add(mpu_dev, 1000000, 900000);
+               if (!r) {
+                       pr_err("%s: unable to register mpu opp(%d)\n", r);
+                       goto no_cpufreq;
+               }
+               /* Do cpufreq things */
+        no_cpufreq:
+               /* Do remaining things */
+        }
+
+3. OPP Search Functions
+=======================
+High level framework such as cpufreq operates on frequencies. To map the
+frequency back to the corresponding OPP, OPP library provides handy functions
+to search the OPP list that OPP library internally manages. These search
+functions return the matching pointer representing the opp if a match is
+found, else returns error. These errors are expected to be handled by standard
+error checks such as IS_ERR() and appropriate actions taken by the caller.
+
+opp_find_freq_exact - Search for an OPP based on an *exact* frequency and
+       availability. This function is especially useful to enable an OPP which
+       is not available by default.
+       Example: In a case when SoC framework detects a situation where a
+       higher frequency could be made available, it can use this function to
+       find the OPP prior to call the opp_enable to actually make it available.
+        rcu_read_lock();
+        opp = opp_find_freq_exact(dev, 1000000000, false);
+        rcu_read_unlock();
+        /* dont operate on the pointer.. just do a sanity check.. */
+        if (IS_ERR(opp)) {
+               pr_err("frequency not disabled!\n");
+               /* trigger appropriate actions.. */
+        } else {
+               opp_enable(dev,1000000000);
+        }
+
+       NOTE: This is the only search function that operates on OPPs which are
+       not available.
+
+opp_find_freq_floor - Search for an available OPP which is *at most* the
+       provided frequency. This function is useful while searching for a lesser
+       match OR operating on OPP information in the order of decreasing
+       frequency.
+       Example: To find the highest opp for a device:
+        freq = ULONG_MAX;
+        rcu_read_lock();
+        opp_find_freq_floor(dev, &freq);
+        rcu_read_unlock();
+
+opp_find_freq_ceil - Search for an available OPP which is *at least* the
+       provided frequency. This function is useful while searching for a
+       higher match OR operating on OPP information in the order of increasing
+       frequency.
+       Example 1: To find the lowest opp for a device:
+        freq = 0;
+        rcu_read_lock();
+        opp_find_freq_ceil(dev, &freq);
+        rcu_read_unlock();
+       Example 2: A simplified implementation of a SoC cpufreq_driver->target:
+        soc_cpufreq_target(..)
+        {
+               /* Do stuff like policy checks etc. */
+               /* Find the best frequency match for the req */
+               rcu_read_lock();
+               opp = opp_find_freq_ceil(dev, &freq);
+               rcu_read_unlock();
+               if (!IS_ERR(opp))
+                       soc_switch_to_freq_voltage(freq);
+               else
+                       /* do something when we cant satisfy the req */
+               /* do other stuff */
+        }
+
+4. OPP Availability Control Functions
+=====================================
+A default OPP list registered with the OPP library may not cater to all possible
+situation. The OPP library provides a set of functions to modify the
+availability of a OPP within the OPP list. This allows SoC frameworks to have
+fine grained dynamic control of which sets of OPPs are operationally available.
+These functions are intended to *temporarily* remove an OPP in conditions such
+as thermal considerations (e.g. don't use OPPx until the temperature drops).
+
+WARNING: Do not use these functions in interrupt context.
+
+opp_enable - Make a OPP available for operation.
+       Example: Lets say that 1GHz OPP is to be made available only if the
+       SoC temperature is lower than a certain threshold. The SoC framework
+       implementation might choose to do something as follows:
+        if (cur_temp < temp_low_thresh) {
+               /* Enable 1GHz if it was disabled */
+               rcu_read_lock();
+               opp = opp_find_freq_exact(dev, 1000000000, false);
+               rcu_read_unlock();
+               /* just error check */
+               if (!IS_ERR(opp))
+                       ret = opp_enable(dev, 1000000000);
+               else
+                       goto try_something_else;
+        }
+
+opp_disable - Make an OPP to be not available for operation
+       Example: Lets say that 1GHz OPP is to be disabled if the temperature
+       exceeds a threshold value. The SoC framework implementation might
+       choose to do something as follows:
+        if (cur_temp > temp_high_thresh) {
+               /* Disable 1GHz if it was enabled */
+               rcu_read_lock();
+               opp = opp_find_freq_exact(dev, 1000000000, true);
+               rcu_read_unlock();
+               /* just error check */
+               if (!IS_ERR(opp))
+                       ret = opp_disable(dev, 1000000000);
+               else
+                       goto try_something_else;
+        }
+
+5. OPP Data Retrieval Functions
+===============================
+Since OPP library abstracts away the OPP information, a set of functions to pull
+information from the OPP structure is necessary. Once an OPP pointer is
+retrieved using the search functions, the following functions can be used by SoC
+framework to retrieve the information represented inside the OPP layer.
+
+opp_get_voltage - Retrieve the voltage represented by the opp pointer.
+       Example: At a cpufreq transition to a different frequency, SoC
+       framework requires to set the voltage represented by the OPP using
+       the regulator framework to the Power Management chip providing the
+       voltage.
+        soc_switch_to_freq_voltage(freq)
+        {
+               /* do things */
+               rcu_read_lock();
+               opp = opp_find_freq_ceil(dev, &freq);
+               v = opp_get_voltage(opp);
+               rcu_read_unlock();
+               if (v)
+                       regulator_set_voltage(.., v);
+               /* do other things */
+        }
+
+opp_get_freq - Retrieve the freq represented by the opp pointer.
+       Example: Lets say the SoC framework uses a couple of helper functions
+       we could pass opp pointers instead of doing additional parameters to
+       handle quiet a bit of data parameters.
+        soc_cpufreq_target(..)
+        {
+               /* do things.. */
+                max_freq = ULONG_MAX;
+                rcu_read_lock();
+                max_opp = opp_find_freq_floor(dev,&max_freq);
+                requested_opp = opp_find_freq_ceil(dev,&freq);
+                if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
+                       r = soc_test_validity(max_opp, requested_opp);
+                rcu_read_unlock();
+               /* do other things */
+        }
+        soc_test_validity(..)
+        {
+                if(opp_get_voltage(max_opp) < opp_get_voltage(requested_opp))
+                        return -EINVAL;
+                if(opp_get_freq(max_opp) < opp_get_freq(requested_opp))
+                        return -EINVAL;
+               /* do things.. */
+        }
+
+opp_get_opp_count - Retrieve the number of available opps for a device
+       Example: Lets say a co-processor in the SoC needs to know the available
+       frequencies in a table, the main processor can notify as following:
+        soc_notify_coproc_available_frequencies()
+        {
+               /* Do things */
+               rcu_read_lock();
+               num_available = opp_get_opp_count(dev);
+               speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
+               /* populate the table in increasing order */
+               freq = 0;
+               while (!IS_ERR(opp = opp_find_freq_ceil(dev, &freq))) {
+                       speeds[i] = freq;
+                       freq++;
+                       i++;
+               }
+               rcu_read_unlock();
+
+               soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
+               /* Do other things */
+        }
+
+6. Cpufreq Table Generation
+===========================
+opp_init_cpufreq_table - cpufreq framework typically is initialized with
+       cpufreq_frequency_table_cpuinfo which is provided with the list of
+       frequencies that are available for operation. This function provides
+       a ready to use conversion routine to translate the OPP layer's internal
+       information about the available frequencies into a format readily
+       providable to cpufreq.
+
+       WARNING: Do not use this function in interrupt context.
+
+       Example:
+        soc_pm_init()
+        {
+               /* Do things */
+               r = opp_init_cpufreq_table(dev, &freq_table);
+               if (!r)
+                       cpufreq_frequency_table_cpuinfo(policy, freq_table);
+               /* Do other things */
+        }
+
+       NOTE: This function is available only if CONFIG_CPU_FREQ is enabled in
+       addition to CONFIG_PM as power management feature is required to
+       dynamically scale voltage and frequency in a system.
+
+7. Data Structures
+==================
+Typically an SoC contains multiple voltage domains which are variable. Each
+domain is represented by a device pointer. The relationship to OPP can be
+represented as follows:
+SoC
+ |- device 1
+ |     |- opp 1 (availability, freq, voltage)
+ |     |- opp 2 ..
+ ...   ...
+ |     `- opp n ..
+ |- device 2
+ ...
+ `- device m
+
+OPP library maintains a internal list that the SoC framework populates and
+accessed by various functions as described above. However, the structures
+representing the actual OPPs and domains are internal to the OPP library itself
+to allow for suitable abstraction reusable across systems.
+
+struct opp - The internal data structure of OPP library which is used to
+       represent an OPP. In addition to the freq, voltage, availability
+       information, it also contains internal book keeping information required
+       for the OPP library to operate on.  Pointer to this structure is
+       provided back to the users such as SoC framework to be used as a
+       identifier for OPP in the interactions with OPP layer.
+
+       WARNING: The struct opp pointer should not be parsed or modified by the
+       users. The defaults of for an instance is populated by opp_add, but the
+       availability of the OPP can be modified by opp_enable/disable functions.
+
+struct device - This is used to identify a domain to the OPP layer. The
+       nature of the device and it's implementation is left to the user of
+       OPP library such as the SoC framework.
+
+Overall, in a simplistic view, the data structure operations is represented as
+following:
+
+Initialization / modification:
+            +-----+        /- opp_enable
+opp_add --> | opp | <-------
+  |         +-----+        \- opp_disable
+  \-------> domain_info(device)
+
+Search functions:
+             /-- opp_find_freq_ceil  ---\   +-----+
+domain_info<---- opp_find_freq_exact -----> | opp |
+             \-- opp_find_freq_floor ---/   +-----+
+
+Retrieval functions:
++-----+     /- opp_get_voltage
+| opp | <---
++-----+     \- opp_get_freq
+
+domain_info <- opp_get_opp_count
index 55b859b3bc723267db79d1b274bf820c37c7469a..489e9bacd165ad4a354130edcf7e03d97471b52b 100644 (file)
@@ -1,6 +1,7 @@
 Run-time Power Management Framework for I/O Devices
 
 (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+(C) 2010 Alan Stern <stern@rowland.harvard.edu>
 
 1. Introduction
 
@@ -157,7 +158,8 @@ rules:
     to execute it, the other callbacks will not be executed for the same device.
 
   * A request to execute ->runtime_resume() will cancel any pending or
-    scheduled requests to execute the other callbacks for the same device.
+    scheduled requests to execute the other callbacks for the same device,
+    except for scheduled autosuspends.
 
 3. Run-time PM Device Fields
 
@@ -165,7 +167,7 @@ The following device run-time PM fields are present in 'struct dev_pm_info', as
 defined in include/linux/pm.h:
 
   struct timer_list suspend_timer;
-    - timer used for scheduling (delayed) suspend request
+    - timer used for scheduling (delayed) suspend and autosuspend requests
 
   unsigned long timer_expires;
     - timer expiration time, in jiffies (if this is different from zero, the
@@ -230,6 +232,28 @@ defined in include/linux/pm.h:
       interface; it may only be modified with the help of the pm_runtime_allow()
       and pm_runtime_forbid() helper functions
 
+  unsigned int no_callbacks;
+    - indicates that the device does not use the run-time PM callbacks (see
+      Section 8); it may be modified only by the pm_runtime_no_callbacks()
+      helper function
+
+  unsigned int use_autosuspend;
+    - indicates that the device's driver supports delayed autosuspend (see
+      Section 9); it may be modified only by the
+      pm_runtime{_dont}_use_autosuspend() helper functions
+
+  unsigned int timer_autosuspends;
+    - indicates that the PM core should attempt to carry out an autosuspend
+      when the timer expires rather than a normal suspend
+
+  int autosuspend_delay;
+    - the delay time (in milliseconds) to be used for autosuspend
+
+  unsigned long last_busy;
+    - the time (in jiffies) when the pm_runtime_mark_last_busy() helper
+      function was last called for this device; used in calculating inactivity
+      periods for autosuspend
+
 All of the above fields are members of the 'power' member of 'struct device'.
 
 4. Run-time PM Device Helper Functions
@@ -255,6 +279,12 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
       error code on failure, where -EAGAIN or -EBUSY means it is safe to attempt
       to suspend the device again in future
 
+  int pm_runtime_autosuspend(struct device *dev);
+    - same as pm_runtime_suspend() except that the autosuspend delay is taken
+      into account; if pm_runtime_autosuspend_expiration() says the delay has
+      not yet expired then an autosuspend is scheduled for the appropriate time
+      and 0 is returned
+
   int pm_runtime_resume(struct device *dev);
     - execute the subsystem-level resume callback for the device; returns 0 on
       success, 1 if the device's run-time PM status was already 'active' or
@@ -267,6 +297,11 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
       device (the request is represented by a work item in pm_wq); returns 0 on
       success or error code if the request has not been queued up
 
+  int pm_request_autosuspend(struct device *dev);
+    - schedule the execution of the subsystem-level suspend callback for the
+      device when the autosuspend delay has expired; if the delay has already
+      expired then the work item is queued up immediately
+
   int pm_schedule_suspend(struct device *dev, unsigned int delay);
     - schedule the execution of the subsystem-level suspend callback for the
       device in future, where 'delay' is the time to wait before queuing up a
@@ -298,12 +333,20 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
     - decrement the device's usage counter
 
   int pm_runtime_put(struct device *dev);
-    - decrement the device's usage counter, run pm_request_idle(dev) and return
-      its result
+    - decrement the device's usage counter; if the result is 0 then run
+      pm_request_idle(dev) and return its result
+
+  int pm_runtime_put_autosuspend(struct device *dev);
+    - decrement the device's usage counter; if the result is 0 then run
+      pm_request_autosuspend(dev) and return its result
 
   int pm_runtime_put_sync(struct device *dev);
-    - decrement the device's usage counter, run pm_runtime_idle(dev) and return
-      its result
+    - decrement the device's usage counter; if the result is 0 then run
+      pm_runtime_idle(dev) and return its result
+
+  int pm_runtime_put_sync_autosuspend(struct device *dev);
+    - decrement the device's usage counter; if the result is 0 then run
+      pm_runtime_autosuspend(dev) and return its result
 
   void pm_runtime_enable(struct device *dev);
     - enable the run-time PM helper functions to run the device bus type's
@@ -349,19 +392,51 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
       counter (used by the /sys/devices/.../power/control interface to
       effectively prevent the device from being power managed at run time)
 
+  void pm_runtime_no_callbacks(struct device *dev);
+    - set the power.no_callbacks flag for the device and remove the run-time
+      PM attributes from /sys/devices/.../power (or prevent them from being
+      added when the device is registered)
+
+  void pm_runtime_mark_last_busy(struct device *dev);
+    - set the power.last_busy field to the current time
+
+  void pm_runtime_use_autosuspend(struct device *dev);
+    - set the power.use_autosuspend flag, enabling autosuspend delays
+
+  void pm_runtime_dont_use_autosuspend(struct device *dev);
+    - clear the power.use_autosuspend flag, disabling autosuspend delays
+
+  void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
+    - set the power.autosuspend_delay value to 'delay' (expressed in
+      milliseconds); if 'delay' is negative then run-time suspends are
+      prevented
+
+  unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
+    - calculate the time when the current autosuspend delay period will expire,
+      based on power.last_busy and power.autosuspend_delay; if the delay time
+      is 1000 ms or larger then the expiration time is rounded up to the
+      nearest second; returns 0 if the delay period has already expired or
+      power.use_autosuspend isn't set, otherwise returns the expiration time
+      in jiffies
+
 It is safe to execute the following helper functions from interrupt context:
 
 pm_request_idle()
+pm_request_autosuspend()
 pm_schedule_suspend()
 pm_request_resume()
 pm_runtime_get_noresume()
 pm_runtime_get()
 pm_runtime_put_noidle()
 pm_runtime_put()
+pm_runtime_put_autosuspend()
+pm_runtime_enable()
 pm_suspend_ignore_children()
 pm_runtime_set_active()
 pm_runtime_set_suspended()
-pm_runtime_enable()
+pm_runtime_suspended()
+pm_runtime_mark_last_busy()
+pm_runtime_autosuspend_expiration()
 
 5. Run-time PM Initialization, Device Probing and Removal
 
@@ -524,3 +599,141 @@ poweroff and run-time suspend callback, and similarly for system resume, thaw,
 restore, and run-time resume, can achieve this with the help of the
 UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its
 last argument to NULL).
+
+8. "No-Callback" Devices
+
+Some "devices" are only logical sub-devices of their parent and cannot be
+power-managed on their own.  (The prototype example is a USB interface.  Entire
+USB devices can go into low-power mode or send wake-up requests, but neither is
+possible for individual interfaces.)  The drivers for these devices have no
+need of run-time PM callbacks; if the callbacks did exist, ->runtime_suspend()
+and ->runtime_resume() would always return 0 without doing anything else and
+->runtime_idle() would always call pm_runtime_suspend().
+
+Subsystems can tell the PM core about these devices by calling
+pm_runtime_no_callbacks().  This should be done after the device structure is
+initialized and before it is registered (although after device registration is
+also okay).  The routine will set the device's power.no_callbacks flag and
+prevent the non-debugging run-time PM sysfs attributes from being created.
+
+When power.no_callbacks is set, the PM core will not invoke the
+->runtime_idle(), ->runtime_suspend(), or ->runtime_resume() callbacks.
+Instead it will assume that suspends and resumes always succeed and that idle
+devices should be suspended.
+
+As a consequence, the PM core will never directly inform the device's subsystem
+or driver about run-time power changes.  Instead, the driver for the device's
+parent must take responsibility for telling the device's driver when the
+parent's power state changes.
+
+9. Autosuspend, or automatically-delayed suspends
+
+Changing a device's power state isn't free; it requires both time and energy.
+A device should be put in a low-power state only when there's some reason to
+think it will remain in that state for a substantial time.  A common heuristic
+says that a device which hasn't been used for a while is liable to remain
+unused; following this advice, drivers should not allow devices to be suspended
+at run-time until they have been inactive for some minimum period.  Even when
+the heuristic ends up being non-optimal, it will still prevent devices from
+"bouncing" too rapidly between low-power and full-power states.
+
+The term "autosuspend" is an historical remnant.  It doesn't mean that the
+device is automatically suspended (the subsystem or driver still has to call
+the appropriate PM routines); rather it means that run-time suspends will
+automatically be delayed until the desired period of inactivity has elapsed.
+
+Inactivity is determined based on the power.last_busy field.  Drivers should
+call pm_runtime_mark_last_busy() to update this field after carrying out I/O,
+typically just before calling pm_runtime_put_autosuspend().  The desired length
+of the inactivity period is a matter of policy.  Subsystems can set this length
+initially by calling pm_runtime_set_autosuspend_delay(), but after device
+registration the length should be controlled by user space, using the
+/sys/devices/.../power/autosuspend_delay_ms attribute.
+
+In order to use autosuspend, subsystems or drivers must call
+pm_runtime_use_autosuspend() (preferably before registering the device), and
+thereafter they should use the various *_autosuspend() helper functions instead
+of the non-autosuspend counterparts:
+
+       Instead of: pm_runtime_suspend    use: pm_runtime_autosuspend;
+       Instead of: pm_schedule_suspend   use: pm_request_autosuspend;
+       Instead of: pm_runtime_put        use: pm_runtime_put_autosuspend;
+       Instead of: pm_runtime_put_sync   use: pm_runtime_put_sync_autosuspend.
+
+Drivers may also continue to use the non-autosuspend helper functions; they
+will behave normally, not taking the autosuspend delay into account.
+Similarly, if the power.use_autosuspend field isn't set then the autosuspend
+helper functions will behave just like the non-autosuspend counterparts.
+
+The implementation is well suited for asynchronous use in interrupt contexts.
+However such use inevitably involves races, because the PM core can't
+synchronize ->runtime_suspend() callbacks with the arrival of I/O requests.
+This synchronization must be handled by the driver, using its private lock.
+Here is a schematic pseudo-code example:
+
+       foo_read_or_write(struct foo_priv *foo, void *data)
+       {
+               lock(&foo->private_lock);
+               add_request_to_io_queue(foo, data);
+               if (foo->num_pending_requests++ == 0)
+                       pm_runtime_get(&foo->dev);
+               if (!foo->is_suspended)
+                       foo_process_next_request(foo);
+               unlock(&foo->private_lock);
+       }
+
+       foo_io_completion(struct foo_priv *foo, void *req)
+       {
+               lock(&foo->private_lock);
+               if (--foo->num_pending_requests == 0) {
+                       pm_runtime_mark_last_busy(&foo->dev);
+                       pm_runtime_put_autosuspend(&foo->dev);
+               } else {
+                       foo_process_next_request(foo);
+               }
+               unlock(&foo->private_lock);
+               /* Send req result back to the user ... */
+       }
+
+       int foo_runtime_suspend(struct device *dev)
+       {
+               struct foo_priv foo = container_of(dev, ...);
+               int ret = 0;
+
+               lock(&foo->private_lock);
+               if (foo->num_pending_requests > 0) {
+                       ret = -EBUSY;
+               } else {
+                       /* ... suspend the device ... */
+                       foo->is_suspended = 1;
+               }
+               unlock(&foo->private_lock);
+               return ret;
+       }
+
+       int foo_runtime_resume(struct device *dev)
+       {
+               struct foo_priv foo = container_of(dev, ...);
+
+               lock(&foo->private_lock);
+               /* ... resume the device ... */
+               foo->is_suspended = 0;
+               pm_runtime_mark_last_busy(&foo->dev);
+               if (foo->num_pending_requests > 0)
+                       foo_process_requests(foo);
+               unlock(&foo->private_lock);
+               return 0;
+       }
+
+The important point is that after foo_io_completion() asks for an autosuspend,
+the foo_runtime_suspend() callback may race with foo_read_or_write().
+Therefore foo_runtime_suspend() has to check whether there are any pending I/O
+requests (while holding the private lock) before allowing the suspend to
+proceed.
+
+In addition, the power.autosuspend_delay field can be changed by user space at
+any time.  If a driver cares about this, it can call
+pm_runtime_autosuspend_expiration() from within the ->runtime_suspend()
+callback while holding its private lock.  If the function returns a nonzero
+value then the delay has not yet expired and the callback should return
+-EAGAIN.
index 514b94fc931e09b337fd297401d9f9c1aa391dac..1bdfa04437732753636e3b6adfc84d7e2626adab 100644 (file)
@@ -49,6 +49,13 @@ machine that doesn't boot) is:
    device (lspci and /sys/devices/pci* is your friend), and see if you can
    fix it, disable it, or trace into its resume function.
 
+   If no device matches the hash (or any matches appear to be false positives),
+   the culprit may be a device from a loadable kernel module that is not loaded
+   until after the hash is checked. You can check the hash against the current
+   devices again after more modules are loaded using sysfs:
+
+       cat /sys/power/pm_trace_dev_match
+
 For example, the above happens to be the VGA device on my EVO, which I
 used to run with "radeonfb" (it's an ATI Radeon mobility). It turns out
 that "radeonfb" simply cannot resume that device - it tries to set the
index 9d60ab717a7b3c8dc0daa4d14e6a914884965bf0..ea718891a665b0cad258ec2881f6ab0b8b5fe96f 100644 (file)
@@ -66,7 +66,8 @@ swsusp saves the state of the machine into active swaps and then reboots or
 powerdowns.  You must explicitly specify the swap partition to resume from with
 ``resume='' kernel option. If signature is found it loads and restores saved
 state. If the option ``noresume'' is specified as a boot parameter, it skips
-the resuming.
+the resuming.  If the option ``hibernate=nocompress'' is specified as a boot
+parameter, it saves hibernation image without compression.
 
 In the meantime while the system is suspended you should not add/remove any
 of the hardware, write to the filesystems, etc.
index 80510c018eeaaec359d5d3b5f980d91938411a6e..777abd7399d5b4249abdd2fd427fca0942c7891e 100644 (file)
@@ -1,7 +1,9 @@
 * SPI (Serial Peripheral Interface)
 
 Required properties:
-- cell-index : SPI controller index.
+- cell-index : QE SPI subblock index.
+               0: QE subblock SPI1
+               1: QE subblock SPI2
 - compatible : should be "fsl,spi".
 - mode : the SPI operation mode, it can be "cpu" or "cpu-qe".
 - reg : Offset and length of the register set for the device
@@ -29,3 +31,23 @@ Example:
                gpios = <&gpio 18 1     // device reg=<0>
                         &gpio 19 1>;   // device reg=<1>
        };
+
+
+* eSPI (Enhanced Serial Peripheral Interface)
+
+Required properties:
+- compatible : should be "fsl,mpc8536-espi".
+- reg : Offset and length of the register set for the device.
+- interrupts : should contain eSPI interrupt, the device has one interrupt.
+- fsl,espi-num-chipselects : the number of the chipselect signals.
+
+Example:
+       spi@110000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "fsl,mpc8536-espi";
+               reg = <0x110000 0x1000>;
+               interrupts = <53 0x2>;
+               interrupt-parent = <&mpic>;
+               fsl,espi-num-chipselects = <4>;
+       };
index 7679bf32f7bbe382f5f30ed966732184873ce32b..b618b1e86c46b671fc2a766e1bd4127362129448 100644 (file)
@@ -990,11 +990,23 @@ S:        Supported
 F:     arch/arm/mach-shmobile/
 F:     drivers/sh/
 
+ARM/TELECHIPS ARM ARCHITECTURE
+M:     "Hans J. Koch" <hjk@linutronix.de>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+F:     arch/arm/plat-tcc/
+F:     arch/arm/mach-tcc8k/
+
 ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
+ARM/TETON BGA MACHINE SUPPORT
+M:     Mark F. Brown <mark.brown314@gmail.com>
+L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:     Maintained
+
 ARM/THECUS N2100 MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1527,6 +1539,8 @@ T:        git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
 S:     Supported
 F:     Documentation/filesystems/ceph.txt
 F:     fs/ceph
+F:     net/ceph
+F:     include/linux/ceph
 
 CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
 M:     David Vrabel <david.vrabel@csr.com>
@@ -3162,7 +3176,7 @@ F:        drivers/net/ioc3-eth.c
 
 IOC3 SERIAL DRIVER
 M:     Pat Gefre <pfg@sgi.com>
-L:     linux-mips@linux-mips.org
+L:     linux-serial@vger.kernel.org
 S:     Maintained
 F:     drivers/serial/ioc3_serial.c
 
@@ -3239,6 +3253,12 @@ F:       drivers/net/irda/
 F:     include/net/irda/
 F:     net/irda/
 
+IRQ SUBSYSTEM
+M:     Thomas Gleixner <tglx@linutronix.de>
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip.git irq/core
+F:     kernel/irq/
+
 ISAPNP
 M:     Jaroslav Kysela <perex@perex.cz>
 S:     Maintained
@@ -4805,6 +4825,15 @@ F:       fs/qnx4/
 F:     include/linux/qnx4_fs.h
 F:     include/linux/qnxtypes.h
 
+RADOS BLOCK DEVICE (RBD)
+F:     include/linux/qnxtypes.h
+M:     Yehuda Sadeh <yehuda@hq.newdream.net>
+M:     Sage Weil <sage@newdream.net>
+M:     ceph-devel@vger.kernel.org
+S:     Supported
+F:     drivers/block/rbd.c
+F:     drivers/block/rbd_types.h
+
 RADEON FRAMEBUFFER DISPLAY DRIVER
 M:     Benjamin Herrenschmidt <benh@kernel.crashing.org>
 L:     linux-fbdev@vger.kernel.org
index 7583116e5d9a2e4cdcd33d33bc1fb9da43c2fcb4..3e438055a92c503d48858761d56e00bcd9848276 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 36
-EXTRAVERSION = -rc8
+EXTRAVERSION =
 NAME = Flesh-Eating Bats with Fangs
 
 # *DOCUMENTATION*
@@ -554,8 +554,15 @@ endif
 ifdef CONFIG_FRAME_POINTER
 KBUILD_CFLAGS  += -fno-omit-frame-pointer -fno-optimize-sibling-calls
 else
+# Some targets (ARM with Thumb2, for example), can't be built with frame
+# pointers.  For those, we don't have FUNCTION_TRACER automatically
+# select FRAME_POINTER.  However, FUNCTION_TRACER adds -pg, and this is
+# incompatible with -fomit-frame-pointer with current GCC, so we don't use
+# -fomit-frame-pointer with FUNCTION_TRACER.
+ifndef CONFIG_FUNCTION_TRACER
 KBUILD_CFLAGS  += -fomit-frame-pointer
 endif
+endif
 
 ifdef CONFIG_DEBUG_INFO
 KBUILD_CFLAGS  += -g
@@ -568,6 +575,12 @@ endif
 
 ifdef CONFIG_FUNCTION_TRACER
 KBUILD_CFLAGS  += -pg
+ifdef CONFIG_DYNAMIC_FTRACE
+       ifdef CONFIG_HAVE_C_RECORDMCOUNT
+               BUILD_C_RECORDMCOUNT := y
+               export BUILD_C_RECORDMCOUNT
+       endif
+endif
 endif
 
 # We trigger additional mismatches with less inlining
@@ -591,6 +604,11 @@ KBUILD_CFLAGS      += $(call cc-option,-fno-strict-overflow)
 # conserve stack if available
 KBUILD_CFLAGS   += $(call cc-option,-fconserve-stack)
 
+# check for 'asm goto'
+ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
+       KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
+endif
+
 # Add user supplied CPPFLAGS, AFLAGS and CFLAGS as the last assignments
 # But warn user when we do so
 warn-assign = \
index fe48fc7a3ebaf85c9bf8c56391bf20d9c9b90bbf..53d7f619a1b9b46643c59cd3c7d4ace354148c20 100644 (file)
@@ -158,4 +158,7 @@ config HAVE_PERF_EVENTS_NMI
          subsystem.  Also has support for calculating CPU cycle events
          to determine how many clock cycles in a given period.
 
+config HAVE_ARCH_JUMP_LABEL
+       bool
+
 source "kernel/gcov/Kconfig"
index b9647bb66d1388d9c13503748252c2a1df4ac830..d04ccd73af45f6487f442a0dba26921db884e218 100644 (file)
@@ -9,6 +9,7 @@ config ALPHA
        select HAVE_IDE
        select HAVE_OPROFILE
        select HAVE_SYSCALL_WRAPPERS
+       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select HAVE_DMA_ATTRS
        help
diff --git a/arch/alpha/include/asm/irqflags.h b/arch/alpha/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..299bbc7
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __ALPHA_IRQFLAGS_H
+#define __ALPHA_IRQFLAGS_H
+
+#include <asm/system.h>
+
+#define IPL_MIN                0
+#define IPL_SW0                1
+#define IPL_SW1                2
+#define IPL_DEV0       3
+#define IPL_DEV1       4
+#define IPL_TIMER      5
+#define IPL_PERF       6
+#define IPL_POWERFAIL  6
+#define IPL_MCHECK     7
+#define IPL_MAX                7
+
+#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
+#undef IPL_MIN
+#define IPL_MIN                __min_ipl
+extern int __min_ipl;
+#endif
+
+#define getipl()               (rdps() & 7)
+#define setipl(ipl)            ((void) swpipl(ipl))
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       return rdps();
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       setipl(IPL_MAX);
+       barrier();
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags = swpipl(IPL_MAX);
+       barrier();
+       return flags;
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       barrier();
+       setipl(IPL_MIN);
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       barrier();
+       setipl(flags);
+       barrier();
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return flags == IPL_MAX;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(getipl());
+}
+
+#endif /* __ALPHA_IRQFLAGS_H */
index 4157cd3c44a96d2811410b334a35f11923ba6fbf..fe792ca818f64c4d9954e8b62e5f8064a5d5777e 100644 (file)
@@ -1,11 +1,6 @@
 #ifndef __ASM_ALPHA_PERF_EVENT_H
 #define __ASM_ALPHA_PERF_EVENT_H
 
-/* Alpha only supports software events through this interface. */
-extern void set_perf_event_pending(void);
-
-#define PERF_EVENT_INDEX_OFFSET 0
-
 #ifdef CONFIG_PERF_EVENTS
 extern void init_hw_perf_events(void);
 #else
index 5aa40cca4f2356ea12a62e8576d50303a2b704b5..9f78e693463755d8deb1194476e6adf12b673f4f 100644 (file)
@@ -259,34 +259,6 @@ __CALL_PAL_RW2(wrperfmon, unsigned long, unsigned long, unsigned long);
 __CALL_PAL_W1(wrusp, unsigned long);
 __CALL_PAL_W1(wrvptptr, unsigned long);
 
-#define IPL_MIN                0
-#define IPL_SW0                1
-#define IPL_SW1                2
-#define IPL_DEV0       3
-#define IPL_DEV1       4
-#define IPL_TIMER      5
-#define IPL_PERF       6
-#define IPL_POWERFAIL  6
-#define IPL_MCHECK     7
-#define IPL_MAX                7
-
-#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
-#undef IPL_MIN
-#define IPL_MIN                __min_ipl
-extern int __min_ipl;
-#endif
-
-#define getipl()               (rdps() & 7)
-#define setipl(ipl)            ((void) swpipl(ipl))
-
-#define local_irq_disable()                    do { setipl(IPL_MAX); barrier(); } while(0)
-#define local_irq_enable()                     do { barrier(); setipl(IPL_MIN); } while(0)
-#define local_save_flags(flags)        ((flags) = rdps())
-#define local_irq_save(flags)  do { (flags) = swpipl(IPL_MAX); barrier(); } while(0)
-#define local_irq_restore(flags)       do { barrier(); setipl(flags); barrier(); } while(0)
-
-#define irqs_disabled()        (getipl() == IPL_MAX)
-
 /*
  * TB routines..
  */
index 85d8e4f58c83ce612269162b9635bd49059c39dd..1cc49683fb69b2a5f96639e71a2f1af821479e77 100644 (file)
@@ -307,7 +307,7 @@ again:
                             new_raw_count) != prev_raw_count)
                goto again;
 
-       delta = (new_raw_count  - (prev_raw_count & alpha_pmu->pmc_count_mask[idx])) + ovf;
+       delta = (new_raw_count - (prev_raw_count & alpha_pmu->pmc_count_mask[idx])) + ovf;
 
        /* It is possible on very rare occasions that the PMC has overflowed
         * but the interrupt is yet to come.  Detect and fix this situation.
@@ -402,14 +402,13 @@ static void maybe_change_configuration(struct cpu_hw_events *cpuc)
                struct hw_perf_event *hwc = &pe->hw;
                int idx = hwc->idx;
 
-               if (cpuc->current_idx[j] != PMC_NO_INDEX) {
-                       cpuc->idx_mask |= (1<<cpuc->current_idx[j]);
-                       continue;
+               if (cpuc->current_idx[j] == PMC_NO_INDEX) {
+                       alpha_perf_event_set_period(pe, hwc, idx);
+                       cpuc->current_idx[j] = idx;
                }
 
-               alpha_perf_event_set_period(pe, hwc, idx);
-               cpuc->current_idx[j] = idx;
-               cpuc->idx_mask |= (1<<cpuc->current_idx[j]);
+               if (!(hwc->state & PERF_HES_STOPPED))
+                       cpuc->idx_mask |= (1<<cpuc->current_idx[j]);
        }
        cpuc->config = cpuc->event[0]->hw.config_base;
 }
@@ -420,12 +419,13 @@ static void maybe_change_configuration(struct cpu_hw_events *cpuc)
  *  - this function is called from outside this module via the pmu struct
  *    returned from perf event initialisation.
  */
-static int alpha_pmu_enable(struct perf_event *event)
+static int alpha_pmu_add(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
        int n0;
        int ret;
-       unsigned long flags;
+       unsigned long irq_flags;
 
        /*
         * The Sparc code has the IRQ disable first followed by the perf
@@ -435,8 +435,8 @@ static int alpha_pmu_enable(struct perf_event *event)
         * nevertheless we disable the PMCs first to enable a potential
         * final PMI to occur before we disable interrupts.
         */
-       perf_disable();
-       local_irq_save(flags);
+       perf_pmu_disable(event->pmu);
+       local_irq_save(irq_flags);
 
        /* Default to error to be returned */
        ret = -EAGAIN;
@@ -455,8 +455,12 @@ static int alpha_pmu_enable(struct perf_event *event)
                }
        }
 
-       local_irq_restore(flags);
-       perf_enable();
+       hwc->state = PERF_HES_UPTODATE;
+       if (!(flags & PERF_EF_START))
+               hwc->state |= PERF_HES_STOPPED;
+
+       local_irq_restore(irq_flags);
+       perf_pmu_enable(event->pmu);
 
        return ret;
 }
@@ -467,15 +471,15 @@ static int alpha_pmu_enable(struct perf_event *event)
  *  - this function is called from outside this module via the pmu struct
  *    returned from perf event initialisation.
  */
-static void alpha_pmu_disable(struct perf_event *event)
+static void alpha_pmu_del(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
-       unsigned long flags;
+       unsigned long irq_flags;
        int j;
 
-       perf_disable();
-       local_irq_save(flags);
+       perf_pmu_disable(event->pmu);
+       local_irq_save(irq_flags);
 
        for (j = 0; j < cpuc->n_events; j++) {
                if (event == cpuc->event[j]) {
@@ -501,8 +505,8 @@ static void alpha_pmu_disable(struct perf_event *event)
                }
        }
 
-       local_irq_restore(flags);
-       perf_enable();
+       local_irq_restore(irq_flags);
+       perf_pmu_enable(event->pmu);
 }
 
 
@@ -514,13 +518,44 @@ static void alpha_pmu_read(struct perf_event *event)
 }
 
 
-static void alpha_pmu_unthrottle(struct perf_event *event)
+static void alpha_pmu_stop(struct perf_event *event, int flags)
+{
+       struct hw_perf_event *hwc = &event->hw;
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+       if (!(hwc->state & PERF_HES_STOPPED)) {
+               cpuc->idx_mask &= ~(1UL<<hwc->idx);
+               hwc->state |= PERF_HES_STOPPED;
+       }
+
+       if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+               alpha_perf_event_update(event, hwc, hwc->idx, 0);
+               hwc->state |= PERF_HES_UPTODATE;
+       }
+
+       if (cpuc->enabled)
+               wrperfmon(PERFMON_CMD_DISABLE, (1UL<<hwc->idx));
+}
+
+
+static void alpha_pmu_start(struct perf_event *event, int flags)
 {
        struct hw_perf_event *hwc = &event->hw;
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
+       if (WARN_ON_ONCE(!(hwc->state & PERF_HES_STOPPED)))
+               return;
+
+       if (flags & PERF_EF_RELOAD) {
+               WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+               alpha_perf_event_set_period(event, hwc, hwc->idx);
+       }
+
+       hwc->state = 0;
+
        cpuc->idx_mask |= 1UL<<hwc->idx;
-       wrperfmon(PERFMON_CMD_ENABLE, (1UL<<hwc->idx));
+       if (cpuc->enabled)
+               wrperfmon(PERFMON_CMD_ENABLE, (1UL<<hwc->idx));
 }
 
 
@@ -642,39 +677,36 @@ static int __hw_perf_event_init(struct perf_event *event)
        return 0;
 }
 
-static const struct pmu pmu = {
-       .enable         = alpha_pmu_enable,
-       .disable        = alpha_pmu_disable,
-       .read           = alpha_pmu_read,
-       .unthrottle     = alpha_pmu_unthrottle,
-};
-
-
 /*
  * Main entry point to initialise a HW performance event.
  */
-const struct pmu *hw_perf_event_init(struct perf_event *event)
+static int alpha_pmu_event_init(struct perf_event *event)
 {
        int err;
 
+       switch (event->attr.type) {
+       case PERF_TYPE_RAW:
+       case PERF_TYPE_HARDWARE:
+       case PERF_TYPE_HW_CACHE:
+               break;
+
+       default:
+               return -ENOENT;
+       }
+
        if (!alpha_pmu)
-               return ERR_PTR(-ENODEV);
+               return -ENODEV;
 
        /* Do the real initialisation work. */
        err = __hw_perf_event_init(event);
 
-       if (err)
-               return ERR_PTR(err);
-
-       return &pmu;
+       return err;
 }
 
-
-
 /*
  * Main entry point - enable HW performance counters.
  */
-void hw_perf_enable(void)
+static void alpha_pmu_enable(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
@@ -700,7 +732,7 @@ void hw_perf_enable(void)
  * Main entry point - disable HW performance counters.
  */
 
-void hw_perf_disable(void)
+static void alpha_pmu_disable(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
@@ -713,6 +745,17 @@ void hw_perf_disable(void)
        wrperfmon(PERFMON_CMD_DISABLE, cpuc->idx_mask);
 }
 
+static struct pmu pmu = {
+       .pmu_enable     = alpha_pmu_enable,
+       .pmu_disable    = alpha_pmu_disable,
+       .event_init     = alpha_pmu_event_init,
+       .add            = alpha_pmu_add,
+       .del            = alpha_pmu_del,
+       .start          = alpha_pmu_start,
+       .stop           = alpha_pmu_stop,
+       .read           = alpha_pmu_read,
+};
+
 
 /*
  * Main entry point - don't know when this is called but it
@@ -766,7 +809,7 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr,
        wrperfmon(PERFMON_CMD_DISABLE, cpuc->idx_mask);
 
        /* la_ptr is the counter that overflowed. */
-       if (unlikely(la_ptr >= perf_max_events)) {
+       if (unlikely(la_ptr >= alpha_pmu->num_pmcs)) {
                /* This should never occur! */
                irq_err_count++;
                pr_warning("PMI: silly index %ld\n", la_ptr);
@@ -807,7 +850,7 @@ static void alpha_perf_event_irq_handler(unsigned long la_ptr,
                        /* Interrupts coming too quickly; "throttle" the
                         * counter, i.e., disable it for a little while.
                         */
-                       cpuc->idx_mask &= ~(1UL<<idx);
+                       alpha_pmu_stop(event, 0);
                }
        }
        wrperfmon(PERFMON_CMD_ENABLE, cpuc->idx_mask);
@@ -837,6 +880,7 @@ void __init init_hw_perf_events(void)
 
        /* And set up PMU specification */
        alpha_pmu = &ev67_pmu;
-       perf_max_events = alpha_pmu->num_pmcs;
+
+       perf_pmu_register(&pmu);
 }
 
index 396af1799ea44e3a80bd758226f31f0c3bced799..0f1d8493cfca9c498a5187b97ae7c9dff8195b71 100644 (file)
@@ -41,7 +41,7 @@
 #include <linux/init.h>
 #include <linux/bcd.h>
 #include <linux/profile.h>
-#include <linux/perf_event.h>
+#include <linux/irq_work.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -83,25 +83,25 @@ static struct {
 
 unsigned long est_cycle_freq;
 
-#ifdef CONFIG_PERF_EVENTS
+#ifdef CONFIG_IRQ_WORK
 
-DEFINE_PER_CPU(u8, perf_event_pending);
+DEFINE_PER_CPU(u8, irq_work_pending);
 
-#define set_perf_event_pending_flag()  __get_cpu_var(perf_event_pending) = 1
-#define test_perf_event_pending()      __get_cpu_var(perf_event_pending)
-#define clear_perf_event_pending()     __get_cpu_var(perf_event_pending) = 0
+#define set_irq_work_pending_flag()  __get_cpu_var(irq_work_pending) = 1
+#define test_irq_work_pending()      __get_cpu_var(irq_work_pending)
+#define clear_irq_work_pending()     __get_cpu_var(irq_work_pending) = 0
 
-void set_perf_event_pending(void)
+void set_irq_work_pending(void)
 {
-       set_perf_event_pending_flag();
+       set_irq_work_pending_flag();
 }
 
-#else  /* CONFIG_PERF_EVENTS */
+#else  /* CONFIG_IRQ_WORK */
 
-#define test_perf_event_pending()      0
-#define clear_perf_event_pending()
+#define test_irq_work_pending()      0
+#define clear_irq_work_pending()
 
-#endif /* CONFIG_PERF_EVENTS */
+#endif /* CONFIG_IRQ_WORK */
 
 
 static inline __u32 rpcc(void)
@@ -191,9 +191,9 @@ irqreturn_t timer_interrupt(int irq, void *dev)
 
        write_sequnlock(&xtime_lock);
 
-       if (test_perf_event_pending()) {
-               clear_perf_event_pending();
-               perf_event_do_pending();
+       if (test_irq_work_pending()) {
+               clear_irq_work_pending();
+               irq_work_run();
        }
 
 #ifndef CONFIG_SMP
index 9c26ba7244fb450b0c73f15ca2565336033e152b..3849887157e72050188f7b627ece321ffe771e60 100644 (file)
@@ -19,13 +19,17 @@ config ARM
        select HAVE_KPROBES if (!XIP_KERNEL)
        select HAVE_KRETPROBES if (HAVE_KPROBES)
        select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
+       select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
+       select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL)
        select HAVE_GENERIC_DMA_COHERENT
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZO
        select HAVE_KERNEL_LZMA
+       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
        select HAVE_REGS_AND_STACK_ACCESS_API
+       select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V7))
        help
          The ARM series is a line of low-power-consumption RISC chip designs
          licensed by ARM Ltd and targeted at embedded applications and
@@ -145,6 +149,9 @@ config ARCH_HAS_CPUFREQ
          and that the relevant menu configurations are displayed for
          it.
 
+config ARCH_HAS_CPU_IDLE_WAIT
+       def_bool y
+
 config GENERIC_HWEIGHT
        bool
        default y
@@ -510,6 +517,7 @@ config ARCH_MMP
        select GENERIC_CLOCKEVENTS
        select TICK_ONESHOT
        select PLAT_PXA
+       select SPARSE_IRQ
        help
          Support for Marvell's PXA168/PXA910(MMP) and MMP2 processor line.
 
@@ -587,6 +595,7 @@ config ARCH_PXA
        select GENERIC_CLOCKEVENTS
        select TICK_ONESHOT
        select PLAT_PXA
+       select SPARSE_IRQ
        help
          Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
 
@@ -678,8 +687,8 @@ config ARCH_S3C64XX
        help
          Samsung S3C64XX series based systems
 
-config ARCH_S5P6440
-       bool "Samsung S5P6440"
+config ARCH_S5P64X0
+       bool "Samsung S5P6440 S5P6450"
        select CPU_V6
        select GENERIC_GPIO
        select HAVE_CLK
@@ -688,7 +697,8 @@ config ARCH_S5P6440
        select HAVE_S3C2410_I2C
        select HAVE_S3C_RTC
        help
-         Samsung S5P6440 CPU based systems
+         Samsung S5P64X0 CPU based systems, such as the Samsung SMDK6440,
+         SMDK6450.
 
 config ARCH_S5P6442
        bool "Samsung S5P6442"
@@ -747,6 +757,15 @@ config ARCH_SHARK
          Support for the StrongARM based Digital DNARD machine, also known
          as "Shark" (<http://www.shark-linux.de/shark.html>).
 
+config ARCH_TCC_926
+       bool "Telechips TCC ARM926-based systems"
+       select CPU_ARM926T
+       select HAVE_CLK
+       select COMMON_CLKDEV
+       select GENERIC_CLOCKEVENTS
+       help
+         Support for Telechips TCC ARM926-based systems.
+
 config ARCH_LH7A40X
        bool "Sharp LH7A40X"
        select CPU_ARM922T
@@ -915,6 +934,8 @@ source "arch/arm/plat-s5p/Kconfig"
 
 source "arch/arm/plat-spear/Kconfig"
 
+source "arch/arm/plat-tcc/Kconfig"
+
 if ARCH_S3C2410
 source "arch/arm/mach-s3c2400/Kconfig"
 source "arch/arm/mach-s3c2410/Kconfig"
@@ -928,7 +949,7 @@ if ARCH_S3C64XX
 source "arch/arm/mach-s3c64xx/Kconfig"
 endif
 
-source "arch/arm/mach-s5p6440/Kconfig"
+source "arch/arm/mach-s5p64x0/Kconfig"
 
 source "arch/arm/mach-s5p6442/Kconfig"
 
@@ -1002,7 +1023,7 @@ endif
 
 config ARM_ERRATA_411920
        bool "ARM errata: Invalidation of the Instruction Cache operation can fail"
-       depends on CPU_V6 && !SMP
+       depends on CPU_V6
        help
          Invalidation of the Instruction Cache operation can
          fail. This erratum is present in 1136 (before r1p4), 1156 and 1176.
@@ -1181,13 +1202,13 @@ source "kernel/time/Kconfig"
 
 config SMP
        bool "Symmetric Multi-Processing (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && (REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP ||\
-                MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 ||\
-                ARCH_S5PV310 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4)
+       depends on EXPERIMENTAL
        depends on GENERIC_CLOCKEVENTS
+       depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \
+                MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 ||\
+                ARCH_S5PV310 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4
        select USE_GENERIC_SMP_HELPERS
-       select HAVE_ARM_SCU if ARCH_REALVIEW || ARCH_OMAP4 || ARCH_S5PV310 ||\
-                ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4
+       select HAVE_ARM_SCU
        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
@@ -1205,6 +1226,19 @@ config SMP
 
          If you don't know what to do here, say N.
 
+config SMP_ON_UP
+       bool "Allow booting SMP kernel on uniprocessor systems (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       depends on SMP && !XIP && !THUMB2_KERNEL
+       default y
+       help
+         SMP kernels contain instructions which fail on non-SMP processors.
+         Enabling this option allows the kernel to modify itself to make
+         these instructions safe.  Disabling it allows about 1K of space
+         savings.
+
+         If you don't know what to do here, say Y.
+
 config HAVE_ARM_SCU
        bool
        depends on SMP
@@ -1255,12 +1289,9 @@ config HOTPLUG_CPU
 
 config LOCAL_TIMERS
        bool "Use local timer interrupts"
-       depends on SMP && (REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || \
-               REALVIEW_EB_A9MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
-               ARCH_S5PV310 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4)
+       depends on SMP
        default y
-       select HAVE_ARM_TWD if ARCH_REALVIEW || ARCH_OMAP4 || ARCH_S5PV310 || \
-               ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS
+       select HAVE_ARM_TWD
        help
          Enable support for local timers on SMP platforms, rather then the
          legacy IPI broadcast method.  Local timers allows the system
@@ -1271,7 +1302,7 @@ source kernel/Kconfig.preempt
 
 config HZ
        int
-       default 200 if ARCH_EBSA110 || ARCH_S3C2410 || ARCH_S5P6440 || \
+       default 200 if ARCH_EBSA110 || ARCH_S3C2410 || ARCH_S5P64X0 || \
                ARCH_S5P6442 || ARCH_S5PV210 || ARCH_S5PV310
        default OMAP_32K_TIMER_HZ if ARCH_OMAP && OMAP_32K_TIMER
        default AT91_TIMER_HZ if ARCH_AT91
@@ -1477,6 +1508,20 @@ config UACCESS_WITH_MEMCPY
          However, if the CPU data cache is using a write-allocate mode,
          this option is unlikely to provide any performance gain.
 
+config SECCOMP
+       bool
+       prompt "Enable seccomp to safely compute untrusted bytecode"
+       ---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 prctl(PR_SET_SECCOMP), it cannot be disabled
+         and the task is only allowed to execute a few safe syscalls
+         defined by each seccomp mode.
+
 config CC_STACKPROTECTOR
        bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
        help
index 91344af75f39694f89d1b4e16529184816f42965..2fd0b99afc4bc849cd448780358fa5fdd68ff644 100644 (file)
@@ -2,6 +2,20 @@ menu "Kernel hacking"
 
 source "lib/Kconfig.debug"
 
+config STRICT_DEVMEM
+       bool "Filter access to /dev/mem"
+       depends on MMU
+       ---help---
+         If this option is disabled, you allow userspace (root) access to all
+         of memory, including kernel and userspace memory. Accidental
+         access to this is obviously disastrous, but specific access can
+         be used by people debugging the kernel.
+
+         If this option is switched on, the /dev/mem file only allows
+         userspace access to memory mapped peripherals.
+
+          If in doubt, say Y.
+
 # RMK wants arm kernels compiled with frame pointers or stack unwinding.
 # If you know what you are doing and are willing to live without stack
 # traces, you can get a slightly smaller kernel by setting this option to
@@ -27,6 +41,11 @@ config ARM_UNWIND
          the performance is not affected. Currently, this feature
          only works with EABI compilers. If unsure say Y.
 
+config OLD_MCOUNT
+       bool
+       depends on FUNCTION_TRACER && FRAME_POINTER
+       default y
+
 config DEBUG_USER
        bool "Verbose user fault messages"
        help
index 59c1ce858fc8b18d4ec613e6dd2bfe62ed06047e..b87aed028eeff2dc50bb4b7c1005f9daadac26a8 100644 (file)
@@ -173,7 +173,7 @@ machine-$(CONFIG_ARCH_RPC)          := rpc
 machine-$(CONFIG_ARCH_S3C2410)         := s3c2410 s3c2400 s3c2412 s3c2416 s3c2440 s3c2443
 machine-$(CONFIG_ARCH_S3C24A0)         := s3c24a0
 machine-$(CONFIG_ARCH_S3C64XX)         := s3c64xx
-machine-$(CONFIG_ARCH_S5P6440)         := s5p6440
+machine-$(CONFIG_ARCH_S5P64X0)         := s5p64x0
 machine-$(CONFIG_ARCH_S5P6442)         := s5p6442
 machine-$(CONFIG_ARCH_S5PC100)         := s5pc100
 machine-$(CONFIG_ARCH_S5PV210)         := s5pv210
@@ -183,6 +183,7 @@ machine-$(CONFIG_ARCH_SHARK)                := shark
 machine-$(CONFIG_ARCH_SHMOBILE)        := shmobile
 machine-$(CONFIG_ARCH_STMP378X)                := stmp378x
 machine-$(CONFIG_ARCH_STMP37XX)                := stmp37xx
+machine-$(CONFIG_ARCH_TCC8K)           := tcc8k
 machine-$(CONFIG_ARCH_TEGRA)           := tegra
 machine-$(CONFIG_ARCH_U300)            := u300
 machine-$(CONFIG_ARCH_U8500)           := ux500
@@ -202,6 +203,7 @@ plat-$(CONFIG_ARCH_MXC)             := mxc
 plat-$(CONFIG_ARCH_OMAP)       := omap
 plat-$(CONFIG_ARCH_S3C64XX)    := samsung
 plat-$(CONFIG_ARCH_STMP3XXX)   := stmp3xxx
+plat-$(CONFIG_ARCH_TCC_926)    := tcc
 plat-$(CONFIG_PLAT_IOP)                := iop
 plat-$(CONFIG_PLAT_NOMADIK)    := nomadik
 plat-$(CONFIG_PLAT_ORION)      := orion
@@ -245,13 +247,14 @@ ifeq ($(FASTFPE),$(wildcard $(FASTFPE)))
 FASTFPE_OBJ    :=$(FASTFPE)/
 endif
 
-# If we have a machine-specific directory, then include it in the build.
-core-y                         += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
-core-y                         += $(machdirs) $(platdirs)
 core-$(CONFIG_FPE_NWFPE)       += arch/arm/nwfpe/
 core-$(CONFIG_FPE_FASTFPE)     += $(FASTFPE_OBJ)
 core-$(CONFIG_VFP)             += arch/arm/vfp/
 
+# If we have a machine-specific directory, then include it in the build.
+core-y                         += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
+core-y                         += $(machdirs) $(platdirs)
+
 drivers-$(CONFIG_OPROFILE)      += arch/arm/oprofile/
 
 libs-y                         := arch/arm/lib/ $(libs-y)
index 7dfa9a85bc0c875b11567025f68e92bd768d7419..ada6359160ebef12614e9cd725449e5353a7a85b 100644 (file)
@@ -67,25 +67,11 @@ static inline unsigned int gic_irq(unsigned int irq)
 
 /*
  * Routines to acknowledge, disable and enable interrupts
- *
- * Linux assumes that when we're done with an interrupt we need to
- * unmask it, in the same way we need to unmask an interrupt when
- * we first enable it.
- *
- * The GIC has a separate notion of "end of interrupt" to re-enable
- * an interrupt after handling, in order to support hardware
- * prioritisation.
- *
- * We can make the GIC behave in the way that Linux expects by making
- * our "acknowledge" routine disable the interrupt, then mark it as
- * complete.
  */
 static void gic_ack_irq(unsigned int irq)
 {
-       u32 mask = 1 << (irq % 32);
 
        spin_lock(&irq_controller_lock);
-       writel(mask, gic_dist_base(irq) + GIC_DIST_ENABLE_CLEAR + (gic_irq(irq) / 32) * 4);
        writel(gic_irq(irq), gic_cpu_base(irq) + GIC_CPU_EOI);
        spin_unlock(&irq_controller_lock);
 }
index 5ebbab6242a78ccb1c23d649cb9a4ee608e2ed3c..8f0f86db36024e885778f9ddd864fab69eed1c27 100644 (file)
 #define DESIGNER       0x41
 #define REVISION       0x0
 #define INTEG_CFG      0x0
-#define PERIPH_ID_VAL  ((PART << 0) | (DESIGNER << 12) \
-                         | (REVISION << 20) | (INTEG_CFG << 24))
+#define PERIPH_ID_VAL  ((PART << 0) | (DESIGNER << 12))
 
 #define PCELL_ID_VAL   0xb105f00d
 
@@ -1859,10 +1858,10 @@ int pl330_add(struct pl330_info *pi)
        regs = pi->base;
 
        /* Check if we can handle this DMAC */
-       if (get_id(pi, PERIPH_ID) != PERIPH_ID_VAL
+       if ((get_id(pi, PERIPH_ID) & 0xfffff) != PERIPH_ID_VAL
           || get_id(pi, PCELL_ID) != PCELL_ID_VAL) {
                dev_err(pi->dev, "PERIPH_ID 0x%x, PCELL_ID 0x%x !\n",
-                       readl(regs + PERIPH_ID), readl(regs + PCELL_ID));
+                       get_id(pi, PERIPH_ID), get_id(pi, PCELL_ID));
                return -EINVAL;
        }
 
index 517d50ddbeb3153d102e426fc915405bae76012b..c0258a8c103bd49c354154e4d3c66d9b12dd2f6b 100644 (file)
@@ -678,7 +678,7 @@ out:
  *     %-EBUSY         physical address already marked in-use.
  *     %0              successful.
  */
-static int
+static int __devinit
 __sa1111_probe(struct device *me, struct resource *mem, int irq)
 {
        struct sa1111 *sachip;
index f1bac70d6ce95f7ae364dd6eb8d4e745dea19fdf..9e90e6d792973042ec81faf2f78433e416a2752d 100644 (file)
@@ -13,6 +13,7 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_ARCH_AT91=y
 CONFIG_ARCH_AT91SAM9G20=y
 CONFIG_MACH_AT91SAM9G20EK=y
+CONFIG_MACH_AT91SAM9G20EK_2MMC=y
 CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
 # CONFIG_ARM_THUMB is not set
 CONFIG_AEABI=y
index ccc9c9959b82baf75d0faa04769a85e79ac23d51..2f7042813765f783fd139d4a7680b880bf9574e5 100644 (file)
@@ -15,6 +15,7 @@ CONFIG_MACH_MV88F6281GTW_GE=y
 CONFIG_MACH_SHEEVAPLUG=y
 CONFIG_MACH_ESATA_SHEEVAPLUG=y
 CONFIG_MACH_GURUPLUG=y
+CONFIG_MACH_DOCKSTAR=y
 CONFIG_MACH_TS219=y
 CONFIG_MACH_TS41X=y
 CONFIG_MACH_OPENRD_BASE=y
index b2038b0e266f351cfca1b583c894cb8c0bc98028..813cfb366c1830bd3fc5e0df3ff1328931cd921d 100644 (file)
@@ -21,8 +21,14 @@ CONFIG_ARCH_MX2=y
 CONFIG_MACH_MX27=y
 CONFIG_MACH_MX27ADS=y
 CONFIG_MACH_PCM038=y
+CONFIG_MACH_CPUIMX27=y
+CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2=y
+CONFIG_MACH_EUKREA_CPUIMX27_USEUART4=y
 CONFIG_MACH_MX27_3DS=y
+CONFIG_MACH_IMX27_VISSTRIM_M10=y
 CONFIG_MACH_IMX27LITE=y
+CONFIG_MACH_PCA100=y
+CONFIG_MACH_MXT_TD60=y
 CONFIG_MXC_IRQ_PRIOR=y
 CONFIG_MXC_PWM=y
 CONFIG_NO_HZ=y
@@ -76,7 +82,9 @@ CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=m
 # CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=m
 CONFIG_SERIAL_IMX=y
 CONFIG_SERIAL_IMX_CONSOLE=y
 # CONFIG_LEGACY_PTYS is not set
@@ -85,19 +93,20 @@ CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=y
 CONFIG_I2C_IMX=y
 CONFIG_SPI=y
-CONFIG_SPI_BITBANG=y
+CONFIG_SPI_IMX=y
 CONFIG_W1=y
 CONFIG_W1_MASTER_MXC=y
 CONFIG_W1_SLAVE_THERM=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_FB_IMX=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
 # CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_USB=m
+# CONFIG_USB_DEVICE_CLASS is not set
+CONFIG_USB_ULPI=y
 CONFIG_MMC=y
 CONFIG_MMC_MXC=y
 CONFIG_RTC_CLASS=y
diff --git a/arch/arm/configs/mx31pdk_defconfig b/arch/arm/configs/mx31pdk_defconfig
deleted file mode 100644 (file)
index 2d29329..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-# CONFIG_COMPAT_BRK is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_MXC=y
-# CONFIG_MACH_MX31ADS is not set
-CONFIG_MACH_MX31_3DS=y
-CONFIG_AEABI=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_LRO is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_FIRMWARE_IN_KERNEL is not set
-# CONFIG_BLK_DEV is not set
-# CONFIG_MISC_DEVICES is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_DEVKMEM is not set
-CONFIG_SERIAL_IMX=y
-CONFIG_SERIAL_IMX_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRC32 is not set
index 161f907b611f388badcb21d4ecbb1d0923ff670f..f0c339fd5d21374e1721c9516822cae038c3639d 100644 (file)
@@ -24,6 +24,7 @@ CONFIG_MACH_PCM043=y
 CONFIG_MACH_ARMADILLO5X0=y
 CONFIG_MACH_MX35_3DS=y
 CONFIG_MACH_KZM_ARM11_01=y
+CONFIG_MACH_EUKREA_CPUIMX35=y
 CONFIG_MXC_IRQ_PRIOR=y
 CONFIG_MXC_PWM=y
 CONFIG_NO_HZ=y
@@ -108,7 +109,6 @@ CONFIG_MMC=y
 CONFIG_MMC_MXC=y
 CONFIG_DMADEVICES=y
 # CONFIG_DNOTIFY is not set
-CONFIG_INOTIFY=y
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_UBIFS_FS=y
index a665ecbbe2bc2b64cad0aa439b9bf32c6c4d6c11..163cfee7644c72c3699cd807f5571d1e79aa6123 100644 (file)
@@ -15,6 +15,8 @@ CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_ARCH_MXC=y
 CONFIG_ARCH_MX5=y
 CONFIG_MACH_MX51_BABBAGE=y
+CONFIG_MACH_MX51_3DS=y
+CONFIG_MACH_EUKREA_CPUIMX51=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT_VOLUNTARY=y
@@ -69,7 +71,6 @@ CONFIG_REALTEK_PHY=y
 CONFIG_NATIONAL_PHY=y
 CONFIG_STE10XP=y
 CONFIG_LSI_ET1011C_PHY=y
-CONFIG_FIXED_PHY=y
 CONFIG_MDIO_BITBANG=y
 CONFIG_MDIO_GPIO=y
 CONFIG_NET_ETHERNET=y
@@ -100,7 +101,6 @@ CONFIG_I2C_ALGOPCF=m
 CONFIG_I2C_ALGOPCA=m
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
 # CONFIG_HID_SUPPORT is not set
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
@@ -117,13 +117,11 @@ CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
 CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=y
-CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
 CONFIG_EXT3_FS_POSIX_ACL=y
 CONFIG_EXT3_FS_SECURITY=y
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
-CONFIG_INOTIFY=y
 CONFIG_QUOTA=y
 CONFIG_QUOTA_NETLINK_INTERFACE=y
 # CONFIG_PRINT_QUOTA_WARNING is not set
@@ -136,6 +134,7 @@ CONFIG_ZISOFS=y
 CONFIG_UDF_FS=m
 CONFIG_MSDOS_FS=m
 CONFIG_VFAT_FS=y
+CONFIG_TMPFS=y
 CONFIG_CONFIGFS_FS=m
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -151,7 +150,6 @@ CONFIG_NLS_UTF8=y
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DETECT_SOFTLOCKUP is not set
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
@@ -159,7 +157,6 @@ CONFIG_DEBUG_KERNEL=y
 # CONFIG_ARM_UNWIND is not set
 CONFIG_DEBUG_LL=y
 CONFIG_EARLY_PRINTK=y
-CONFIG_KEYS=y
 CONFIG_SECURITYFS=y
 CONFIG_CRYPTO_DEFLATE=y
 CONFIG_CRYPTO_LZO=y
index 9312ef9f9bf42b82ca2e05ad99bb951bc5c2306b..5ca7a61f7c01d6d5eef1591f80fad1152a9dab31 100644 (file)
@@ -39,6 +39,7 @@ CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_ARM_CHARLCD=y
 CONFIG_NETDEVICES=y
 CONFIG_SMSC_PHY=y
 CONFIG_NET_ETHERNET=y
@@ -52,10 +53,13 @@ CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_VERSATILE=y
+CONFIG_SPI=y
+CONFIG_GPIOLIB=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_FB_ARMCLCD=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
@@ -70,7 +74,13 @@ CONFIG_SND_ARMAACI=y
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
-CONFIG_INOTIFY=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_PL031=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_CRAMFS=y
@@ -80,6 +90,7 @@ CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
index fb75192ee7e5afa21f5d8c2907a476e36d02cee6..fcaa60328051254439df8f96dc2013b8dc750a4e 100644 (file)
@@ -38,6 +38,7 @@ CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
 CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_ARM_CHARLCD=y
 CONFIG_NETDEVICES=y
 CONFIG_SMSC_PHY=y
 CONFIG_NET_ETHERNET=y
@@ -51,10 +52,13 @@ CONFIG_SERIAL_AMBA_PL011=y
 CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_VERSATILE=y
+CONFIG_SPI=y
+CONFIG_GPIOLIB=y
 # CONFIG_HWMON is not set
 CONFIG_FB=y
 CONFIG_FB_ARMCLCD=y
-# CONFIG_VGA_CONSOLE is not set
 CONFIG_FRAMEBUFFER_CONSOLE=y
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
@@ -69,7 +73,13 @@ CONFIG_SND_ARMAACI=y
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
 CONFIG_MMC_ARMMMCI=y
-CONFIG_INOTIFY=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_PL031=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
 CONFIG_CRAMFS=y
@@ -79,6 +89,7 @@ CONFIG_ROOT_NFS=y
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
 # CONFIG_SCHED_DEBUG is not set
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
similarity index 97%
rename from arch/arm/configs/s5p6440_defconfig
rename to arch/arm/configs/s5p64x0_defconfig
index 0b0266c6d3269592ed882fc664dee73dd045d5e1..2993ecd35145265d0cf2566bbf227158cd07a5c5 100644 (file)
@@ -5,10 +5,11 @@ CONFIG_KALLSYMS_ALL=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_S5P6440=y
+CONFIG_ARCH_S5P64X0=y
 CONFIG_S3C_BOOT_ERROR_RESET=y
 CONFIG_S3C_LOWLEVEL_UART_PORT=1
 CONFIG_MACH_SMDK6440=y
+CONFIG_MACH_SMDK6450=y
 CONFIG_CPU_32v6K=y
 CONFIG_AEABI=y
 CONFIG_CMDLINE="root=/dev/ram0 rw ramdisk=8192 initrd=0x20800000,8M console=ttySAC1,115200 init=/linuxrc"
index 46e5e0747269beade612d95c01ba4707acdfc59b..c1c252cdca60702334e1f6e0abae37836c5b7462 100644 (file)
@@ -28,26 +28,9 @@ CONFIG_CPU_IDLE=y
 CONFIG_FPE_NWFPE=y
 CONFIG_PM=y
 # CONFIG_SUSPEND is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# 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_IPV6 is not set
-# CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MISC_DEVICES is not set
 # CONFIG_INPUT_MOUSEDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_KEYBOARD_ATKBD is not set
@@ -58,7 +41,6 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_LEGACY_PTY_COUNT=16
 # CONFIG_HW_RANDOM is not set
 CONFIG_I2C=y
-CONFIG_POWER_SUPPLY=y
 # CONFIG_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_REGULATOR=y
@@ -66,24 +48,10 @@ CONFIG_FB=y
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_SOUND=y
-CONFIG_SND=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
-# CONFIG_SND_VERBOSE_PROCFS 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_HID_SUPPORT is not set
 # CONFIG_USB_SUPPORT is not set
 CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
 CONFIG_MMC_ARMMMCI=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_BACKLIGHT=y
 CONFIG_RTC_CLASS=y
 # CONFIG_RTC_HCTOSYS is not set
 CONFIG_RTC_DRV_COH901331=y
@@ -93,12 +61,11 @@ CONFIG_COH901318=y
 CONFIG_FUSE_FS=y
 CONFIG_VFAT_FS=y
 CONFIG_TMPFS=y
-# CONFIG_NETWORK_FILESYSTEMS is not set
 CONFIG_NLS_CODEPAGE_437=y
 CONFIG_NLS_ISO8859_1=y
 CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
 CONFIG_DEBUG_KERNEL=y
-# CONFIG_DETECT_SOFTLOCKUP is not set
 # CONFIG_SCHED_DEBUG is not set
 CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_PREEMPT is not set
index 6e8f05c8a1c8f61efbffbb8cab303dd28e36efc0..062b58c029ab92ceb23cf0616568a76d3ec3a6b1 100644 (file)
        .long   9999b,9001f;                    \
        .popsection
 
+#ifdef CONFIG_SMP
+#define ALT_SMP(instr...)                                      \
+9998:  instr
+#define ALT_UP(instr...)                                       \
+       .pushsection ".alt.smp.init", "a"                       ;\
+       .long   9998b                                           ;\
+       instr                                                   ;\
+       .popsection
+#define ALT_UP_B(label)                                        \
+       .equ    up_b_offset, label - 9998b                      ;\
+       .pushsection ".alt.smp.init", "a"                       ;\
+       .long   9998b                                           ;\
+       b       . + up_b_offset                                 ;\
+       .popsection
+#else
+#define ALT_SMP(instr...)
+#define ALT_UP(instr...) instr
+#define ALT_UP_B(label) b label
+#endif
+
 /*
  * SMP data memory barrier
  */
        .macro  smp_dmb
 #ifdef CONFIG_SMP
 #if __LINUX_ARM_ARCH__ >= 7
-       dmb
+       ALT_SMP(dmb)
 #elif __LINUX_ARM_ARCH__ == 6
-       mcr     p15, 0, r0, c7, c10, 5  @ dmb
+       ALT_SMP(mcr     p15, 0, r0, c7, c10, 5) @ dmb
+#else
+#error Incompatible SMP platform
 #endif
+       ALT_UP(nop)
 #endif
        .endm
 
index 4656a24058d21f75d30097ae5b06a1b66863bdd9..3acd8fa25e347dc1bcd276ba036e9107ff5d06d9 100644 (file)
 #endif
 
 /*
- * This flag is used to indicate that the page pointed to by a pte
- * is dirty and requires cleaning before returning it to the user.
+ * This flag is used to indicate that the page pointed to by a pte is clean
+ * and does not require cleaning before returning it to the user.
  */
-#define PG_dcache_dirty PG_arch_1
+#define PG_dcache_clean PG_arch_1
 
 /*
  *     MM Cache Management
  *     Please note that the implementation of these, and the required
  *     effects are cache-type (VIVT/VIPT/PIPT) specific.
  *
+ *     flush_icache_all()
+ *
+ *             Unconditionally clean and invalidate the entire icache.
+ *             Currently only needed for cache-v6.S and cache-v7.S, see
+ *             __flush_icache_all for the generic implementation.
+ *
  *     flush_kern_all()
  *
  *             Unconditionally clean and invalidate the entire cache.
  */
 
 struct cpu_cache_fns {
+       void (*flush_icache_all)(void);
        void (*flush_kern_all)(void);
        void (*flush_user_all)(void);
        void (*flush_user_range)(unsigned long, unsigned long, unsigned int);
@@ -227,6 +234,7 @@ struct cpu_cache_fns {
 
 extern struct cpu_cache_fns cpu_cache;
 
+#define __cpuc_flush_icache_all                cpu_cache.flush_icache_all
 #define __cpuc_flush_kern_all          cpu_cache.flush_kern_all
 #define __cpuc_flush_user_all          cpu_cache.flush_user_all
 #define __cpuc_flush_user_range                cpu_cache.flush_user_range
@@ -246,6 +254,7 @@ extern struct cpu_cache_fns cpu_cache;
 
 #else
 
+#define __cpuc_flush_icache_all                __glue(_CACHE,_flush_icache_all)
 #define __cpuc_flush_kern_all          __glue(_CACHE,_flush_kern_cache_all)
 #define __cpuc_flush_user_all          __glue(_CACHE,_flush_user_cache_all)
 #define __cpuc_flush_user_range                __glue(_CACHE,_flush_user_cache_range)
@@ -253,6 +262,7 @@ extern struct cpu_cache_fns cpu_cache;
 #define __cpuc_coherent_user_range     __glue(_CACHE,_coherent_user_range)
 #define __cpuc_flush_dcache_area       __glue(_CACHE,_flush_kern_dcache_area)
 
+extern void __cpuc_flush_icache_all(void);
 extern void __cpuc_flush_kern_all(void);
 extern void __cpuc_flush_user_all(void);
 extern void __cpuc_flush_user_range(unsigned long, unsigned long, unsigned int);
@@ -291,6 +301,37 @@ extern void copy_to_user_page(struct vm_area_struct *, struct page *,
 /*
  * Convert calls to our calling convention.
  */
+
+/* Invalidate I-cache */
+#define __flush_icache_all_generic()                                   \
+       asm("mcr        p15, 0, %0, c7, c5, 0"                          \
+           : : "r" (0));
+
+/* Invalidate I-cache inner shareable */
+#define __flush_icache_all_v7_smp()                                    \
+       asm("mcr        p15, 0, %0, c7, c1, 0"                          \
+           : : "r" (0));
+
+/*
+ * Optimized __flush_icache_all for the common cases. Note that UP ARMv7
+ * will fall through to use __flush_icache_all_generic.
+ */
+#if (defined(CONFIG_CPU_V7) && defined(CONFIG_CPU_V6)) ||              \
+       defined(CONFIG_SMP_ON_UP)
+#define __flush_icache_preferred       __cpuc_flush_icache_all
+#elif __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)
+#define __flush_icache_preferred       __flush_icache_all_v7_smp
+#elif __LINUX_ARM_ARCH__ == 6 && defined(CONFIG_ARM_ERRATA_411920)
+#define __flush_icache_preferred       __cpuc_flush_icache_all
+#else
+#define __flush_icache_preferred       __flush_icache_all_generic
+#endif
+
+static inline void __flush_icache_all(void)
+{
+       __flush_icache_preferred();
+}
+
 #define flush_cache_all()              __cpuc_flush_kern_all()
 
 static inline void vivt_flush_cache_mm(struct mm_struct *mm)
@@ -366,21 +407,6 @@ extern void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
 extern void flush_dcache_page(struct page *);
 
-static inline void __flush_icache_all(void)
-{
-#ifdef CONFIG_ARM_ERRATA_411920
-       extern void v6_icache_inval_all(void);
-       v6_icache_inval_all();
-#elif defined(CONFIG_SMP) && __LINUX_ARM_ARCH__ >= 7
-       asm("mcr        p15, 0, %0, c7, c1, 0   @ invalidate I-cache inner shareable\n"
-           :
-           : "r" (0));
-#else
-       asm("mcr        p15, 0, %0, c7, c5, 0   @ invalidate I-cache\n"
-           :
-           : "r" (0));
-#endif
-}
 static inline void flush_kernel_vmap_range(void *addr, int size)
 {
        if ((cache_is_vivt() || cache_is_vipt_aliasing()))
@@ -405,9 +431,6 @@ static inline void flush_anon_page(struct vm_area_struct *vma,
 #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_area(page_address(page), PAGE_SIZE);
 }
 
 #define flush_dcache_mmap_lock(mapping) \
index d3a4c2cb9f2f662f5348175baa2a03995c66835d..c023db09fcc14ced27ec4bacaca40b44c48005ad 100644 (file)
@@ -6,6 +6,7 @@
 #define CACHEID_VIPT_ALIASING          (1 << 2)
 #define CACHEID_VIPT                   (CACHEID_VIPT_ALIASING|CACHEID_VIPT_NONALIASING)
 #define CACHEID_ASID_TAGGED            (1 << 3)
+#define CACHEID_VIPT_I_ALIASING                (1 << 4)
 
 extern unsigned int cacheid;
 
@@ -14,15 +15,18 @@ extern unsigned int cacheid;
 #define cache_is_vipt_nonaliasing()    cacheid_is(CACHEID_VIPT_NONALIASING)
 #define cache_is_vipt_aliasing()       cacheid_is(CACHEID_VIPT_ALIASING)
 #define icache_is_vivt_asid_tagged()   cacheid_is(CACHEID_ASID_TAGGED)
+#define icache_is_vipt_aliasing()      cacheid_is(CACHEID_VIPT_I_ALIASING)
 
 /*
  * __LINUX_ARM_ARCH__ is the minimum supported CPU architecture
  * Mask out support which will never be present on newer CPUs.
  * - v6+ is never VIVT
- * - v7+ VIPT never aliases
+ * - v7+ VIPT never aliases on D-side
  */
 #if __LINUX_ARM_ARCH__ >= 7
-#define __CACHEID_ARCH_MIN     (CACHEID_VIPT_NONALIASING | CACHEID_ASID_TAGGED)
+#define __CACHEID_ARCH_MIN     (CACHEID_VIPT_NONALIASING |\
+                                CACHEID_ASID_TAGGED |\
+                                CACHEID_VIPT_I_ALIASING)
 #elif __LINUX_ARM_ARCH__ >= 6
 #define        __CACHEID_ARCH_MIN      (~CACHEID_VIVT)
 #else
index 5747a8baa4135b44c25711197799255c9f5f61ff..8bb66bca2e3eb8a8561f2c63d9334e8991ebb728 100644 (file)
@@ -127,4 +127,8 @@ struct mm_struct;
 extern unsigned long arch_randomize_brk(struct mm_struct *mm);
 #define arch_randomize_brk arch_randomize_brk
 
+extern int vectors_user_mapping(void);
+#define arch_setup_additional_pages(bprm, uses_interp) vectors_user_mapping()
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
+
 #endif
index 103f7ee9731357fa7a8e19bb83416a1465c53cb4..f89515adac60ef579ad27cce19d827784ad59b36 100644 (file)
@@ -2,12 +2,30 @@
 #define _ASM_ARM_FTRACE
 
 #ifdef CONFIG_FUNCTION_TRACER
-#define MCOUNT_ADDR            ((long)(mcount))
+#define MCOUNT_ADDR            ((unsigned long)(__gnu_mcount_nc))
 #define MCOUNT_INSN_SIZE       4 /* sizeof mcount call */
 
 #ifndef __ASSEMBLY__
 extern void mcount(void);
 extern void __gnu_mcount_nc(void);
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+struct dyn_arch_ftrace {
+#ifdef CONFIG_OLD_MCOUNT
+       bool    old_mcount;
+#endif
+};
+
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+       /* With Thumb-2, the recorded addresses have the lsb set */
+       return addr & ~1;
+}
+
+extern void ftrace_caller_old(void);
+extern void ftrace_call_old(void);
+#endif
+
 #endif
 
 #endif
index 212e47828c791e44c16f93783cba17d10eadddff..7ecd793b8f5a94ebdbba19ee26ac9a75eaaa33d6 100644 (file)
 #define TRACER_RUNNING         BIT(TRACER_RUNNING_BIT)
 #define TRACER_CYCLE_ACC       BIT(TRACER_CYCLE_ACC_BIT)
 
-struct tracectx {
-       unsigned int    etb_bufsz;
-       void __iomem    *etb_regs;
-       void __iomem    *etm_regs;
-       unsigned long   flags;
-       int             ncmppairs;
-       int             etm_portsz;
-       struct device   *dev;
-       struct clk      *emu_clk;
-       struct mutex    mutex;
-};
-
 #define TRACER_TIMEOUT 10000
 
 #define etm_writel(t, v, x) \
@@ -112,10 +100,10 @@ struct tracectx {
 
 /* ETM status register, "ETM Architecture", 3.3.2 */
 #define ETMR_STATUS            (0x10)
-#define ETMST_OVERFLOW         (1 << 0)
-#define ETMST_PROGBIT          (1 << 1)
-#define ETMST_STARTSTOP                (1 << 2)
-#define ETMST_TRIGGER          (1 << 3)
+#define ETMST_OVERFLOW         BIT(0)
+#define ETMST_PROGBIT          BIT(1)
+#define ETMST_STARTSTOP                BIT(2)
+#define ETMST_TRIGGER          BIT(3)
 
 #define etm_progbit(t)         (etm_readl((t), ETMR_STATUS) & ETMST_PROGBIT)
 #define etm_started(t)         (etm_readl((t), ETMR_STATUS) & ETMST_STARTSTOP)
@@ -123,7 +111,7 @@ struct tracectx {
 
 #define ETMR_TRACEENCTRL2      0x1c
 #define ETMR_TRACEENCTRL       0x24
-#define ETMTE_INCLEXCL         (1 << 24)
+#define ETMTE_INCLEXCL         BIT(24)
 #define ETMR_TRACEENEVT                0x20
 #define ETMCTRL_OPTS           (ETMCTRL_DO_CPRT | \
                                ETMCTRL_DATA_DO_ADDR | \
@@ -146,12 +134,12 @@ struct tracectx {
 #define ETBR_CTRL              0x20
 #define ETBR_FORMATTERCTRL     0x304
 #define ETBFF_ENFTC            1
-#define ETBFF_ENFCONT          (1 << 1)
-#define ETBFF_FONFLIN          (1 << 4)
-#define ETBFF_MANUAL_FLUSH     (1 << 6)
-#define ETBFF_TRIGIN           (1 << 8)
-#define ETBFF_TRIGEVT          (1 << 9)
-#define ETBFF_TRIGFL           (1 << 10)
+#define ETBFF_ENFCONT          BIT(1)
+#define ETBFF_FONFLIN          BIT(4)
+#define ETBFF_MANUAL_FLUSH     BIT(6)
+#define ETBFF_TRIGIN           BIT(8)
+#define ETBFF_TRIGEVT          BIT(9)
+#define ETBFF_TRIGFL           BIT(10)
 
 #define etb_writel(t, v, x) \
        (__raw_writel((v), (t)->etb_regs + (x)))
diff --git a/arch/arm/include/asm/hw_breakpoint.h b/arch/arm/include/asm/hw_breakpoint.h
new file mode 100644 (file)
index 0000000..4d8ae9d
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef _ARM_HW_BREAKPOINT_H
+#define _ARM_HW_BREAKPOINT_H
+
+#ifdef __KERNEL__
+
+struct task_struct;
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+
+struct arch_hw_breakpoint_ctrl {
+               u32 __reserved  : 9,
+               mismatch        : 1,
+                               : 9,
+               len             : 8,
+               type            : 2,
+               privilege       : 2,
+               enabled         : 1;
+};
+
+struct arch_hw_breakpoint {
+       u32     address;
+       u32     trigger;
+       struct perf_event *suspended_wp;
+       struct arch_hw_breakpoint_ctrl ctrl;
+};
+
+static inline u32 encode_ctrl_reg(struct arch_hw_breakpoint_ctrl ctrl)
+{
+       return (ctrl.mismatch << 22) | (ctrl.len << 5) | (ctrl.type << 3) |
+               (ctrl.privilege << 1) | ctrl.enabled;
+}
+
+static inline void decode_ctrl_reg(u32 reg,
+                                  struct arch_hw_breakpoint_ctrl *ctrl)
+{
+       ctrl->enabled   = reg & 0x1;
+       reg >>= 1;
+       ctrl->privilege = reg & 0x3;
+       reg >>= 2;
+       ctrl->type      = reg & 0x3;
+       reg >>= 2;
+       ctrl->len       = reg & 0xff;
+       reg >>= 17;
+       ctrl->mismatch  = reg & 0x1;
+}
+
+/* Debug architecture numbers. */
+#define ARM_DEBUG_ARCH_RESERVED        0       /* In case of ptrace ABI updates. */
+#define ARM_DEBUG_ARCH_V6      1
+#define ARM_DEBUG_ARCH_V6_1    2
+#define ARM_DEBUG_ARCH_V7_ECP14        3
+#define ARM_DEBUG_ARCH_V7_MM   4
+
+/* Breakpoint */
+#define ARM_BREAKPOINT_EXECUTE 0
+
+/* Watchpoints */
+#define ARM_BREAKPOINT_LOAD    1
+#define ARM_BREAKPOINT_STORE   2
+
+/* Privilege Levels */
+#define ARM_BREAKPOINT_PRIV    1
+#define ARM_BREAKPOINT_USER    2
+
+/* Lengths */
+#define ARM_BREAKPOINT_LEN_1   0x1
+#define ARM_BREAKPOINT_LEN_2   0x3
+#define ARM_BREAKPOINT_LEN_4   0xf
+#define ARM_BREAKPOINT_LEN_8   0xff
+
+/* Limits */
+#define ARM_MAX_BRP            16
+#define ARM_MAX_WRP            16
+#define ARM_MAX_HBP_SLOTS      (ARM_MAX_BRP + ARM_MAX_WRP)
+
+/* DSCR method of entry bits. */
+#define ARM_DSCR_MOE(x)                        ((x >> 2) & 0xf)
+#define ARM_ENTRY_BREAKPOINT           0x1
+#define ARM_ENTRY_ASYNC_WATCHPOINT     0x2
+#define ARM_ENTRY_SYNC_WATCHPOINT      0xa
+
+/* DSCR monitor/halting bits. */
+#define ARM_DSCR_HDBGEN                (1 << 14)
+#define ARM_DSCR_MDBGEN                (1 << 15)
+
+/* opcode2 numbers for the co-processor instructions. */
+#define ARM_OP2_BVR            4
+#define ARM_OP2_BCR            5
+#define ARM_OP2_WVR            6
+#define ARM_OP2_WCR            7
+
+/* Base register numbers for the debug registers. */
+#define ARM_BASE_BVR           64
+#define ARM_BASE_BCR           80
+#define ARM_BASE_WVR           96
+#define ARM_BASE_WCR           112
+
+/* Accessor macros for the debug registers. */
+#define ARM_DBG_READ(M, OP2, VAL) do {\
+       asm volatile("mrc p14, 0, %0, c0," #M ", " #OP2 : "=r" (VAL));\
+} while (0)
+
+#define ARM_DBG_WRITE(M, OP2, VAL) do {\
+       asm volatile("mcr p14, 0, %0, c0," #M ", " #OP2 : : "r" (VAL));\
+} while (0)
+
+struct notifier_block;
+struct perf_event;
+struct pmu;
+
+extern struct pmu perf_ops_bp;
+extern int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
+                                 int *gen_len, int *gen_type);
+extern int arch_check_bp_in_kernelspace(struct perf_event *bp);
+extern int arch_validate_hwbkpt_settings(struct perf_event *bp);
+extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+                                          unsigned long val, void *data);
+
+extern u8 arch_get_debug_arch(void);
+extern u8 arch_get_max_wp_len(void);
+extern void clear_ptrace_hw_breakpoint(struct task_struct *tsk);
+
+int arch_install_hw_breakpoint(struct perf_event *bp);
+void arch_uninstall_hw_breakpoint(struct perf_event *bp);
+void hw_breakpoint_pmu_read(struct perf_event *bp);
+int hw_breakpoint_slots(int type);
+
+#else
+static inline void clear_ptrace_hw_breakpoint(struct task_struct *tsk) {}
+
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+#endif /* __KERNEL__ */
+#endif /* _ARM_HW_BREAKPOINT_H */
index 90831f6f5f5cb9b033097f895cfb5edc5dc8b7b6..5586b7c8ef6fd7b1f112890d07e87b03aa695257 100644 (file)
@@ -24,4 +24,6 @@ void set_irq_flags(unsigned int irq, unsigned int flags);
 #define IRQF_PROBE     (1 << 1)
 #define IRQF_NOAUTOEN  (1 << 2)
 
+#define ARCH_IRQ_INIT_FLAGS    (IRQ_NOREQUEST | IRQ_NOPROBE)
+
 #endif
index 1261b1f928d95a9ac1cf374148208415c4dc248d..815efa2d4e07b5087e31965a06fc05c1fdfd9fa0 100644 (file)
@@ -294,6 +294,7 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr);
 #define ARCH_HAS_VALID_PHYS_ADDR_RANGE
 extern int valid_phys_addr_range(unsigned long addr, size_t size);
 extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
+extern int devmem_is_allowed(unsigned long pfn);
 #endif
 
 /*
index 6d09974e66462c6801d869dafbf7d3e54b9c45d7..1e6cca55c750486b98ef85ca5a04c9af471d64ea 100644 (file)
  */
 #if __LINUX_ARM_ARCH__ >= 6
 
-#define raw_local_irq_save(x)                                  \
-       ({                                                      \
-       __asm__ __volatile__(                                   \
-       "mrs    %0, cpsr                @ local_irq_save\n"     \
-       "cpsid  i"                                              \
-       : "=r" (x) : : "memory", "cc");                         \
-       })
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags;
+
+       asm volatile(
+               "       mrs     %0, cpsr        @ arch_local_irq_save\n"
+               "       cpsid   i"
+               : "=r" (flags) : : "memory", "cc");
+       return flags;
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       asm volatile(
+               "       cpsie i                 @ arch_local_irq_enable"
+               :
+               :
+               : "memory", "cc");
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       asm volatile(
+               "       cpsid i                 @ arch_local_irq_disable"
+               :
+               :
+               : "memory", "cc");
+}
 
-#define raw_local_irq_enable()  __asm__("cpsie i       @ __sti" : : : "memory", "cc")
-#define raw_local_irq_disable() __asm__("cpsid i       @ __cli" : : : "memory", "cc")
 #define local_fiq_enable()  __asm__("cpsie f   @ __stf" : : : "memory", "cc")
 #define local_fiq_disable() __asm__("cpsid f   @ __clf" : : : "memory", "cc")
-
 #else
 
 /*
  * Save the current interrupt enable state & disable IRQs
  */
-#define raw_local_irq_save(x)                                  \
-       ({                                                      \
-               unsigned long temp;                             \
-               (void) (&temp == &x);                           \
-       __asm__ __volatile__(                                   \
-       "mrs    %0, cpsr                @ local_irq_save\n"     \
-"      orr     %1, %0, #128\n"                                 \
-"      msr     cpsr_c, %1"                                     \
-       : "=r" (x), "=r" (temp)                                 \
-       :                                                       \
-       : "memory", "cc");                                      \
-       })
-       
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags, temp;
+
+       asm volatile(
+               "       mrs     %0, cpsr        @ arch_local_irq_save\n"
+               "       orr     %1, %0, #128\n"
+               "       msr     cpsr_c, %1"
+               : "=r" (flags), "=r" (temp)
+               :
+               : "memory", "cc");
+       return flags;
+}
+
 /*
  * Enable IRQs
  */
-#define raw_local_irq_enable()                                 \
-       ({                                                      \
-               unsigned long temp;                             \
-       __asm__ __volatile__(                                   \
-       "mrs    %0, cpsr                @ local_irq_enable\n"   \
-"      bic     %0, %0, #128\n"                                 \
-"      msr     cpsr_c, %0"                                     \
-       : "=r" (temp)                                           \
-       :                                                       \
-       : "memory", "cc");                                      \
-       })
+static inline void arch_local_irq_enable(void)
+{
+       unsigned long temp;
+       asm volatile(
+               "       mrs     %0, cpsr        @ arch_local_irq_enable\n"
+               "       bic     %0, %0, #128\n"
+               "       msr     cpsr_c, %0"
+               : "=r" (temp)
+               :
+               : "memory", "cc");
+}
 
 /*
  * Disable IRQs
  */
-#define raw_local_irq_disable()                                        \
-       ({                                                      \
-               unsigned long temp;                             \
-       __asm__ __volatile__(                                   \
-       "mrs    %0, cpsr                @ local_irq_disable\n"  \
-"      orr     %0, %0, #128\n"                                 \
-"      msr     cpsr_c, %0"                                     \
-       : "=r" (temp)                                           \
-       :                                                       \
-       : "memory", "cc");                                      \
-       })
+static inline void arch_local_irq_disable(void)
+{
+       unsigned long temp;
+       asm volatile(
+               "       mrs     %0, cpsr        @ arch_local_irq_disable\n"
+               "       orr     %0, %0, #128\n"
+               "       msr     cpsr_c, %0"
+               : "=r" (temp)
+               :
+               : "memory", "cc");
+}
 
 /*
  * Enable FIQs
 /*
  * Save the current interrupt enable state.
  */
-#define raw_local_save_flags(x)                                        \
-       ({                                                      \
-       __asm__ __volatile__(                                   \
-       "mrs    %0, cpsr                @ local_save_flags"     \
-       : "=r" (x) : : "memory", "cc");                         \
-       })
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+       asm volatile(
+               "       mrs     %0, cpsr        @ local_save_flags"
+               : "=r" (flags) : : "memory", "cc");
+       return flags;
+}
 
 /*
  * restore saved IRQ & FIQ state
  */
-#define raw_local_irq_restore(x)                               \
-       __asm__ __volatile__(                                   \
-       "msr    cpsr_c, %0              @ local_irq_restore\n"  \
-       :                                                       \
-       : "r" (x)                                               \
-       : "memory", "cc")
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile(
+               "       msr     cpsr_c, %0      @ local_irq_restore"
+               :
+               : "r" (flags)
+               : "memory", "cc");
+}
 
-#define raw_irqs_disabled_flags(flags) \
-({                                     \
-       (int)((flags) & PSR_I_BIT);     \
-})
+static inline int arch_irqs_disabled_flags(unsigned long flags)
+{
+       return flags & PSR_I_BIT;
+}
 
 #endif
 #endif
index 8a0dd18ba6427301ed4b802739a390dec64d12c2..d97a964207fa15693c011f88f27dc64f4c7c3f16 100644 (file)
@@ -16,18 +16,15 @@ struct sys_timer;
 
 struct machine_desc {
        /*
-        * Note! The first four elements are used
+        * Note! The first two elements are used
         * by assembler code in head.S, head-common.S
         */
        unsigned int            nr;             /* architecture number  */
-       unsigned int            nr_irqs;        /* number of IRQs */
-       unsigned int            phys_io;        /* start of physical io */
-       unsigned int            io_pg_offst;    /* byte offset for io 
-                                                * page tabe entry      */
-
        const char              *name;          /* architecture name    */
        unsigned long           boot_params;    /* tagged list          */
 
+       unsigned int            nr_irqs;        /* number of IRQs */
+
        unsigned int            video_start;    /* start of video RAM   */
        unsigned int            video_end;      /* end of video RAM     */
 
index a0b3cac0547c0a9949c30cc919adcf5e08fcf500..71605d9f8e421ad36a058992c032ad5459114929 100644 (file)
@@ -18,7 +18,6 @@
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
 #include <asm/proc-fns.h>
-#include <asm-generic/mm_hooks.h>
 
 void __check_kvm_seq(struct mm_struct *mm);
 
@@ -134,4 +133,32 @@ switch_mm(struct mm_struct *prev, struct mm_struct *next,
 #define deactivate_mm(tsk,mm)  do { } while (0)
 #define activate_mm(prev,next) switch_mm(prev, next, NULL)
 
+/*
+ * We are inserting a "fake" vma for the user-accessible vector page so
+ * gdb and friends can get to it through ptrace and /proc/<pid>/mem.
+ * But we also want to remove it before the generic code gets to see it
+ * during process exit or the unmapping of it would  cause total havoc.
+ * (the macro is used as remove_vma() is static to mm/mmap.c)
+ */
+#define arch_exit_mmap(mm) \
+do { \
+       struct vm_area_struct *high_vma = find_vma(mm, 0xffff0000); \
+       if (high_vma) { \
+               BUG_ON(high_vma->vm_next);  /* it should be last */ \
+               if (high_vma->vm_prev) \
+                       high_vma->vm_prev->vm_next = NULL; \
+               else \
+                       mm->mmap = NULL; \
+               rb_erase(&high_vma->vm_rb, &mm->mm_rb); \
+               mm->mmap_cache = NULL; \
+               mm->map_count--; \
+               remove_vma(high_vma); \
+       } \
+} while (0)
+
+static inline void arch_dup_mmap(struct mm_struct *oldmm,
+                                struct mm_struct *mm)
+{
+}
+
 #endif
index e4dfa69abb68fa4868eaaacd2bdd67b83876704e..cbb0bc295d2b184d380e63920dcb55930c7b76b7 100644 (file)
@@ -7,20 +7,27 @@
 
 struct unwind_table;
 
-struct mod_arch_specific
-{
 #ifdef CONFIG_ARM_UNWIND
-       Elf_Shdr *unw_sec_init;
-       Elf_Shdr *unw_sec_devinit;
-       Elf_Shdr *unw_sec_core;
-       Elf_Shdr *sec_init_text;
-       Elf_Shdr *sec_devinit_text;
-       Elf_Shdr *sec_core_text;
-       struct unwind_table *unwind_init;
-       struct unwind_table *unwind_devinit;
-       struct unwind_table *unwind_core;
-#endif
+struct arm_unwind_mapping {
+       Elf_Shdr *unw_sec;
+       Elf_Shdr *sec_text;
+       struct unwind_table *unwind;
+};
+enum {
+       ARM_SEC_INIT,
+       ARM_SEC_DEVINIT,
+       ARM_SEC_CORE,
+       ARM_SEC_EXIT,
+       ARM_SEC_DEVEXIT,
+       ARM_SEC_MAX,
+};
+struct mod_arch_specific {
+       struct arm_unwind_mapping map[ARM_SEC_MAX];
 };
+#else
+struct mod_arch_specific {
+};
+#endif
 
 /*
  * Include the ARM architecture version.
index b5799a3b7117d5480eec6456008f79e01d1064ae..c4aa4e8c6af9cda0b7e88a46cbed94dc6e3b565d 100644 (file)
 #ifndef __ARM_PERF_EVENT_H__
 #define __ARM_PERF_EVENT_H__
 
-/*
- * NOP: on *most* (read: all supported) ARM platforms, the performance
- * counter interrupts are regular interrupts and not an NMI. This
- * means that when we receive the interrupt we can call
- * perf_event_do_pending() that handles all of the work with
- * interrupts disabled.
- */
-static inline void
-set_perf_event_pending(void)
-{
-}
-
 /* ARM performance counters start from 1 (in the cp15 accesses) so use the
  * same indexes here for consistency. */
 #define PERF_EVENT_INDEX_OFFSET 1
index e90b167ea8484002fffb0121e7a2d61726851fe6..a9672e8406a3cdb5efd45f69b0cbe10e47196ec2 100644 (file)
@@ -278,9 +278,24 @@ extern struct page *empty_zero_page;
 
 #define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
 
-#define set_pte_at(mm,addr,ptep,pteval) do { \
-       set_pte_ext(ptep, pteval, (addr) >= TASK_SIZE ? 0 : PTE_EXT_NG); \
- } while (0)
+#if __LINUX_ARM_ARCH__ < 6
+static inline void __sync_icache_dcache(pte_t pteval)
+{
+}
+#else
+extern void __sync_icache_dcache(pte_t pteval);
+#endif
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+                             pte_t *ptep, pte_t pteval)
+{
+       if (addr >= TASK_SIZE)
+               set_pte_ext(ptep, pteval, 0);
+       else {
+               __sync_icache_dcache(pteval);
+               set_pte_ext(ptep, pteval, PTE_EXT_NG);
+       }
+}
 
 /*
  * The following only work if pte_present() is true.
@@ -290,8 +305,13 @@ extern struct page *empty_zero_page;
 #define pte_write(pte)         (pte_val(pte) & L_PTE_WRITE)
 #define pte_dirty(pte)         (pte_val(pte) & L_PTE_DIRTY)
 #define pte_young(pte)         (pte_val(pte) & L_PTE_YOUNG)
+#define pte_exec(pte)          (pte_val(pte) & L_PTE_EXEC)
 #define pte_special(pte)       (0)
 
+#define pte_present_user(pte) \
+       ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
+        (L_PTE_PRESENT | L_PTE_USER))
+
 #define PTE_BIT_FUNC(fn,op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
 
index 7bed3daf83b8f27547ac608d574ffb00de8d1871..67357baaeeebd93417932c70ca0d370d17818f51 100644 (file)
@@ -19,6 +19,7 @@
 
 #ifdef __KERNEL__
 
+#include <asm/hw_breakpoint.h>
 #include <asm/ptrace.h>
 #include <asm/types.h>
 
@@ -41,6 +42,9 @@ struct debug_entry {
 struct debug_info {
        int                     nsaved;
        struct debug_entry      bp[2];
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+       struct perf_event       *hbp[ARM_MAX_HBP_SLOTS];
+#endif
 };
 
 struct thread_struct {
index 7ce15eb15f72992289c899b5fa05385300aa0c8e..783d50f326181c274facb3c2de3a91975a29ee7f 100644 (file)
@@ -29,6 +29,8 @@
 #define PTRACE_SETCRUNCHREGS   26
 #define PTRACE_GETVFPREGS      27
 #define PTRACE_SETVFPREGS      28
+#define PTRACE_GETHBPREGS      29
+#define PTRACE_SETHBPREGS      30
 
 /*
  * PSR bits
diff --git a/arch/arm/include/asm/seccomp.h b/arch/arm/include/asm/seccomp.h
new file mode 100644 (file)
index 0000000..52b156b
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _ASM_ARM_SECCOMP_H
+#define _ASM_ARM_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_rt_sigreturn
+
+#endif /* _ASM_ARM_SECCOMP_H */
diff --git a/arch/arm/include/asm/smp_mpidr.h b/arch/arm/include/asm/smp_mpidr.h
new file mode 100644 (file)
index 0000000..6a9307d
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef ASMARM_SMP_MIDR_H
+#define ASMARM_SMP_MIDR_H
+
+#define hard_smp_processor_id()                                                \
+       ({                                                              \
+               unsigned int cpunum;                                    \
+               __asm__("\n"                                            \
+                       "1:     mrc p15, 0, %0, c0, c0, 5\n"            \
+                       "       .pushsection \".alt.smp.init\", \"a\"\n"\
+                       "       .long   1b\n"                           \
+                       "       mov     %0, #0\n"                       \
+                       "       .popsection"                            \
+                       : "=r" (cpunum));                               \
+               cpunum &= 0x0F;                                         \
+       })
+
+#endif
index e6215305544aa9c63db768c53a7c194fe38c6747..f24c1b9e211dd180a6caf548260110a33f75b33c 100644 (file)
@@ -7,15 +7,40 @@
 
 #include <asm/cputype.h>
 
+/*
+ * Return true if we are running on a SMP platform
+ */
+static inline bool is_smp(void)
+{
+#ifndef CONFIG_SMP
+       return false;
+#elif defined(CONFIG_SMP_ON_UP)
+       extern unsigned int smp_on_up;
+       return !!smp_on_up;
+#else
+       return true;
+#endif
+}
+
 /* all SMP configurations have the extended CPUID registers */
 static inline int tlb_ops_need_broadcast(void)
 {
+       if (!is_smp())
+               return 0;
+
        return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 2;
 }
 
+#if !defined(CONFIG_SMP) || __LINUX_ARM_ARCH__ >= 7
+#define cache_ops_need_broadcast()     0
+#else
 static inline int cache_ops_need_broadcast(void)
 {
+       if (!is_smp())
+               return 0;
+
        return ((read_cpuid_ext(CPUID_EXT_MMFR3) >> 12) & 0xf) < 1;
 }
+#endif
 
 #endif
index 8ba1ccf82a0200283367db344ed79259f8d57c05..1120f18a6b17695e48c37a6b4d1d7e50d306e478 100644 (file)
@@ -85,6 +85,10 @@ void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
                                       struct pt_regs *),
                     int sig, int code, const char *name);
 
+void hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int,
+                                      struct pt_regs *),
+                    int sig, int code, const char *name);
+
 #define xchg(ptr,x) \
        ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
@@ -325,6 +329,8 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
 extern void disable_hlt(void);
 extern void enable_hlt(void);
 
+void cpu_idle_wait(void);
+
 #include <asm-generic/cmpxchg-local.h>
 
 #if __LINUX_ARM_ARCH__ < 6
index 763e29fa85300b23180221a0c832c71b71b3e382..7b5cc8dae06e6e99b1dfc18edf6cef748629f25f 100644 (file)
@@ -144,6 +144,7 @@ extern void vfp_flush_hwstate(struct thread_info *);
 #define TIF_MEMDIE             18      /* is terminating due to OOM killer */
 #define TIF_FREEZE             19
 #define TIF_RESTORE_SIGMASK    20
+#define TIF_SECCOMP            21
 
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
@@ -153,6 +154,7 @@ extern void vfp_flush_hwstate(struct thread_info *);
 #define _TIF_USING_IWMMXT      (1 << TIF_USING_IWMMXT)
 #define _TIF_FREEZE            (1 << TIF_FREEZE)
 #define _TIF_RESTORE_SIGMASK   (1 << TIF_RESTORE_SIGMASK)
+#define _TIF_SECCOMP           (1 << TIF_SECCOMP)
 
 /*
  * Change these and you break ASM code in entry-common.S
index 33b546ae72d49c82545271372a1972283f7ddb5b..ce7378ea15a2b30c3aea7ce22d0a793b8838d7c4 100644 (file)
 #undef _TLB
 #undef MULTI_TLB
 
+#ifdef CONFIG_SMP_ON_UP
+#define MULTI_TLB 1
+#endif
+
 #define v3_tlb_flags   (TLB_V3_FULL | TLB_V3_PAGE)
 
 #ifdef CONFIG_CPU_TLB_V3
 # define v6wbi_always_flags    (-1UL)
 #endif
 
-#ifdef CONFIG_SMP
-#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_V7_IS_BTB | \
+#define v7wbi_tlb_flags_smp    (TLB_WB | TLB_DCLEAN | TLB_V7_IS_BTB | \
                         TLB_V7_UIS_FULL | TLB_V7_UIS_PAGE | TLB_V7_UIS_ASID)
-#else
-#define v7wbi_tlb_flags (TLB_WB | TLB_DCLEAN | TLB_BTB | \
+#define v7wbi_tlb_flags_up     (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  v7wbi_tlb_flags
-# define v7wbi_always_flags    v7wbi_tlb_flags
+
+# ifdef CONFIG_SMP_ON_UP
+#  define v7wbi_possible_flags (v7wbi_tlb_flags_smp | v7wbi_tlb_flags_up)
+#  define v7wbi_always_flags   (v7wbi_tlb_flags_smp & v7wbi_tlb_flags_up)
+# elif defined(CONFIG_SMP)
+#  define v7wbi_possible_flags v7wbi_tlb_flags_smp
+#  define v7wbi_always_flags   v7wbi_tlb_flags_smp
+# else
+#  define v7wbi_possible_flags v7wbi_tlb_flags_up
+#  define v7wbi_always_flags   v7wbi_tlb_flags_up
+# endif
 # ifdef _TLB
 #  define MULTI_TLB 1
 # else
@@ -560,12 +570,20 @@ extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 #endif
 
 /*
- * if PG_dcache_dirty is set for the page, we need to ensure that any
+ * If PG_dcache_clean is not set for the page, we need to ensure that any
  * cache entries for the kernels virtual memory range are written
- * back to the page.
+ * back to the page. On ARMv6 and later, the cache coherency is handled via
+ * the set_pte_at() function.
  */
+#if __LINUX_ARM_ARCH__ < 6
 extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
        pte_t *ptep);
+#else
+static inline void update_mmu_cache(struct vm_area_struct *vma,
+                                   unsigned long addr, pte_t *ptep)
+{
+}
+#endif
 
 #endif
 
index 980b78e31328156925f361cf5f6a2deac14c1500..5b9b268f4fbb368ecc34942c6bebed1c421beaca 100644 (file)
@@ -42,6 +42,7 @@ obj-$(CONFIG_KGDB)            += kgdb.o
 obj-$(CONFIG_ARM_UNWIND)       += unwind.o
 obj-$(CONFIG_HAVE_TCM)         += tcm.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
+obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
 
 obj-$(CONFIG_CRUNCH)           += crunch.o crunch-bits.o
 AFLAGS_crunch-bits.o           := -Wa,-mcpu=ep9312
index 8214bfebfaca6625226f8b2dd041d978e5ddc25e..e5e1e5387678f7ff5d9df7811b4f902c2b385f41 100644 (file)
@@ -165,6 +165,8 @@ EXPORT_SYMBOL(_find_next_bit_be);
 #endif
 
 #ifdef CONFIG_FUNCTION_TRACER
+#ifdef CONFIG_OLD_MCOUNT
 EXPORT_SYMBOL(mcount);
+#endif
 EXPORT_SYMBOL(__gnu_mcount_nc);
 #endif
index 85f2a019f77bc93b17e0c55bf60693d18a8e2ffa..82da661721327c12744b58f3a7686e76f182cff3 100644 (file)
@@ -102,8 +102,6 @@ int main(void)
   DEFINE(SIZEOF_MACHINE_DESC,  sizeof(struct machine_desc));
   DEFINE(MACHINFO_TYPE,                offsetof(struct machine_desc, nr));
   DEFINE(MACHINFO_NAME,                offsetof(struct machine_desc, name));
-  DEFINE(MACHINFO_PHYSIO,      offsetof(struct machine_desc, phys_io));
-  DEFINE(MACHINFO_PGOFFIO,     offsetof(struct machine_desc, io_pg_offst));
   BLANK();
   DEFINE(PROC_INFO_SZ,         sizeof(struct proc_info_list));
   DEFINE(PROCINFO_INITFUNC,    offsetof(struct proc_info_list, __cpu_flush));
index a38b4879441d1715b42c4e7994f9f4d8e67b7fe4..a0f07521ca8a2dd1b5a3ffc375b6eaadc9f51131 100644 (file)
 #if defined(CONFIG_DEBUG_ICEDCC)
                @@ debug using ARM EmbeddedICE DCC channel
 
-#if defined(CONFIG_CPU_V6)
-
-               .macro  addruart, rx, tmp
+               .macro  addruart, rp, rv
                .endm
 
+#if defined(CONFIG_CPU_V6)
+
                .macro  senduart, rd, rx
                mcr     p14, 0, \rd, c0, c5, 0
                .endm
@@ -51,9 +51,6 @@
 
 #elif defined(CONFIG_CPU_V7)
 
-               .macro  addruart, rx, tmp
-               .endm
-
                .macro  senduart, rd, rx
                mcr     p14, 0, \rd, c0, c5, 0
                .endm
@@ -71,9 +68,6 @@ wait:         mrc     p14, 0, pc, c0, c1, 0
 
 #elif defined(CONFIG_CPU_XSCALE)
 
-               .macro  addruart, rx, tmp
-               .endm
-
                .macro  senduart, rd, rx
                mcr     p14, 0, \rd, c8, c0, 0
                .endm
@@ -98,9 +92,6 @@ wait:         mrc     p14, 0, pc, c0, c1, 0
 
 #else
 
-               .macro  addruart, rx, tmp
-               .endm
-
                .macro  senduart, rd, rx
                mcr     p14, 0, \rd, c1, c0, 0
                .endm
@@ -130,6 +121,22 @@ wait:              mrc     p14, 0, pc, c0, c1, 0
 #include <mach/debug-macro.S>
 #endif /* CONFIG_DEBUG_ICEDCC */
 
+#ifdef CONFIG_MMU
+               .macro  addruart_current, rx, tmp1, tmp2
+               addruart        \tmp1, \tmp2
+               mrc             p15, 0, \rx, c1, c0
+               tst             \rx, #1
+               moveq           \rx, \tmp1
+               movne           \rx, \tmp2
+               .endm
+
+#else /* !CONFIG_MMU */
+               .macro  addruart_current, rx, tmp1, tmp2
+               addruart        \rx, \tmp1
+               .endm
+
+#endif /* CONFIG_MMU */
+
 /*
  * Useful debugging routines
  */
@@ -164,7 +171,7 @@ ENDPROC(printhex2)
                .ltorg
 
 ENTRY(printascii)
-               addruart r3, r1
+               addruart_current r3, r1, r2
                b       2f
 1:             waituart r2, r3
                senduart r1, r3
@@ -180,7 +187,7 @@ ENTRY(printascii)
 ENDPROC(printascii)
 
 ENTRY(printch)
-               addruart r3, r1
+               addruart_current r3, r1, r2
                mov     r1, r0
                mov     r0, #0
                b       1b
index bb8e93a76407241042345c51273690f6cdc35578..c09e3573c5deb5795042eb1073f210472b0eadbc 100644 (file)
@@ -46,7 +46,8 @@
         * this macro assumes that irqstat (r6) and base (r5) are
         * preserved from get_irqnr_and_base above
         */
-       test_for_ipi r0, r6, r5, lr
+       ALT_SMP(test_for_ipi r0, r6, r5, lr)
+       ALT_UP_B(9997f)
        movne   r0, sp
        adrne   lr, BSYM(1b)
        bne     do_IPI
@@ -57,6 +58,7 @@
        adrne   lr, BSYM(1b)
        bne     do_local_timer
 #endif
+9997:
 #endif
 
        .endm
@@ -965,11 +967,8 @@ kuser_cmpxchg_fixup:
        beq     1b
        rsbs    r0, r3, #0
        /* beware -- each __kuser slot must be 8 instructions max */
-#ifdef CONFIG_SMP
-       b       __kuser_memory_barrier
-#else
-       usr_ret lr
-#endif
+       ALT_SMP(b       __kuser_memory_barrier)
+       ALT_UP(usr_ret  lr)
 
 #endif
 
index 7885722bdf4eff7115137ac46444c8d176f05b57..8bfa98757cd2f3fc9ef128011944a55fa7838ffd 100644 (file)
@@ -129,30 +129,58 @@ ENDPROC(ret_from_fork)
  * clobber the ip register.  This is OK because the ARM calling convention
  * allows it to be clobbered in subroutines and doesn't use it to hold
  * parameters.)
+ *
+ * When using dynamic ftrace, we patch out the mcount call by a "mov r0, r0"
+ * for the mcount case, and a "pop {lr}" for the __gnu_mcount_nc case (see
+ * arch/arm/kernel/ftrace.c).
  */
+
+#ifndef CONFIG_OLD_MCOUNT
+#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))
+#error Ftrace requires CONFIG_FRAME_POINTER=y with GCC older than 4.4.0.
+#endif
+#endif
+
 #ifdef CONFIG_DYNAMIC_FTRACE
-ENTRY(mcount)
+ENTRY(__gnu_mcount_nc)
+       mov     ip, lr
+       ldmia   sp!, {lr}
+       mov     pc, ip
+ENDPROC(__gnu_mcount_nc)
+
+ENTRY(ftrace_caller)
        stmdb   sp!, {r0-r3, lr}
        mov     r0, lr
        sub     r0, r0, #MCOUNT_INSN_SIZE
+       ldr     r1, [sp, #20]
 
-       .globl mcount_call
-mcount_call:
+       .global ftrace_call
+ftrace_call:
        bl      ftrace_stub
-       ldr     lr, [fp, #-4]                   @ restore lr
-       ldmia   sp!, {r0-r3, pc}
+       ldmia   sp!, {r0-r3, ip, lr}
+       mov     pc, ip
+ENDPROC(ftrace_caller)
 
-ENTRY(ftrace_caller)
+#ifdef CONFIG_OLD_MCOUNT
+ENTRY(mcount)
+       stmdb   sp!, {lr}
+       ldr     lr, [fp, #-4]
+       ldmia   sp!, {pc}
+ENDPROC(mcount)
+
+ENTRY(ftrace_caller_old)
        stmdb   sp!, {r0-r3, lr}
        ldr     r1, [fp, #-4]
        mov     r0, lr
        sub     r0, r0, #MCOUNT_INSN_SIZE
 
-       .globl ftrace_call
-ftrace_call:
+       .globl ftrace_call_old
+ftrace_call_old:
        bl      ftrace_stub
        ldr     lr, [fp, #-4]                   @ restore lr
        ldmia   sp!, {r0-r3, pc}
+ENDPROC(ftrace_caller_old)
+#endif
 
 #else
 
@@ -160,7 +188,7 @@ ENTRY(__gnu_mcount_nc)
        stmdb   sp!, {r0-r3, lr}
        ldr     r0, =ftrace_trace_function
        ldr     r2, [r0]
-       adr     r0, ftrace_stub
+       adr     r0, .Lftrace_stub
        cmp     r0, r2
        bne     gnu_trace
        ldmia   sp!, {r0-r3, ip, lr}
@@ -170,11 +198,19 @@ gnu_trace:
        ldr     r1, [sp, #20]                   @ lr of instrumented routine
        mov     r0, lr
        sub     r0, r0, #MCOUNT_INSN_SIZE
-       mov     lr, pc
+       adr     lr, BSYM(1f)
        mov     pc, r2
+1:
        ldmia   sp!, {r0-r3, ip, lr}
        mov     pc, ip
+ENDPROC(__gnu_mcount_nc)
 
+#ifdef CONFIG_OLD_MCOUNT
+/*
+ * This is under an ifdef in order to force link-time errors for people trying
+ * to build with !FRAME_POINTER with a GCC which doesn't use the new-style
+ * mcount.
+ */
 ENTRY(mcount)
        stmdb   sp!, {r0-r3, lr}
        ldr     r0, =ftrace_trace_function
@@ -193,12 +229,15 @@ trace:
        mov     pc, r2
        ldr     lr, [fp, #-4]                   @ restore lr
        ldmia   sp!, {r0-r3, pc}
+ENDPROC(mcount)
+#endif
 
 #endif /* CONFIG_DYNAMIC_FTRACE */
 
-       .globl ftrace_stub
-ftrace_stub:
+ENTRY(ftrace_stub)
+.Lftrace_stub:
        mov     pc, lr
+ENDPROC(ftrace_stub)
 
 #endif /* CONFIG_FUNCTION_TRACER */
 
@@ -295,7 +334,6 @@ ENTRY(vector_swi)
 
        get_thread_info tsk
        adr     tbl, sys_call_table             @ load syscall table pointer
-       ldr     ip, [tsk, #TI_FLAGS]            @ check for syscall tracing
 
 #if defined(CONFIG_OABI_COMPAT)
        /*
@@ -312,8 +350,20 @@ ENTRY(vector_swi)
        eor     scno, scno, #__NR_SYSCALL_BASE  @ check OS number
 #endif
 
+       ldr     r10, [tsk, #TI_FLAGS]           @ check for syscall tracing
        stmdb   sp!, {r4, r5}                   @ push fifth and sixth args
-       tst     ip, #_TIF_SYSCALL_TRACE         @ are we tracing syscalls?
+
+#ifdef CONFIG_SECCOMP
+       tst     r10, #_TIF_SECCOMP
+       beq     1f
+       mov     r0, scno
+       bl      __secure_computing      
+       add     r0, sp, #S_R0 + S_OFF           @ pointer to regs
+       ldmia   r0, {r0 - r3}                   @ have to reload r0 - r3
+1:
+#endif
+
+       tst     r10, #_TIF_SYSCALL_TRACE                @ are we tracing syscalls?
        bne     __sys_trace
 
        cmp     scno, #NR_syscalls              @ check upper syscall limit
index 33c7077174db118175a1818228b900f56226b45f..a48d512579880fcb7d6795603a367ec7c1133b3f 100644 (file)
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexander Shishkin");
 
+/*
+ * ETM tracer state
+ */
+struct tracectx {
+       unsigned int    etb_bufsz;
+       void __iomem    *etb_regs;
+       void __iomem    *etm_regs;
+       unsigned long   flags;
+       int             ncmppairs;
+       int             etm_portsz;
+       struct device   *dev;
+       struct clk      *emu_clk;
+       struct mutex    mutex;
+};
+
 static struct tracectx tracer;
 
 static inline bool trace_isrunning(struct tracectx *t)
index 0298286ad4ad5971302a6690c5046e66826bccb2..971ac8c36ea775ca58702cb0f17c18aba7b1c4a7 100644 (file)
  * Dynamic function tracing support.
  *
  * Copyright (C) 2008 Abhishek Sagar <sagar.abhishek@gmail.com>
+ * Copyright (C) 2010 Rabin Vincent <rabin@rab.in>
  *
  * For licencing details, see COPYING.
  *
  * Defines low-level handling of mcount calls when the kernel
  * is compiled with the -pg flag. When using dynamic ftrace, the
- * mcount call-sites get patched lazily with NOP till they are
- * enabled. All code mutation routines here take effect atomically.
+ * mcount call-sites get patched with NOP till they are enabled.
+ * All code mutation routines here are called under stop_machine().
  */
 
 #include <linux/ftrace.h>
+#include <linux/uaccess.h>
 
 #include <asm/cacheflush.h>
 #include <asm/ftrace.h>
 
-#define PC_OFFSET      8
-#define BL_OPCODE      0xeb000000
-#define BL_OFFSET_MASK 0x00ffffff
+#ifdef CONFIG_THUMB2_KERNEL
+#define        NOP             0xeb04f85d      /* pop.w {lr} */
+#else
+#define        NOP             0xe8bd4000      /* pop {lr} */
+#endif
 
-static unsigned long bl_insn;
-static const unsigned long NOP = 0xe1a00000; /* mov r0, r0 */
+#ifdef CONFIG_OLD_MCOUNT
+#define OLD_MCOUNT_ADDR        ((unsigned long) mcount)
+#define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old)
 
-unsigned char *ftrace_nop_replace(void)
+#define        OLD_NOP         0xe1a00000      /* mov r0, r0 */
+
+static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
 {
-       return (char *)&NOP;
+       return rec->arch.old_mcount ? OLD_NOP : NOP;
 }
 
+static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr)
+{
+       if (!rec->arch.old_mcount)
+               return addr;
+
+       if (addr == MCOUNT_ADDR)
+               addr = OLD_MCOUNT_ADDR;
+       else if (addr == FTRACE_ADDR)
+               addr = OLD_FTRACE_ADDR;
+
+       return addr;
+}
+#else
+static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
+{
+       return NOP;
+}
+
+static unsigned long adjust_address(struct dyn_ftrace *rec, unsigned long addr)
+{
+       return addr;
+}
+#endif
+
 /* construct a branch (BL) instruction to addr */
-unsigned char *ftrace_call_replace(unsigned long pc, unsigned long addr)
+#ifdef CONFIG_THUMB2_KERNEL
+static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
 {
+       unsigned long s, j1, j2, i1, i2, imm10, imm11;
+       unsigned long first, second;
        long offset;
 
-       offset = (long)addr - (long)(pc + PC_OFFSET);
+       offset = (long)addr - (long)(pc + 4);
+       if (offset < -16777216 || offset > 16777214) {
+               WARN_ON_ONCE(1);
+               return 0;
+       }
+
+       s       = (offset >> 24) & 0x1;
+       i1      = (offset >> 23) & 0x1;
+       i2      = (offset >> 22) & 0x1;
+       imm10   = (offset >> 12) & 0x3ff;
+       imm11   = (offset >>  1) & 0x7ff;
+
+       j1 = (!i1) ^ s;
+       j2 = (!i2) ^ s;
+
+       first = 0xf000 | (s << 10) | imm10;
+       second = 0xd000 | (j1 << 13) | (j2 << 11) | imm11;
+
+       return (second << 16) | first;
+}
+#else
+static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr)
+{
+       long offset;
+
+       offset = (long)addr - (long)(pc + 8);
        if (unlikely(offset < -33554432 || offset > 33554428)) {
                /* Can't generate branches that far (from ARM ARM). Ftrace
                 * doesn't generate branches outside of kernel text.
                 */
                WARN_ON_ONCE(1);
-               return NULL;
+               return 0;
        }
-       offset = (offset >> 2) & BL_OFFSET_MASK;
-       bl_insn = BL_OPCODE | offset;
-       return (unsigned char *)&bl_insn;
-}
 
-int ftrace_modify_code(unsigned long pc, unsigned char *old_code,
-                      unsigned char *new_code)
-{
-       unsigned long err = 0, replaced = 0, old, new;
+       offset = (offset >> 2) & 0x00ffffff;
 
-       old = *(unsigned long *)old_code;
-       new = *(unsigned long *)new_code;
+       return 0xeb000000 | offset;
+}
+#endif
 
-       __asm__ __volatile__ (
-               "1:  ldr    %1, [%2]  \n"
-               "    cmp    %1, %4    \n"
-               "2:  streq  %3, [%2]  \n"
-               "    cmpne  %1, %3    \n"
-               "    movne  %0, #2    \n"
-               "3:\n"
+static int ftrace_modify_code(unsigned long pc, unsigned long old,
+                             unsigned long new)
+{
+       unsigned long replaced;
 
-               ".pushsection .fixup, \"ax\"\n"
-               "4:  mov  %0, #1  \n"
-               "    b    3b      \n"
-               ".popsection\n"
+       if (probe_kernel_read(&replaced, (void *)pc, MCOUNT_INSN_SIZE))
+               return -EFAULT;
 
-               ".pushsection __ex_table, \"a\"\n"
-               "    .long 1b, 4b \n"
-               "    .long 2b, 4b \n"
-               ".popsection\n"
+       if (replaced != old)
+               return -EINVAL;
 
-               : "=r"(err), "=r"(replaced)
-               : "r"(pc), "r"(new), "r"(old), "0"(err), "1"(replaced)
-               : "memory");
+       if (probe_kernel_write((void *)pc, &new, MCOUNT_INSN_SIZE))
+               return -EPERM;
 
-       if (!err && (replaced == old))
-               flush_icache_range(pc, pc + MCOUNT_INSN_SIZE);
+       flush_icache_range(pc, pc + MCOUNT_INSN_SIZE);
 
-       return err;
+       return 0;
 }
 
 int ftrace_update_ftrace_func(ftrace_func_t func)
 {
-       int ret;
        unsigned long pc, old;
-       unsigned char *new;
+       unsigned long new;
+       int ret;
 
        pc = (unsigned long)&ftrace_call;
        memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE);
        new = ftrace_call_replace(pc, (unsigned long)func);
-       ret = ftrace_modify_code(pc, (unsigned char *)&old, new);
+
+       ret = ftrace_modify_code(pc, old, new);
+
+#ifdef CONFIG_OLD_MCOUNT
+       if (!ret) {
+               pc = (unsigned long)&ftrace_call_old;
+               memcpy(&old, &ftrace_call_old, MCOUNT_INSN_SIZE);
+               new = ftrace_call_replace(pc, (unsigned long)func);
+
+               ret = ftrace_modify_code(pc, old, new);
+       }
+#endif
+
+       return ret;
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+       unsigned long new, old;
+       unsigned long ip = rec->ip;
+
+       old = ftrace_nop_replace(rec);
+       new = ftrace_call_replace(ip, adjust_address(rec, addr));
+
+       return ftrace_modify_code(rec->ip, old, new);
+}
+
+int ftrace_make_nop(struct module *mod,
+                   struct dyn_ftrace *rec, unsigned long addr)
+{
+       unsigned long ip = rec->ip;
+       unsigned long old;
+       unsigned long new;
+       int ret;
+
+       old = ftrace_call_replace(ip, adjust_address(rec, addr));
+       new = ftrace_nop_replace(rec);
+       ret = ftrace_modify_code(ip, old, new);
+
+#ifdef CONFIG_OLD_MCOUNT
+       if (ret == -EINVAL && addr == MCOUNT_ADDR) {
+               rec->arch.old_mcount = true;
+
+               old = ftrace_call_replace(ip, adjust_address(rec, addr));
+               new = ftrace_nop_replace(rec);
+               ret = ftrace_modify_code(ip, old, new);
+       }
+#endif
+
        return ret;
 }
 
-/* run from ftrace_init with irqs disabled */
 int __init ftrace_dyn_arch_init(void *data)
 {
-       ftrace_mcount_set(data);
+       *(unsigned long *)data = 0;
+
        return 0;
 }
index b9505aa267c003a84b2101b1e66af809932f867e..bbecaac1e0135132dd7b208735fd18130030ec76 100644 (file)
 #define ATAG_CORE_SIZE ((2*4 + 3*4) >> 2)
 #define ATAG_CORE_SIZE_EMPTY ((2*4) >> 2)
 
-       .align  2
-       .type   __switch_data, %object
-__switch_data:
-       .long   __mmap_switched
-       .long   __data_loc                      @ r4
-       .long   _data                           @ r5
-       .long   __bss_start                     @ r6
-       .long   _end                            @ r7
-       .long   processor_id                    @ r4
-       .long   __machine_arch_type             @ r5
-       .long   __atags_pointer                 @ r6
-       .long   cr_alignment                    @ r7
-       .long   init_thread_union + THREAD_START_SP @ sp
-
-/*
- * The following fragment of code is executed with the MMU on in MMU mode,
- * and uses absolute addresses; this is not position independent.
- *
- *  r0  = cp#15 control register
- *  r1  = machine ID
- *  r2  = atags pointer
- *  r9  = processor ID
- */
-__mmap_switched:
-       adr     r3, __switch_data + 4
-
-       ldmia   r3!, {r4, r5, r6, r7}
-       cmp     r4, r5                          @ Copy data segment if needed
-1:     cmpne   r5, r6
-       ldrne   fp, [r4], #4
-       strne   fp, [r5], #4
-       bne     1b
-
-       mov     fp, #0                          @ Clear BSS (and zero fp)
-1:     cmp     r6, r7
-       strcc   fp, [r6],#4
-       bcc     1b
-
- ARM(  ldmia   r3, {r4, r5, r6, r7, sp})
- THUMB(        ldmia   r3, {r4, r5, r6, r7}    )
- THUMB(        ldr     sp, [r3, #16]           )
-       str     r9, [r4]                        @ Save processor ID
-       str     r1, [r5]                        @ Save machine type
-       str     r2, [r6]                        @ Save atags pointer
-       bic     r4, r0, #CR_A                   @ Clear 'A' bit
-       stmia   r7, {r0, r4}                    @ Save control register values
-       b       start_kernel
-ENDPROC(__mmap_switched)
-
 /*
  * Exception handling.  Something went wrong and we can't proceed.  We
  * ought to tell the user, but since we don't have any guarantee that
@@ -73,21 +24,7 @@ ENDPROC(__mmap_switched)
  * and hope for the best (useful if bootloader fails to pass a proper
  * machine ID for example).
  */
-__error_p:
-#ifdef CONFIG_DEBUG_LL
-       adr     r0, str_p1
-       bl      printascii
-       mov     r0, r9
-       bl      printhex8
-       adr     r0, str_p2
-       bl      printascii
-       b       __error
-str_p1:        .asciz  "\nError: unrecognized/unsupported processor variant (0x"
-str_p2:        .asciz  ").\n"
-       .align
-#endif
-ENDPROC(__error_p)
-
+       __HEAD
 __error_a:
 #ifdef CONFIG_DEBUG_LL
        mov     r4, r1                          @ preserve machine ID
@@ -97,7 +34,7 @@ __error_a:
        bl      printhex8
        adr     r0, str_a2
        bl      printascii
-       adr     r3, 4f
+       adr     r3, __lookup_machine_type_data
        ldmia   r3, {r4, r5, r6}                @ get machine desc list
        sub     r4, r3, r4                      @ get offset between virt&phys
        add     r5, r5, r4                      @ convert virt addresses to
@@ -125,78 +62,6 @@ str_a3:     .asciz  "\nPlease check your kernel config and/or bootloader.\n"
        .align
 #endif
 
-__error:
-#ifdef CONFIG_ARCH_RPC
-/*
- * Turn the screen red on a error - RiscPC only.
- */
-       mov     r0, #0x02000000
-       mov     r3, #0x11
-       orr     r3, r3, r3, lsl #8
-       orr     r3, r3, r3, lsl #16
-       str     r3, [r0], #4
-       str     r3, [r0], #4
-       str     r3, [r0], #4
-       str     r3, [r0], #4
-#endif
-1:     mov     r0, r0
-       b       1b
-ENDPROC(__error)
-
-
-/*
- * Read processor ID register (CP#15, CR0), and look up in the linker-built
- * supported processor list.  Note that we can't use the absolute addresses
- * for the __proc_info lists since we aren't running with the MMU on
- * (and therefore, we are not in the correct address space).  We have to
- * calculate the offset.
- *
- *     r9 = cpuid
- * Returns:
- *     r3, r4, r6 corrupted
- *     r5 = proc_info pointer in physical address space
- *     r9 = cpuid (preserved)
- */
-__lookup_processor_type:
-       adr     r3, 3f
-       ldmia   r3, {r5 - r7}
-       add     r3, r3, #8
-       sub     r3, r3, r7                      @ get offset between virt&phys
-       add     r5, r5, r3                      @ convert virt addresses to
-       add     r6, r6, r3                      @ physical address space
-1:     ldmia   r5, {r3, r4}                    @ value, mask
-       and     r4, r4, r9                      @ mask wanted bits
-       teq     r3, r4
-       beq     2f
-       add     r5, r5, #PROC_INFO_SZ           @ sizeof(proc_info_list)
-       cmp     r5, r6
-       blo     1b
-       mov     r5, #0                          @ unknown processor
-2:     mov     pc, lr
-ENDPROC(__lookup_processor_type)
-
-/*
- * This provides a C-API version of the above function.
- */
-ENTRY(lookup_processor_type)
-       stmfd   sp!, {r4 - r7, r9, lr}
-       mov     r9, r0
-       bl      __lookup_processor_type
-       mov     r0, r5
-       ldmfd   sp!, {r4 - r7, r9, pc}
-ENDPROC(lookup_processor_type)
-
-/*
- * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
- * more information about the __proc_info and __arch_info structures.
- */
-       .align  2
-3:     .long   __proc_info_begin
-       .long   __proc_info_end
-4:     .long   .
-       .long   __arch_info_begin
-       .long   __arch_info_end
-
 /*
  * Lookup machine architecture in the linker-build list of architectures.
  * Note that we can't use the absolute addresses for the __arch_info
@@ -209,7 +74,7 @@ ENDPROC(lookup_processor_type)
  *  r5 = mach_info pointer in physical address space
  */
 __lookup_machine_type:
-       adr     r3, 4b
+       adr     r3, __lookup_machine_type_data
        ldmia   r3, {r4, r5, r6}
        sub     r3, r3, r4                      @ get offset between virt&phys
        add     r5, r5, r3                      @ convert virt addresses to
@@ -225,15 +90,16 @@ __lookup_machine_type:
 ENDPROC(__lookup_machine_type)
 
 /*
- * This provides a C-API version of the above function.
+ * Look in arch/arm/kernel/arch.[ch] for information about the
+ * __arch_info structures.
  */
-ENTRY(lookup_machine_type)
-       stmfd   sp!, {r4 - r6, lr}
-       mov     r1, r0
-       bl      __lookup_machine_type
-       mov     r0, r5
-       ldmfd   sp!, {r4 - r6, pc}
-ENDPROC(lookup_machine_type)
+       .align  2
+       .type   __lookup_machine_type_data, %object
+__lookup_machine_type_data:
+       .long   .
+       .long   __arch_info_begin
+       .long   __arch_info_end
+       .size   __lookup_machine_type_data, . - __lookup_machine_type_data
 
 /* Determine validity of the r2 atags pointer.  The heuristic requires
  * that the pointer be aligned, in the first 16k of physical RAM and
@@ -265,3 +131,150 @@ __vet_atags:
 1:     mov     r2, #0
        mov     pc, lr
 ENDPROC(__vet_atags)
+
+/*
+ * The following fragment of code is executed with the MMU on in MMU mode,
+ * and uses absolute addresses; this is not position independent.
+ *
+ *  r0  = cp#15 control register
+ *  r1  = machine ID
+ *  r2  = atags pointer
+ *  r9  = processor ID
+ */
+       __INIT
+__mmap_switched:
+       adr     r3, __mmap_switched_data
+
+       ldmia   r3!, {r4, r5, r6, r7}
+       cmp     r4, r5                          @ Copy data segment if needed
+1:     cmpne   r5, r6
+       ldrne   fp, [r4], #4
+       strne   fp, [r5], #4
+       bne     1b
+
+       mov     fp, #0                          @ Clear BSS (and zero fp)
+1:     cmp     r6, r7
+       strcc   fp, [r6],#4
+       bcc     1b
+
+ ARM(  ldmia   r3, {r4, r5, r6, r7, sp})
+ THUMB(        ldmia   r3, {r4, r5, r6, r7}    )
+ THUMB(        ldr     sp, [r3, #16]           )
+       str     r9, [r4]                        @ Save processor ID
+       str     r1, [r5]                        @ Save machine type
+       str     r2, [r6]                        @ Save atags pointer
+       bic     r4, r0, #CR_A                   @ Clear 'A' bit
+       stmia   r7, {r0, r4}                    @ Save control register values
+       b       start_kernel
+ENDPROC(__mmap_switched)
+
+       .align  2
+       .type   __mmap_switched_data, %object
+__mmap_switched_data:
+       .long   __data_loc                      @ r4
+       .long   _sdata                          @ r5
+       .long   __bss_start                     @ r6
+       .long   _end                            @ r7
+       .long   processor_id                    @ r4
+       .long   __machine_arch_type             @ r5
+       .long   __atags_pointer                 @ r6
+       .long   cr_alignment                    @ r7
+       .long   init_thread_union + THREAD_START_SP @ sp
+       .size   __mmap_switched_data, . - __mmap_switched_data
+
+/*
+ * This provides a C-API version of __lookup_machine_type
+ */
+ENTRY(lookup_machine_type)
+       stmfd   sp!, {r4 - r6, lr}
+       mov     r1, r0
+       bl      __lookup_machine_type
+       mov     r0, r5
+       ldmfd   sp!, {r4 - r6, pc}
+ENDPROC(lookup_machine_type)
+
+/*
+ * This provides a C-API version of __lookup_processor_type
+ */
+ENTRY(lookup_processor_type)
+       stmfd   sp!, {r4 - r6, r9, lr}
+       mov     r9, r0
+       bl      __lookup_processor_type
+       mov     r0, r5
+       ldmfd   sp!, {r4 - r6, r9, pc}
+ENDPROC(lookup_processor_type)
+
+/*
+ * Read processor ID register (CP#15, CR0), and look up in the linker-built
+ * supported processor list.  Note that we can't use the absolute addresses
+ * for the __proc_info lists since we aren't running with the MMU on
+ * (and therefore, we are not in the correct address space).  We have to
+ * calculate the offset.
+ *
+ *     r9 = cpuid
+ * Returns:
+ *     r3, r4, r6 corrupted
+ *     r5 = proc_info pointer in physical address space
+ *     r9 = cpuid (preserved)
+ */
+       __CPUINIT
+__lookup_processor_type:
+       adr     r3, __lookup_processor_type_data
+       ldmia   r3, {r4 - r6}
+       sub     r3, r3, r4                      @ get offset between virt&phys
+       add     r5, r5, r3                      @ convert virt addresses to
+       add     r6, r6, r3                      @ physical address space
+1:     ldmia   r5, {r3, r4}                    @ value, mask
+       and     r4, r4, r9                      @ mask wanted bits
+       teq     r3, r4
+       beq     2f
+       add     r5, r5, #PROC_INFO_SZ           @ sizeof(proc_info_list)
+       cmp     r5, r6
+       blo     1b
+       mov     r5, #0                          @ unknown processor
+2:     mov     pc, lr
+ENDPROC(__lookup_processor_type)
+
+/*
+ * Look in <asm/procinfo.h> for information about the __proc_info structure.
+ */
+       .align  2
+       .type   __lookup_processor_type_data, %object
+__lookup_processor_type_data:
+       .long   .
+       .long   __proc_info_begin
+       .long   __proc_info_end
+       .size   __lookup_processor_type_data, . - __lookup_processor_type_data
+
+__error_p:
+#ifdef CONFIG_DEBUG_LL
+       adr     r0, str_p1
+       bl      printascii
+       mov     r0, r9
+       bl      printhex8
+       adr     r0, str_p2
+       bl      printascii
+       b       __error
+str_p1:        .asciz  "\nError: unrecognized/unsupported processor variant (0x"
+str_p2:        .asciz  ").\n"
+       .align
+#endif
+ENDPROC(__error_p)
+
+__error:
+#ifdef CONFIG_ARCH_RPC
+/*
+ * Turn the screen red on a error - RiscPC only.
+ */
+       mov     r0, #0x02000000
+       mov     r3, #0x11
+       orr     r3, r3, r3, lsl #8
+       orr     r3, r3, r3, lsl #16
+       str     r3, [r0], #4
+       str     r3, [r0], #4
+       str     r3, [r0], #4
+       str     r3, [r0], #4
+#endif
+1:     mov     r0, r0
+       b       1b
+ENDPROC(__error)
index 573b803dc6bf667e49270f3873119c453e1c50d7..814ce1a732706d0cdb24f5e49007530715ba0b0a 100644 (file)
@@ -48,8 +48,6 @@ ENTRY(stext)
        movs    r8, r5                          @ invalid machine (r5=0)?
        beq     __error_a                       @ yes, error 'a'
 
-       ldr     r13, __switch_data              @ address to jump to after
-                                               @ the initialization is done
        adr     lr, BSYM(__after_proc_init)     @ return (PIC) address
  ARM(  add     pc, r10, #PROCINFO_INITFUNC     )
  THUMB(        add     r12, r10, #PROCINFO_INITFUNC    )
@@ -87,8 +85,7 @@ __after_proc_init:
        mcr     p15, 0, r0, c1, c0, 0           @ write control reg
 #endif /* CONFIG_CPU_CP15 */
 
-       mov     r3, r13
-       mov     pc, r3                          @ clear the BSS and jump
+       b       __mmap_switched                 @ clear the BSS and jump
                                                @ to start_kernel
 ENDPROC(__after_proc_init)
        .ltorg
index eb62bf947212ababff5175d10d784dc4f465273f..dd6b369ac69cae5c86dca1e30edd4574b80a2052 100644 (file)
 #include <asm/thread_info.h>
 #include <asm/system.h>
 
+#ifdef CONFIG_DEBUG_LL
+#include <mach/debug-macro.S>
+#endif
+
 #if (PHYS_OFFSET & 0x001fffff)
 #error "PHYS_OFFSET must be at an even 2MiB boundary!"
 #endif
@@ -86,6 +90,9 @@ ENTRY(stext)
        movs    r8, r5                          @ invalid machine (r5=0)?
        beq     __error_a                       @ yes, error 'a'
        bl      __vet_atags
+#ifdef CONFIG_SMP_ON_UP
+       bl      __fixup_smp
+#endif
        bl      __create_page_tables
 
        /*
@@ -95,113 +102,15 @@ ENTRY(stext)
         * above.  On return, the CPU will be ready for the MMU to be
         * turned on, and r0 will hold the CPU control register value.
         */
-       ldr     r13, __switch_data              @ address to jump to after
+       ldr     r13, =__mmap_switched           @ address to jump to after
                                                @ mmu has been enabled
-       adr     lr, BSYM(__enable_mmu)          @ return (PIC) address
+       adr     lr, BSYM(1f)                    @ return (PIC) address
  ARM(  add     pc, r10, #PROCINFO_INITFUNC     )
  THUMB(        add     r12, r10, #PROCINFO_INITFUNC    )
  THUMB(        mov     pc, r12                         )
+1:     b       __enable_mmu
 ENDPROC(stext)
-
-#if defined(CONFIG_SMP)
-ENTRY(secondary_startup)
-       /*
-        * Common entry point for secondary CPUs.
-        *
-        * Ensure that we're in SVC mode, and IRQs are disabled.  Lookup
-        * the processor type - there is no need to check the machine type
-        * as it has already been validated by the primary processor.
-        */
-       setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
-       mrc     p15, 0, r9, c0, c0              @ get processor id
-       bl      __lookup_processor_type
-       movs    r10, r5                         @ invalid processor?
-       moveq   r0, #'p'                        @ yes, error 'p'
-       beq     __error
-
-       /*
-        * Use the page tables supplied from  __cpu_up.
-        */
-       adr     r4, __secondary_data
-       ldmia   r4, {r5, r7, r12}               @ address to jump to after
-       sub     r4, r4, r5                      @ mmu has been enabled
-       ldr     r4, [r7, r4]                    @ get secondary_data.pgdir
-       adr     lr, BSYM(__enable_mmu)          @ return address
-       mov     r13, r12                        @ __secondary_switched address
- ARM(  add     pc, r10, #PROCINFO_INITFUNC     ) @ initialise processor
-                                                 @ (return control reg)
- THUMB(        add     r12, r10, #PROCINFO_INITFUNC    )
- THUMB(        mov     pc, r12                         )
-ENDPROC(secondary_startup)
-
-       /*
-        * r6  = &secondary_data
-        */
-ENTRY(__secondary_switched)
-       ldr     sp, [r7, #4]                    @ get secondary_data.stack
-       mov     fp, #0
-       b       secondary_start_kernel
-ENDPROC(__secondary_switched)
-
-       .type   __secondary_data, %object
-__secondary_data:
-       .long   .
-       .long   secondary_data
-       .long   __secondary_switched
-#endif /* defined(CONFIG_SMP) */
-
-
-
-/*
- * Setup common bits before finally enabling the MMU.  Essentially
- * this is just loading the page table pointer and domain access
- * registers.
- */
-__enable_mmu:
-#ifdef CONFIG_ALIGNMENT_TRAP
-       orr     r0, r0, #CR_A
-#else
-       bic     r0, r0, #CR_A
-#endif
-#ifdef CONFIG_CPU_DCACHE_DISABLE
-       bic     r0, r0, #CR_C
-#endif
-#ifdef CONFIG_CPU_BPREDICT_DISABLE
-       bic     r0, r0, #CR_Z
-#endif
-#ifdef CONFIG_CPU_ICACHE_DISABLE
-       bic     r0, r0, #CR_I
-#endif
-       mov     r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
-                     domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
-                     domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
-                     domain_val(DOMAIN_IO, DOMAIN_CLIENT))
-       mcr     p15, 0, r5, c3, c0, 0           @ load domain access register
-       mcr     p15, 0, r4, c2, c0, 0           @ load page table pointer
-       b       __turn_mmu_on
-ENDPROC(__enable_mmu)
-
-/*
- * Enable the MMU.  This completely changes the structure of the visible
- * memory space.  You will not be able to trace execution through this.
- * If you have an enquiry about this, *please* check the linux-arm-kernel
- * mailing list archives BEFORE sending another post to the list.
- *
- *  r0  = cp#15 control register
- *  r13 = *virtual* address to jump to upon completion
- *
- * other registers depend on the function called upon completion
- */
-       .align  5
-__turn_mmu_on:
-       mov     r0, r0
-       mcr     p15, 0, r0, c1, c0, 0           @ write control reg
-       mrc     p15, 0, r3, c0, c0, 0           @ read id reg
-       mov     r3, r3
-       mov     r3, r13
-       mov     pc, r3
-ENDPROC(__turn_mmu_on)
-
+       .ltorg
 
 /*
  * Setup the initial page tables.  We only setup the barest
@@ -213,7 +122,7 @@ ENDPROC(__turn_mmu_on)
  * r10 = procinfo
  *
  * Returns:
- *  r0, r3, r6, r7 corrupted
+ *  r0, r3, r5-r7 corrupted
  *  r4 = physical page table address
  */
 __create_page_tables:
@@ -235,20 +144,30 @@ __create_page_tables:
        ldr     r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags
 
        /*
-        * Create identity mapping for first MB of kernel to
-        * cater for the MMU enable.  This identity mapping
-        * will be removed by paging_init().  We use our current program
-        * counter to determine corresponding section base address.
+        * Create identity mapping to cater for __enable_mmu.
+        * This identity mapping will be removed by paging_init().
         */
-       mov     r6, pc
-       mov     r6, r6, lsr #20                 @ start of kernel section
-       orr     r3, r7, r6, lsl #20             @ flags + kernel base
-       str     r3, [r4, r6, lsl #2]            @ identity mapping
+       adr     r0, __enable_mmu_loc
+       ldmia   r0, {r3, r5, r6}
+       sub     r0, r0, r3                      @ virt->phys offset
+       add     r5, r5, r0                      @ phys __enable_mmu
+       add     r6, r6, r0                      @ phys __enable_mmu_end
+       mov     r5, r5, lsr #20
+       mov     r6, r6, lsr #20
+
+1:     orr     r3, r7, r5, lsl #20             @ flags + kernel base
+       str     r3, [r4, r5, lsl #2]            @ identity mapping
+       teq     r5, r6
+       addne   r5, r5, #1                      @ next section
+       bne     1b
 
        /*
         * Now setup the pagetables for our kernel direct
         * mapped region.
         */
+       mov     r3, pc
+       mov     r3, r3, lsr #20
+       orr     r3, r7, r3, lsl #20
        add     r0, r4,  #(KERNEL_START & 0xff000000) >> 18
        str     r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
        ldr     r6, =(KERNEL_END - 1)
@@ -289,24 +208,35 @@ __create_page_tables:
        str     r6, [r0]
 
 #ifdef CONFIG_DEBUG_LL
-       ldr     r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
+#ifndef CONFIG_DEBUG_ICEDCC
        /*
         * Map in IO space for serial debugging.
         * This allows debug messages to be output
         * via a serial console before paging_init.
         */
-       ldr     r3, [r8, #MACHINFO_PGOFFIO]
+       addruart r7, r3
+
+       mov     r3, r3, lsr #20
+       mov     r3, r3, lsl #2
+
        add     r0, r4, r3
        rsb     r3, r3, #0x4000                 @ PTRS_PER_PGD*sizeof(long)
        cmp     r3, #0x0800                     @ limit to 512MB
        movhi   r3, #0x0800
        add     r6, r0, r3
-       ldr     r3, [r8, #MACHINFO_PHYSIO]
-       orr     r3, r3, r7
+       mov     r3, r7, lsr #20
+       ldr     r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
+       orr     r3, r7, r3, lsl #20
 1:     str     r3, [r0], #4
        add     r3, r3, #1 << 20
        teq     r0, r6
        bne     1b
+
+#else /* CONFIG_DEBUG_ICEDCC */
+       /* we don't need any serial debugging mappings for ICEDCC */
+       ldr     r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
+#endif /* !CONFIG_DEBUG_ICEDCC */
+
 #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
        /*
         * If we're using the NetWinder or CATS, we also need to map
@@ -332,5 +262,168 @@ __create_page_tables:
        mov     pc, lr
 ENDPROC(__create_page_tables)
        .ltorg
+__enable_mmu_loc:
+       .long   .
+       .long   __enable_mmu
+       .long   __enable_mmu_end
+
+#if defined(CONFIG_SMP)
+       __CPUINIT
+ENTRY(secondary_startup)
+       /*
+        * Common entry point for secondary CPUs.
+        *
+        * Ensure that we're in SVC mode, and IRQs are disabled.  Lookup
+        * the processor type - there is no need to check the machine type
+        * as it has already been validated by the primary processor.
+        */
+       setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9
+       mrc     p15, 0, r9, c0, c0              @ get processor id
+       bl      __lookup_processor_type
+       movs    r10, r5                         @ invalid processor?
+       moveq   r0, #'p'                        @ yes, error 'p'
+       beq     __error_p
+
+       /*
+        * Use the page tables supplied from  __cpu_up.
+        */
+       adr     r4, __secondary_data
+       ldmia   r4, {r5, r7, r12}               @ address to jump to after
+       sub     r4, r4, r5                      @ mmu has been enabled
+       ldr     r4, [r7, r4]                    @ get secondary_data.pgdir
+       adr     lr, BSYM(__enable_mmu)          @ return address
+       mov     r13, r12                        @ __secondary_switched address
+ ARM(  add     pc, r10, #PROCINFO_INITFUNC     ) @ initialise processor
+                                                 @ (return control reg)
+ THUMB(        add     r12, r10, #PROCINFO_INITFUNC    )
+ THUMB(        mov     pc, r12                         )
+ENDPROC(secondary_startup)
+
+       /*
+        * r6  = &secondary_data
+        */
+ENTRY(__secondary_switched)
+       ldr     sp, [r7, #4]                    @ get secondary_data.stack
+       mov     fp, #0
+       b       secondary_start_kernel
+ENDPROC(__secondary_switched)
+
+       .type   __secondary_data, %object
+__secondary_data:
+       .long   .
+       .long   secondary_data
+       .long   __secondary_switched
+#endif /* defined(CONFIG_SMP) */
+
+
+
+/*
+ * Setup common bits before finally enabling the MMU.  Essentially
+ * this is just loading the page table pointer and domain access
+ * registers.
+ *
+ *  r0  = cp#15 control register
+ *  r1  = machine ID
+ *  r2  = atags pointer
+ *  r4  = page table pointer
+ *  r9  = processor ID
+ *  r13 = *virtual* address to jump to upon completion
+ */
+__enable_mmu:
+#ifdef CONFIG_ALIGNMENT_TRAP
+       orr     r0, r0, #CR_A
+#else
+       bic     r0, r0, #CR_A
+#endif
+#ifdef CONFIG_CPU_DCACHE_DISABLE
+       bic     r0, r0, #CR_C
+#endif
+#ifdef CONFIG_CPU_BPREDICT_DISABLE
+       bic     r0, r0, #CR_Z
+#endif
+#ifdef CONFIG_CPU_ICACHE_DISABLE
+       bic     r0, r0, #CR_I
+#endif
+       mov     r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
+                     domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
+                     domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
+                     domain_val(DOMAIN_IO, DOMAIN_CLIENT))
+       mcr     p15, 0, r5, c3, c0, 0           @ load domain access register
+       mcr     p15, 0, r4, c2, c0, 0           @ load page table pointer
+       b       __turn_mmu_on
+ENDPROC(__enable_mmu)
+
+/*
+ * Enable the MMU.  This completely changes the structure of the visible
+ * memory space.  You will not be able to trace execution through this.
+ * If you have an enquiry about this, *please* check the linux-arm-kernel
+ * mailing list archives BEFORE sending another post to the list.
+ *
+ *  r0  = cp#15 control register
+ *  r1  = machine ID
+ *  r2  = atags pointer
+ *  r9  = processor ID
+ *  r13 = *virtual* address to jump to upon completion
+ *
+ * other registers depend on the function called upon completion
+ */
+       .align  5
+__turn_mmu_on:
+       mov     r0, r0
+       mcr     p15, 0, r0, c1, c0, 0           @ write control reg
+       mrc     p15, 0, r3, c0, c0, 0           @ read id reg
+       mov     r3, r3
+       mov     r3, r13
+       mov     pc, r3
+__enable_mmu_end:
+ENDPROC(__turn_mmu_on)
+
+
+#ifdef CONFIG_SMP_ON_UP
+__fixup_smp:
+       mov     r7, #0x00070000
+       orr     r6, r7, #0xff000000     @ mask 0xff070000
+       orr     r7, r7, #0x41000000     @ val 0x41070000
+       and     r0, r9, r6
+       teq     r0, r7                  @ ARM CPU and ARMv6/v7?
+       bne     __fixup_smp_on_up       @ no, assume UP
+
+       orr     r6, r6, #0x0000ff00
+       orr     r6, r6, #0x000000f0     @ mask 0xff07fff0
+       orr     r7, r7, #0x0000b000
+       orr     r7, r7, #0x00000020     @ val 0x4107b020
+       and     r0, r9, r6
+       teq     r0, r7                  @ ARM 11MPCore?
+       moveq   pc, lr                  @ yes, assume SMP
+
+       mrc     p15, 0, r0, c0, c0, 5   @ read MPIDR
+       tst     r0, #1 << 31
+       movne   pc, lr                  @ bit 31 => SMP
+
+__fixup_smp_on_up:
+       adr     r0, 1f
+       ldmia   r0, {r3, r6, r7}
+       sub     r3, r0, r3
+       add     r6, r6, r3
+       add     r7, r7, r3
+2:     cmp     r6, r7
+       ldmia   r6!, {r0, r4}
+       strlo   r4, [r0, r3]
+       blo     2b
+       mov     pc, lr
+ENDPROC(__fixup_smp)
+
+1:     .word   .
+       .word   __smpalt_begin
+       .word   __smpalt_end
+
+       .pushsection .data
+       .globl  smp_on_up
+smp_on_up:
+       ALT_SMP(.long   1)
+       ALT_UP(.long    0)
+       .popsection
+
+#endif
 
 #include "head-common.S"
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
new file mode 100644 (file)
index 0000000..54593b0
--- /dev/null
@@ -0,0 +1,849 @@
+/*
+ * This program is free software; you can 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.
+ *
+ * Copyright (C) 2009, 2010 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+/*
+ * HW_breakpoint: a unified kernel/user-space hardware breakpoint facility,
+ * using the CPU's debug registers.
+ */
+#define pr_fmt(fmt) "hw-breakpoint: " fmt
+
+#include <linux/errno.h>
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/smp.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <asm/current.h>
+#include <asm/hw_breakpoint.h>
+#include <asm/kdebug.h>
+#include <asm/system.h>
+#include <asm/traps.h>
+
+/* Breakpoint currently in use for each BRP. */
+static DEFINE_PER_CPU(struct perf_event *, bp_on_reg[ARM_MAX_BRP]);
+
+/* Watchpoint currently in use for each WRP. */
+static DEFINE_PER_CPU(struct perf_event *, wp_on_reg[ARM_MAX_WRP]);
+
+/* Number of BRP/WRP registers on this CPU. */
+static int core_num_brps;
+static int core_num_wrps;
+
+/* Debug architecture version. */
+static u8 debug_arch;
+
+/* Maximum supported watchpoint length. */
+static u8 max_watchpoint_len;
+
+/* Determine number of BRP registers available. */
+static int get_num_brps(void)
+{
+       u32 didr;
+       ARM_DBG_READ(c0, 0, didr);
+       return ((didr >> 24) & 0xf) + 1;
+}
+
+/* Determine number of WRP registers available. */
+static int get_num_wrps(void)
+{
+       /*
+        * FIXME: When a watchpoint fires, the only way to work out which
+        * watchpoint it was is by disassembling the faulting instruction
+        * and working out the address of the memory access.
+        *
+        * Furthermore, we can only do this if the watchpoint was precise
+        * since imprecise watchpoints prevent us from calculating register
+        * based addresses.
+        *
+        * For the time being, we only report 1 watchpoint register so we
+        * always know which watchpoint fired. In the future we can either
+        * add a disassembler and address generation emulator, or we can
+        * insert a check to see if the DFAR is set on watchpoint exception
+        * entry [the ARM ARM states that the DFAR is UNKNOWN, but
+        * experience shows that it is set on some implementations].
+        */
+
+#if 0
+       u32 didr, wrps;
+       ARM_DBG_READ(c0, 0, didr);
+       return ((didr >> 28) & 0xf) + 1;
+#endif
+
+       return 1;
+}
+
+int hw_breakpoint_slots(int type)
+{
+       /*
+        * We can be called early, so don't rely on
+        * our static variables being initialised.
+        */
+       switch (type) {
+       case TYPE_INST:
+               return get_num_brps();
+       case TYPE_DATA:
+               return get_num_wrps();
+       default:
+               pr_warning("unknown slot type: %d\n", type);
+               return 0;
+       }
+}
+
+/* Determine debug architecture. */
+static u8 get_debug_arch(void)
+{
+       u32 didr;
+
+       /* Do we implement the extended CPUID interface? */
+       if (((read_cpuid_id() >> 16) & 0xf) != 0xf) {
+               pr_warning("CPUID feature registers not supported. "
+                               "Assuming v6 debug is present.\n");
+               return ARM_DEBUG_ARCH_V6;
+       }
+
+       ARM_DBG_READ(c0, 0, didr);
+       return (didr >> 16) & 0xf;
+}
+
+/* Does this core support mismatch breakpoints? */
+static int core_has_mismatch_bps(void)
+{
+       return debug_arch >= ARM_DEBUG_ARCH_V7_ECP14 && core_num_brps > 1;
+}
+
+u8 arch_get_debug_arch(void)
+{
+       return debug_arch;
+}
+
+#define READ_WB_REG_CASE(OP2, M, VAL)          \
+       case ((OP2 << 4) + M):                  \
+               ARM_DBG_READ(c ## M, OP2, VAL); \
+               break
+
+#define WRITE_WB_REG_CASE(OP2, M, VAL)         \
+       case ((OP2 << 4) + M):                  \
+               ARM_DBG_WRITE(c ## M, OP2, VAL);\
+               break
+
+#define GEN_READ_WB_REG_CASES(OP2, VAL)                \
+       READ_WB_REG_CASE(OP2, 0, VAL);          \
+       READ_WB_REG_CASE(OP2, 1, VAL);          \
+       READ_WB_REG_CASE(OP2, 2, VAL);          \
+       READ_WB_REG_CASE(OP2, 3, VAL);          \
+       READ_WB_REG_CASE(OP2, 4, VAL);          \
+       READ_WB_REG_CASE(OP2, 5, VAL);          \
+       READ_WB_REG_CASE(OP2, 6, VAL);          \
+       READ_WB_REG_CASE(OP2, 7, VAL);          \
+       READ_WB_REG_CASE(OP2, 8, VAL);          \
+       READ_WB_REG_CASE(OP2, 9, VAL);          \
+       READ_WB_REG_CASE(OP2, 10, VAL);         \
+       READ_WB_REG_CASE(OP2, 11, VAL);         \
+       READ_WB_REG_CASE(OP2, 12, VAL);         \
+       READ_WB_REG_CASE(OP2, 13, VAL);         \
+       READ_WB_REG_CASE(OP2, 14, VAL);         \
+       READ_WB_REG_CASE(OP2, 15, VAL)
+
+#define GEN_WRITE_WB_REG_CASES(OP2, VAL)       \
+       WRITE_WB_REG_CASE(OP2, 0, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 1, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 2, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 3, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 4, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 5, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 6, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 7, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 8, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 9, VAL);         \
+       WRITE_WB_REG_CASE(OP2, 10, VAL);        \
+       WRITE_WB_REG_CASE(OP2, 11, VAL);        \
+       WRITE_WB_REG_CASE(OP2, 12, VAL);        \
+       WRITE_WB_REG_CASE(OP2, 13, VAL);        \
+       WRITE_WB_REG_CASE(OP2, 14, VAL);        \
+       WRITE_WB_REG_CASE(OP2, 15, VAL)
+
+static u32 read_wb_reg(int n)
+{
+       u32 val = 0;
+
+       switch (n) {
+       GEN_READ_WB_REG_CASES(ARM_OP2_BVR, val);
+       GEN_READ_WB_REG_CASES(ARM_OP2_BCR, val);
+       GEN_READ_WB_REG_CASES(ARM_OP2_WVR, val);
+       GEN_READ_WB_REG_CASES(ARM_OP2_WCR, val);
+       default:
+               pr_warning("attempt to read from unknown breakpoint "
+                               "register %d\n", n);
+       }
+
+       return val;
+}
+
+static void write_wb_reg(int n, u32 val)
+{
+       switch (n) {
+       GEN_WRITE_WB_REG_CASES(ARM_OP2_BVR, val);
+       GEN_WRITE_WB_REG_CASES(ARM_OP2_BCR, val);
+       GEN_WRITE_WB_REG_CASES(ARM_OP2_WVR, val);
+       GEN_WRITE_WB_REG_CASES(ARM_OP2_WCR, val);
+       default:
+               pr_warning("attempt to write to unknown breakpoint "
+                               "register %d\n", n);
+       }
+       isb();
+}
+
+/*
+ * In order to access the breakpoint/watchpoint control registers,
+ * we must be running in debug monitor mode. Unfortunately, we can
+ * be put into halting debug mode at any time by an external debugger
+ * but there is nothing we can do to prevent that.
+ */
+static int enable_monitor_mode(void)
+{
+       u32 dscr;
+       int ret = 0;
+
+       ARM_DBG_READ(c1, 0, dscr);
+
+       /* Ensure that halting mode is disabled. */
+       if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN, "halting debug mode enabled."
+                               "Unable to access hardware resources.")) {
+               ret = -EPERM;
+               goto out;
+       }
+
+       /* Write to the corresponding DSCR. */
+       switch (debug_arch) {
+       case ARM_DEBUG_ARCH_V6:
+       case ARM_DEBUG_ARCH_V6_1:
+               ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN));
+               break;
+       case ARM_DEBUG_ARCH_V7_ECP14:
+               ARM_DBG_WRITE(c2, 2, (dscr | ARM_DSCR_MDBGEN));
+               break;
+       default:
+               ret = -ENODEV;
+               goto out;
+       }
+
+       /* Check that the write made it through. */
+       ARM_DBG_READ(c1, 0, dscr);
+       if (WARN_ONCE(!(dscr & ARM_DSCR_MDBGEN),
+                               "failed to enable monitor mode.")) {
+               ret = -EPERM;
+       }
+
+out:
+       return ret;
+}
+
+/*
+ * Check if 8-bit byte-address select is available.
+ * This clobbers WRP 0.
+ */
+static u8 get_max_wp_len(void)
+{
+       u32 ctrl_reg;
+       struct arch_hw_breakpoint_ctrl ctrl;
+       u8 size = 4;
+
+       if (debug_arch < ARM_DEBUG_ARCH_V7_ECP14)
+               goto out;
+
+       if (enable_monitor_mode())
+               goto out;
+
+       memset(&ctrl, 0, sizeof(ctrl));
+       ctrl.len = ARM_BREAKPOINT_LEN_8;
+       ctrl_reg = encode_ctrl_reg(ctrl);
+
+       write_wb_reg(ARM_BASE_WVR, 0);
+       write_wb_reg(ARM_BASE_WCR, ctrl_reg);
+       if ((read_wb_reg(ARM_BASE_WCR) & ctrl_reg) == ctrl_reg)
+               size = 8;
+
+out:
+       return size;
+}
+
+u8 arch_get_max_wp_len(void)
+{
+       return max_watchpoint_len;
+}
+
+/*
+ * Handler for reactivating a suspended watchpoint when the single
+ * step `mismatch' breakpoint is triggered.
+ */
+static void wp_single_step_handler(struct perf_event *bp, int unused,
+                                  struct perf_sample_data *data,
+                                  struct pt_regs *regs)
+{
+       perf_event_enable(counter_arch_bp(bp)->suspended_wp);
+       unregister_hw_breakpoint(bp);
+}
+
+static int bp_is_single_step(struct perf_event *bp)
+{
+       return bp->overflow_handler == wp_single_step_handler;
+}
+
+/*
+ * Install a perf counter breakpoint.
+ */
+int arch_install_hw_breakpoint(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       struct perf_event **slot, **slots;
+       int i, max_slots, ctrl_base, val_base, ret = 0;
+
+       /* Ensure that we are in monitor mode and halting mode is disabled. */
+       ret = enable_monitor_mode();
+       if (ret)
+               goto out;
+
+       if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
+               /* Breakpoint */
+               ctrl_base = ARM_BASE_BCR;
+               val_base = ARM_BASE_BVR;
+               slots = __get_cpu_var(bp_on_reg);
+               max_slots = core_num_brps - 1;
+
+               if (bp_is_single_step(bp)) {
+                       info->ctrl.mismatch = 1;
+                       i = max_slots;
+                       slots[i] = bp;
+                       goto setup;
+               }
+       } else {
+               /* Watchpoint */
+               ctrl_base = ARM_BASE_WCR;
+               val_base = ARM_BASE_WVR;
+               slots = __get_cpu_var(wp_on_reg);
+               max_slots = core_num_wrps;
+       }
+
+       for (i = 0; i < max_slots; ++i) {
+               slot = &slots[i];
+
+               if (!*slot) {
+                       *slot = bp;
+                       break;
+               }
+       }
+
+       if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot")) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+setup:
+       /* Setup the address register. */
+       write_wb_reg(val_base + i, info->address);
+
+       /* Setup the control register. */
+       write_wb_reg(ctrl_base + i, encode_ctrl_reg(info->ctrl) | 0x1);
+
+out:
+       return ret;
+}
+
+void arch_uninstall_hw_breakpoint(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       struct perf_event **slot, **slots;
+       int i, max_slots, base;
+
+       if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) {
+               /* Breakpoint */
+               base = ARM_BASE_BCR;
+               slots = __get_cpu_var(bp_on_reg);
+               max_slots = core_num_brps - 1;
+
+               if (bp_is_single_step(bp)) {
+                       i = max_slots;
+                       slots[i] = NULL;
+                       goto reset;
+               }
+       } else {
+               /* Watchpoint */
+               base = ARM_BASE_WCR;
+               slots = __get_cpu_var(wp_on_reg);
+               max_slots = core_num_wrps;
+       }
+
+       /* Remove the breakpoint. */
+       for (i = 0; i < max_slots; ++i) {
+               slot = &slots[i];
+
+               if (*slot == bp) {
+                       *slot = NULL;
+                       break;
+               }
+       }
+
+       if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot"))
+               return;
+
+reset:
+       /* Reset the control register. */
+       write_wb_reg(base + i, 0);
+}
+
+static int get_hbp_len(u8 hbp_len)
+{
+       unsigned int len_in_bytes = 0;
+
+       switch (hbp_len) {
+       case ARM_BREAKPOINT_LEN_1:
+               len_in_bytes = 1;
+               break;
+       case ARM_BREAKPOINT_LEN_2:
+               len_in_bytes = 2;
+               break;
+       case ARM_BREAKPOINT_LEN_4:
+               len_in_bytes = 4;
+               break;
+       case ARM_BREAKPOINT_LEN_8:
+               len_in_bytes = 8;
+               break;
+       }
+
+       return len_in_bytes;
+}
+
+/*
+ * Check whether bp virtual address is in kernel space.
+ */
+int arch_check_bp_in_kernelspace(struct perf_event *bp)
+{
+       unsigned int len;
+       unsigned long va;
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+       va = info->address;
+       len = get_hbp_len(info->ctrl.len);
+
+       return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
+}
+
+/*
+ * Extract generic type and length encodings from an arch_hw_breakpoint_ctrl.
+ * Hopefully this will disappear when ptrace can bypass the conversion
+ * to generic breakpoint descriptions.
+ */
+int arch_bp_generic_fields(struct arch_hw_breakpoint_ctrl ctrl,
+                          int *gen_len, int *gen_type)
+{
+       /* Type */
+       switch (ctrl.type) {
+       case ARM_BREAKPOINT_EXECUTE:
+               *gen_type = HW_BREAKPOINT_X;
+               break;
+       case ARM_BREAKPOINT_LOAD:
+               *gen_type = HW_BREAKPOINT_R;
+               break;
+       case ARM_BREAKPOINT_STORE:
+               *gen_type = HW_BREAKPOINT_W;
+               break;
+       case ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE:
+               *gen_type = HW_BREAKPOINT_RW;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Len */
+       switch (ctrl.len) {
+       case ARM_BREAKPOINT_LEN_1:
+               *gen_len = HW_BREAKPOINT_LEN_1;
+               break;
+       case ARM_BREAKPOINT_LEN_2:
+               *gen_len = HW_BREAKPOINT_LEN_2;
+               break;
+       case ARM_BREAKPOINT_LEN_4:
+               *gen_len = HW_BREAKPOINT_LEN_4;
+               break;
+       case ARM_BREAKPOINT_LEN_8:
+               *gen_len = HW_BREAKPOINT_LEN_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Construct an arch_hw_breakpoint from a perf_event.
+ */
+static int arch_build_bp_info(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+       /* Type */
+       switch (bp->attr.bp_type) {
+       case HW_BREAKPOINT_X:
+               info->ctrl.type = ARM_BREAKPOINT_EXECUTE;
+               break;
+       case HW_BREAKPOINT_R:
+               info->ctrl.type = ARM_BREAKPOINT_LOAD;
+               break;
+       case HW_BREAKPOINT_W:
+               info->ctrl.type = ARM_BREAKPOINT_STORE;
+               break;
+       case HW_BREAKPOINT_RW:
+               info->ctrl.type = ARM_BREAKPOINT_LOAD | ARM_BREAKPOINT_STORE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Len */
+       switch (bp->attr.bp_len) {
+       case HW_BREAKPOINT_LEN_1:
+               info->ctrl.len = ARM_BREAKPOINT_LEN_1;
+               break;
+       case HW_BREAKPOINT_LEN_2:
+               info->ctrl.len = ARM_BREAKPOINT_LEN_2;
+               break;
+       case HW_BREAKPOINT_LEN_4:
+               info->ctrl.len = ARM_BREAKPOINT_LEN_4;
+               break;
+       case HW_BREAKPOINT_LEN_8:
+               info->ctrl.len = ARM_BREAKPOINT_LEN_8;
+               if ((info->ctrl.type != ARM_BREAKPOINT_EXECUTE)
+                       && max_watchpoint_len >= 8)
+                       break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Address */
+       info->address = bp->attr.bp_addr;
+
+       /* Privilege */
+       info->ctrl.privilege = ARM_BREAKPOINT_USER;
+       if (arch_check_bp_in_kernelspace(bp) && !bp_is_single_step(bp))
+               info->ctrl.privilege |= ARM_BREAKPOINT_PRIV;
+
+       /* Enabled? */
+       info->ctrl.enabled = !bp->attr.disabled;
+
+       /* Mismatch */
+       info->ctrl.mismatch = 0;
+
+       return 0;
+}
+
+/*
+ * Validate the arch-specific HW Breakpoint register settings.
+ */
+int arch_validate_hwbkpt_settings(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       int ret = 0;
+       u32 bytelen, max_len, offset, alignment_mask = 0x3;
+
+       /* Build the arch_hw_breakpoint. */
+       ret = arch_build_bp_info(bp);
+       if (ret)
+               goto out;
+
+       /* Check address alignment. */
+       if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
+               alignment_mask = 0x7;
+       if (info->address & alignment_mask) {
+               /*
+                * Try to fix the alignment. This may result in a length
+                * that is too large, so we must check for that.
+                */
+               bytelen = get_hbp_len(info->ctrl.len);
+               max_len = info->ctrl.type == ARM_BREAKPOINT_EXECUTE ? 4 :
+                               max_watchpoint_len;
+
+               if (max_len >= 8)
+                       offset = info->address & 0x7;
+               else
+                       offset = info->address & 0x3;
+
+               if (bytelen > (1 << ((max_len - (offset + 1)) >> 1))) {
+                       ret = -EFBIG;
+                       goto out;
+               }
+
+               info->ctrl.len <<= offset;
+               info->address &= ~offset;
+
+               pr_debug("breakpoint alignment fixup: length = 0x%x, "
+                       "address = 0x%x\n", info->ctrl.len, info->address);
+       }
+
+       /*
+        * Currently we rely on an overflow handler to take
+        * care of single-stepping the breakpoint when it fires.
+        * In the case of userspace breakpoints on a core with V7 debug,
+        * we can use the mismatch feature as a poor-man's hardware single-step.
+        */
+       if (WARN_ONCE(!bp->overflow_handler &&
+               (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_bps()),
+                       "overflow handler required but none found")) {
+               ret = -EINVAL;
+               goto out;
+       }
+out:
+       return ret;
+}
+
+static void update_mismatch_flag(int idx, int flag)
+{
+       struct perf_event *bp = __get_cpu_var(bp_on_reg[idx]);
+       struct arch_hw_breakpoint *info;
+
+       if (bp == NULL)
+               return;
+
+       info = counter_arch_bp(bp);
+
+       /* Update the mismatch field to enter/exit `single-step' mode */
+       if (!bp->overflow_handler && info->ctrl.mismatch != flag) {
+               info->ctrl.mismatch = flag;
+               write_wb_reg(ARM_BASE_BCR + idx, encode_ctrl_reg(info->ctrl) | 0x1);
+       }
+}
+
+static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
+{
+       int i;
+       struct perf_event *bp, **slots = __get_cpu_var(wp_on_reg);
+       struct arch_hw_breakpoint *info;
+       struct perf_event_attr attr;
+
+       /* Without a disassembler, we can only handle 1 watchpoint. */
+       BUG_ON(core_num_wrps > 1);
+
+       hw_breakpoint_init(&attr);
+       attr.bp_addr    = regs->ARM_pc & ~0x3;
+       attr.bp_len     = HW_BREAKPOINT_LEN_4;
+       attr.bp_type    = HW_BREAKPOINT_X;
+
+       for (i = 0; i < core_num_wrps; ++i) {
+               rcu_read_lock();
+
+               if (slots[i] == NULL) {
+                       rcu_read_unlock();
+                       continue;
+               }
+
+               /*
+                * The DFAR is an unknown value. Since we only allow a
+                * single watchpoint, we can set the trigger to the lowest
+                * possible faulting address.
+                */
+               info = counter_arch_bp(slots[i]);
+               info->trigger = slots[i]->attr.bp_addr;
+               pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
+               perf_bp_event(slots[i], regs);
+
+               /*
+                * If no overflow handler is present, insert a temporary
+                * mismatch breakpoint so we can single-step over the
+                * watchpoint trigger.
+                */
+               if (!slots[i]->overflow_handler) {
+                       bp = register_user_hw_breakpoint(&attr,
+                                                        wp_single_step_handler,
+                                                        current);
+                       counter_arch_bp(bp)->suspended_wp = slots[i];
+                       perf_event_disable(slots[i]);
+               }
+
+               rcu_read_unlock();
+       }
+}
+
+static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)
+{
+       int i;
+       int mismatch;
+       u32 ctrl_reg, val, addr;
+       struct perf_event *bp, **slots = __get_cpu_var(bp_on_reg);
+       struct arch_hw_breakpoint *info;
+       struct arch_hw_breakpoint_ctrl ctrl;
+
+       /* The exception entry code places the amended lr in the PC. */
+       addr = regs->ARM_pc;
+
+       for (i = 0; i < core_num_brps; ++i) {
+               rcu_read_lock();
+
+               bp = slots[i];
+
+               if (bp == NULL) {
+                       rcu_read_unlock();
+                       continue;
+               }
+
+               mismatch = 0;
+
+               /* Check if the breakpoint value matches. */
+               val = read_wb_reg(ARM_BASE_BVR + i);
+               if (val != (addr & ~0x3))
+                       goto unlock;
+
+               /* Possible match, check the byte address select to confirm. */
+               ctrl_reg = read_wb_reg(ARM_BASE_BCR + i);
+               decode_ctrl_reg(ctrl_reg, &ctrl);
+               if ((1 << (addr & 0x3)) & ctrl.len) {
+                       mismatch = 1;
+                       info = counter_arch_bp(bp);
+                       info->trigger = addr;
+               }
+
+unlock:
+               if ((mismatch && !info->ctrl.mismatch) || bp_is_single_step(bp)) {
+                       pr_debug("breakpoint fired: address = 0x%x\n", addr);
+                       perf_bp_event(bp, regs);
+               }
+
+               update_mismatch_flag(i, mismatch);
+               rcu_read_unlock();
+       }
+}
+
+/*
+ * Called from either the Data Abort Handler [watchpoint] or the
+ * Prefetch Abort Handler [breakpoint].
+ */
+static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
+                                struct pt_regs *regs)
+{
+       int ret = 1; /* Unhandled fault. */
+       u32 dscr;
+
+       /* We only handle watchpoints and hardware breakpoints. */
+       ARM_DBG_READ(c1, 0, dscr);
+
+       /* Perform perf callbacks. */
+       switch (ARM_DSCR_MOE(dscr)) {
+       case ARM_ENTRY_BREAKPOINT:
+               breakpoint_handler(addr, regs);
+               break;
+       case ARM_ENTRY_ASYNC_WATCHPOINT:
+               WARN_ON("Asynchronous watchpoint exception taken. "
+                       "Debugging results may be unreliable");
+       case ARM_ENTRY_SYNC_WATCHPOINT:
+               watchpoint_handler(addr, regs);
+               break;
+       default:
+               goto out;
+       }
+
+       ret = 0;
+out:
+       return ret;
+}
+
+/*
+ * One-time initialisation.
+ */
+static void __init reset_ctrl_regs(void *unused)
+{
+       int i;
+
+       if (enable_monitor_mode())
+               return;
+
+       for (i = 0; i < core_num_brps; ++i) {
+               write_wb_reg(ARM_BASE_BCR + i, 0UL);
+               write_wb_reg(ARM_BASE_BVR + i, 0UL);
+       }
+
+       for (i = 0; i < core_num_wrps; ++i) {
+               write_wb_reg(ARM_BASE_WCR + i, 0UL);
+               write_wb_reg(ARM_BASE_WVR + i, 0UL);
+       }
+}
+
+static int __init arch_hw_breakpoint_init(void)
+{
+       int ret = 0;
+       u32 dscr;
+
+       debug_arch = get_debug_arch();
+
+       if (debug_arch > ARM_DEBUG_ARCH_V7_ECP14) {
+               pr_info("debug architecture 0x%x unsupported.\n", debug_arch);
+               ret = -ENODEV;
+               goto out;
+       }
+
+       /* Determine how many BRPs/WRPs are available. */
+       core_num_brps = get_num_brps();
+       core_num_wrps = get_num_wrps();
+
+       pr_info("found %d breakpoint and %d watchpoint registers.\n",
+                       core_num_brps, core_num_wrps);
+
+       if (core_has_mismatch_bps())
+               pr_info("1 breakpoint reserved for watchpoint single-step.\n");
+
+       ARM_DBG_READ(c1, 0, dscr);
+       if (dscr & ARM_DSCR_HDBGEN) {
+               pr_warning("halting debug mode enabled. Assuming maximum "
+                               "watchpoint size of 4 bytes.");
+       } else {
+               /* Work out the maximum supported watchpoint length. */
+               max_watchpoint_len = get_max_wp_len();
+               pr_info("maximum watchpoint size is %u bytes.\n",
+                               max_watchpoint_len);
+
+               /*
+                * Reset the breakpoint resources. We assume that a halting
+                * debugger will leave the world in a nice state for us.
+                */
+               smp_call_function(reset_ctrl_regs, NULL, 1);
+               reset_ctrl_regs(NULL);
+       }
+
+       /* Register debug fault handler. */
+       hook_fault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT,
+                       "watchpoint debug exception");
+       hook_ifault_code(2, hw_breakpoint_pending, SIGTRAP, TRAP_HWBKPT,
+                       "breakpoint debug exception");
+
+out:
+       return ret;
+}
+arch_initcall(arch_hw_breakpoint_init);
+
+void hw_breakpoint_pmu_read(struct perf_event *bp)
+{
+}
+
+/*
+ * Dummy function to register with die_notifier.
+ */
+int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+                                       unsigned long val, void *data)
+{
+       return NOTIFY_DONE;
+}
index c0d5c3b3a760fa79624657ebc495b1d7b81b8c66..36ad3be4692a21c4970de80b8d8562327571f681 100644 (file)
@@ -154,14 +154,6 @@ void set_irq_flags(unsigned int irq, unsigned int iflags)
 
 void __init init_IRQ(void)
 {
-       struct irq_desc *desc;
-       int irq;
-
-       for (irq = 0; irq < nr_irqs; irq++) {
-               desc = irq_to_desc_alloc_node(irq, 0);
-               desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
-       }
-
        init_arch_irq();
 }
 
@@ -169,7 +161,7 @@ void __init init_IRQ(void)
 int __init arch_probe_nr_irqs(void)
 {
        nr_irqs = arch_nr_irqs ? arch_nr_irqs : NR_IRQS;
-       return 0;
+       return nr_irqs;
 }
 #endif
 
index 6b4605893f1e45329ab4058e33c2590056e02468..d9bd786ce23dc1228ac7937ad442292f08c74cca 100644 (file)
@@ -69,20 +69,31 @@ int module_frob_arch_sections(Elf_Ehdr *hdr,
 {
 #ifdef CONFIG_ARM_UNWIND
        Elf_Shdr *s, *sechdrs_end = sechdrs + hdr->e_shnum;
+       struct arm_unwind_mapping *maps = mod->arch.map;
 
        for (s = sechdrs; s < sechdrs_end; s++) {
-               if (strcmp(".ARM.exidx.init.text", secstrings + s->sh_name) == 0)
-                       mod->arch.unw_sec_init = s;
-               else if (strcmp(".ARM.exidx.devinit.text", secstrings + s->sh_name) == 0)
-                       mod->arch.unw_sec_devinit = s;
-               else if (strcmp(".ARM.exidx", secstrings + s->sh_name) == 0)
-                       mod->arch.unw_sec_core = s;
-               else if (strcmp(".init.text", secstrings + s->sh_name) == 0)
-                       mod->arch.sec_init_text = s;
-               else if (strcmp(".devinit.text", secstrings + s->sh_name) == 0)
-                       mod->arch.sec_devinit_text = s;
-               else if (strcmp(".text", secstrings + s->sh_name) == 0)
-                       mod->arch.sec_core_text = s;
+               char const *secname = secstrings + s->sh_name;
+
+               if (strcmp(".ARM.exidx.init.text", secname) == 0)
+                       maps[ARM_SEC_INIT].unw_sec = s;
+               else if (strcmp(".ARM.exidx.devinit.text", secname) == 0)
+                       maps[ARM_SEC_DEVINIT].unw_sec = s;
+               else if (strcmp(".ARM.exidx", secname) == 0)
+                       maps[ARM_SEC_CORE].unw_sec = s;
+               else if (strcmp(".ARM.exidx.exit.text", secname) == 0)
+                       maps[ARM_SEC_EXIT].unw_sec = s;
+               else if (strcmp(".ARM.exidx.devexit.text", secname) == 0)
+                       maps[ARM_SEC_DEVEXIT].unw_sec = s;
+               else if (strcmp(".init.text", secname) == 0)
+                       maps[ARM_SEC_INIT].sec_text = s;
+               else if (strcmp(".devinit.text", secname) == 0)
+                       maps[ARM_SEC_DEVINIT].sec_text = s;
+               else if (strcmp(".text", secname) == 0)
+                       maps[ARM_SEC_CORE].sec_text = s;
+               else if (strcmp(".exit.text", secname) == 0)
+                       maps[ARM_SEC_EXIT].sec_text = s;
+               else if (strcmp(".devexit.text", secname) == 0)
+                       maps[ARM_SEC_DEVEXIT].sec_text = s;
        }
 #endif
        return 0;
@@ -292,31 +303,22 @@ apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
 #ifdef CONFIG_ARM_UNWIND
 static void register_unwind_tables(struct module *mod)
 {
-       if (mod->arch.unw_sec_init && mod->arch.sec_init_text)
-               mod->arch.unwind_init =
-                       unwind_table_add(mod->arch.unw_sec_init->sh_addr,
-                                        mod->arch.unw_sec_init->sh_size,
-                                        mod->arch.sec_init_text->sh_addr,
-                                        mod->arch.sec_init_text->sh_size);
-       if (mod->arch.unw_sec_devinit && mod->arch.sec_devinit_text)
-               mod->arch.unwind_devinit =
-                       unwind_table_add(mod->arch.unw_sec_devinit->sh_addr,
-                                        mod->arch.unw_sec_devinit->sh_size,
-                                        mod->arch.sec_devinit_text->sh_addr,
-                                        mod->arch.sec_devinit_text->sh_size);
-       if (mod->arch.unw_sec_core && mod->arch.sec_core_text)
-               mod->arch.unwind_core =
-                       unwind_table_add(mod->arch.unw_sec_core->sh_addr,
-                                        mod->arch.unw_sec_core->sh_size,
-                                        mod->arch.sec_core_text->sh_addr,
-                                        mod->arch.sec_core_text->sh_size);
+       int i;
+       for (i = 0; i < ARM_SEC_MAX; ++i) {
+               struct arm_unwind_mapping *map = &mod->arch.map[i];
+               if (map->unw_sec && map->sec_text)
+                       map->unwind = unwind_table_add(map->unw_sec->sh_addr,
+                                                      map->unw_sec->sh_size,
+                                                      map->sec_text->sh_addr,
+                                                      map->sec_text->sh_size);
+       }
 }
 
 static void unregister_unwind_tables(struct module *mod)
 {
-       unwind_table_del(mod->arch.unwind_init);
-       unwind_table_del(mod->arch.unwind_devinit);
-       unwind_table_del(mod->arch.unwind_core);
+       int i = ARM_SEC_MAX;
+       while (--i >= 0)
+               unwind_table_del(mod->arch.map[i].unwind);
 }
 #else
 static inline void register_unwind_tables(struct module *mod) { }
index ecbb0288e5dd95c80b420635dffee6ef600f86a8..49643b1467e62d529d4edd661990bb64da1e1f73 100644 (file)
@@ -123,6 +123,12 @@ armpmu_get_max_events(void)
 }
 EXPORT_SYMBOL_GPL(armpmu_get_max_events);
 
+int perf_num_counters(void)
+{
+       return armpmu_get_max_events();
+}
+EXPORT_SYMBOL_GPL(perf_num_counters);
+
 #define HW_OP_UNSUPPORTED              0xFFFF
 
 #define C(_x) \
@@ -221,46 +227,56 @@ again:
 }
 
 static void
-armpmu_disable(struct perf_event *event)
+armpmu_read(struct perf_event *event)
 {
-       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
-       int idx = hwc->idx;
-
-       WARN_ON(idx < 0);
-
-       clear_bit(idx, cpuc->active_mask);
-       armpmu->disable(hwc, idx);
-
-       barrier();
 
-       armpmu_event_update(event, hwc, idx);
-       cpuc->events[idx] = NULL;
-       clear_bit(idx, cpuc->used_mask);
+       /* Don't read disabled counters! */
+       if (hwc->idx < 0)
+               return;
 
-       perf_event_update_userpage(event);
+       armpmu_event_update(event, hwc, hwc->idx);
 }
 
 static void
-armpmu_read(struct perf_event *event)
+armpmu_stop(struct perf_event *event, int flags)
 {
        struct hw_perf_event *hwc = &event->hw;
 
-       /* Don't read disabled counters! */
-       if (hwc->idx < 0)
+       if (!armpmu)
                return;
 
-       armpmu_event_update(event, hwc, hwc->idx);
+       /*
+        * ARM pmu always has to update the counter, so ignore
+        * PERF_EF_UPDATE, see comments in armpmu_start().
+        */
+       if (!(hwc->state & PERF_HES_STOPPED)) {
+               armpmu->disable(hwc, hwc->idx);
+               barrier(); /* why? */
+               armpmu_event_update(event, hwc, hwc->idx);
+               hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+       }
 }
 
 static void
-armpmu_unthrottle(struct perf_event *event)
+armpmu_start(struct perf_event *event, int flags)
 {
        struct hw_perf_event *hwc = &event->hw;
 
+       if (!armpmu)
+               return;
+
+       /*
+        * ARM pmu always has to reprogram the period, so ignore
+        * PERF_EF_RELOAD, see the comment below.
+        */
+       if (flags & PERF_EF_RELOAD)
+               WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+
+       hwc->state = 0;
        /*
         * Set the period again. Some counters can't be stopped, so when we
-        * were throttled we simply disabled the IRQ source and the counter
+        * were stopped we simply disabled the IRQ source and the counter
         * may have been left counting. If we don't do this step then we may
         * get an interrupt too soon or *way* too late if the overflow has
         * happened since disabling.
@@ -269,14 +285,33 @@ armpmu_unthrottle(struct perf_event *event)
        armpmu->enable(hwc, hwc->idx);
 }
 
+static void
+armpmu_del(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+
+       WARN_ON(idx < 0);
+
+       clear_bit(idx, cpuc->active_mask);
+       armpmu_stop(event, PERF_EF_UPDATE);
+       cpuc->events[idx] = NULL;
+       clear_bit(idx, cpuc->used_mask);
+
+       perf_event_update_userpage(event);
+}
+
 static int
-armpmu_enable(struct perf_event *event)
+armpmu_add(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
        int idx;
        int err = 0;
 
+       perf_pmu_disable(event->pmu);
+
        /* If we don't have a space for the counter then finish early. */
        idx = armpmu->get_event_idx(cpuc, hwc);
        if (idx < 0) {
@@ -293,25 +328,19 @@ armpmu_enable(struct perf_event *event)
        cpuc->events[idx] = event;
        set_bit(idx, cpuc->active_mask);
 
-       /* Set the period for the event. */
-       armpmu_event_set_period(event, hwc, idx);
-
-       /* Enable the event. */
-       armpmu->enable(hwc, idx);
+       hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+       if (flags & PERF_EF_START)
+               armpmu_start(event, PERF_EF_RELOAD);
 
        /* Propagate our changes to the userspace mapping. */
        perf_event_update_userpage(event);
 
 out:
+       perf_pmu_enable(event->pmu);
        return err;
 }
 
-static struct pmu pmu = {
-       .enable     = armpmu_enable,
-       .disable    = armpmu_disable,
-       .unthrottle = armpmu_unthrottle,
-       .read       = armpmu_read,
-};
+static struct pmu pmu;
 
 static int
 validate_event(struct cpu_hw_events *cpuc,
@@ -491,20 +520,29 @@ __hw_perf_event_init(struct perf_event *event)
        return err;
 }
 
-const struct pmu *
-hw_perf_event_init(struct perf_event *event)
+static int armpmu_event_init(struct perf_event *event)
 {
        int err = 0;
 
+       switch (event->attr.type) {
+       case PERF_TYPE_RAW:
+       case PERF_TYPE_HARDWARE:
+       case PERF_TYPE_HW_CACHE:
+               break;
+
+       default:
+               return -ENOENT;
+       }
+
        if (!armpmu)
-               return ERR_PTR(-ENODEV);
+               return -ENODEV;
 
        event->destroy = hw_perf_event_destroy;
 
        if (!atomic_inc_not_zero(&active_events)) {
-               if (atomic_read(&active_events) > perf_max_events) {
+               if (atomic_read(&active_events) > armpmu->num_events) {
                        atomic_dec(&active_events);
-                       return ERR_PTR(-ENOSPC);
+                       return -ENOSPC;
                }
 
                mutex_lock(&pmu_reserve_mutex);
@@ -518,17 +556,16 @@ hw_perf_event_init(struct perf_event *event)
        }
 
        if (err)
-               return ERR_PTR(err);
+               return err;
 
        err = __hw_perf_event_init(event);
        if (err)
                hw_perf_event_destroy(event);
 
-       return err ? ERR_PTR(err) : &pmu;
+       return err;
 }
 
-void
-hw_perf_enable(void)
+static void armpmu_enable(struct pmu *pmu)
 {
        /* Enable all of the perf events on hardware. */
        int idx;
@@ -549,13 +586,23 @@ hw_perf_enable(void)
        armpmu->start();
 }
 
-void
-hw_perf_disable(void)
+static void armpmu_disable(struct pmu *pmu)
 {
        if (armpmu)
                armpmu->stop();
 }
 
+static struct pmu pmu = {
+       .pmu_enable     = armpmu_enable,
+       .pmu_disable    = armpmu_disable,
+       .event_init     = armpmu_event_init,
+       .add            = armpmu_add,
+       .del            = armpmu_del,
+       .start          = armpmu_start,
+       .stop           = armpmu_stop,
+       .read           = armpmu_read,
+};
+
 /*
  * ARMv6 Performance counter handling code.
  *
@@ -1045,7 +1092,7 @@ armv6pmu_handle_irq(int irq_num,
         * platforms that can have the PMU interrupts raised as an NMI, this
         * will not work.
         */
-       perf_event_do_pending();
+       irq_work_run();
 
        return IRQ_HANDLED;
 }
@@ -2021,7 +2068,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
         * platforms that can have the PMU interrupts raised as an NMI, this
         * will not work.
         */
-       perf_event_do_pending();
+       irq_work_run();
 
        return IRQ_HANDLED;
 }
@@ -2389,7 +2436,7 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
                        armpmu->disable(hwc, idx);
        }
 
-       perf_event_do_pending();
+       irq_work_run();
 
        /*
         * Re-enable the PMU.
@@ -2716,7 +2763,7 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
                        armpmu->disable(hwc, idx);
        }
 
-       perf_event_do_pending();
+       irq_work_run();
 
        /*
         * Re-enable the PMU.
@@ -2933,14 +2980,12 @@ init_hw_perf_events(void)
                        armpmu = &armv6pmu;
                        memcpy(armpmu_perf_cache_map, armv6_perf_cache_map,
                                        sizeof(armv6_perf_cache_map));
-                       perf_max_events = armv6pmu.num_events;
                        break;
                case 0xB020:    /* ARM11mpcore */
                        armpmu = &armv6mpcore_pmu;
                        memcpy(armpmu_perf_cache_map,
                               armv6mpcore_perf_cache_map,
                               sizeof(armv6mpcore_perf_cache_map));
-                       perf_max_events = armv6mpcore_pmu.num_events;
                        break;
                case 0xC080:    /* Cortex-A8 */
                        armv7pmu.id = ARM_PERF_PMU_ID_CA8;
@@ -2952,7 +2997,6 @@ init_hw_perf_events(void)
                        /* Reset PMNC and read the nb of CNTx counters
                            supported */
                        armv7pmu.num_events = armv7_reset_read_pmnc();
-                       perf_max_events = armv7pmu.num_events;
                        break;
                case 0xC090:    /* Cortex-A9 */
                        armv7pmu.id = ARM_PERF_PMU_ID_CA9;
@@ -2964,7 +3008,6 @@ init_hw_perf_events(void)
                        /* Reset PMNC and read the nb of CNTx counters
                            supported */
                        armv7pmu.num_events = armv7_reset_read_pmnc();
-                       perf_max_events = armv7pmu.num_events;
                        break;
                }
        /* Intel CPUs [xscale]. */
@@ -2975,13 +3018,11 @@ init_hw_perf_events(void)
                        armpmu = &xscale1pmu;
                        memcpy(armpmu_perf_cache_map, xscale_perf_cache_map,
                                        sizeof(xscale_perf_cache_map));
-                       perf_max_events = xscale1pmu.num_events;
                        break;
                case 2:
                        armpmu = &xscale2pmu;
                        memcpy(armpmu_perf_cache_map, xscale_perf_cache_map,
                                        sizeof(xscale_perf_cache_map));
-                       perf_max_events = xscale2pmu.num_events;
                        break;
                }
        }
@@ -2991,9 +3032,10 @@ init_hw_perf_events(void)
                                arm_pmu_names[armpmu->id], armpmu->num_events);
        } else {
                pr_info("no hardware support available\n");
-               perf_max_events = -1;
        }
 
+       perf_pmu_register(&pmu);
+
        return 0;
 }
 arch_initcall(init_hw_perf_events);
@@ -3001,13 +3043,6 @@ arch_initcall(init_hw_perf_events);
 /*
  * Callchain handling code.
  */
-static inline void
-callchain_store(struct perf_callchain_entry *entry,
-               u64 ip)
-{
-       if (entry->nr < PERF_MAX_STACK_DEPTH)
-               entry->ip[entry->nr++] = ip;
-}
 
 /*
  * The registers we're interested in are at the end of the variable
@@ -3039,7 +3074,7 @@ user_backtrace(struct frame_tail *tail,
        if (__copy_from_user_inatomic(&buftail, tail, sizeof(buftail)))
                return NULL;
 
-       callchain_store(entry, buftail.lr);
+       perf_callchain_store(entry, buftail.lr);
 
        /*
         * Frame pointers should strictly progress back up the stack
@@ -3051,16 +3086,11 @@ user_backtrace(struct frame_tail *tail,
        return buftail.fp - 1;
 }
 
-static void
-perf_callchain_user(struct pt_regs *regs,
-                   struct perf_callchain_entry *entry)
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
        struct frame_tail *tail;
 
-       callchain_store(entry, PERF_CONTEXT_USER);
-
-       if (!user_mode(regs))
-               regs = task_pt_regs(current);
 
        tail = (struct frame_tail *)regs->ARM_fp - 1;
 
@@ -3078,56 +3108,18 @@ callchain_trace(struct stackframe *fr,
                void *data)
 {
        struct perf_callchain_entry *entry = data;
-       callchain_store(entry, fr->pc);
+       perf_callchain_store(entry, fr->pc);
        return 0;
 }
 
-static void
-perf_callchain_kernel(struct pt_regs *regs,
-                     struct perf_callchain_entry *entry)
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
        struct stackframe fr;
 
-       callchain_store(entry, PERF_CONTEXT_KERNEL);
        fr.fp = regs->ARM_fp;
        fr.sp = regs->ARM_sp;
        fr.lr = regs->ARM_lr;
        fr.pc = regs->ARM_pc;
        walk_stackframe(&fr, callchain_trace, entry);
 }
-
-static void
-perf_do_callchain(struct pt_regs *regs,
-                 struct perf_callchain_entry *entry)
-{
-       int is_user;
-
-       if (!regs)
-               return;
-
-       is_user = user_mode(regs);
-
-       if (!current || !current->pid)
-               return;
-
-       if (is_user && current->state != TASK_RUNNING)
-               return;
-
-       if (!is_user)
-               perf_callchain_kernel(regs, entry);
-
-       if (current->mm)
-               perf_callchain_user(regs, entry);
-}
-
-static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
-
-struct perf_callchain_entry *
-perf_callchain(struct pt_regs *regs)
-{
-       struct perf_callchain_entry *entry = &__get_cpu_var(pmc_irq_entry);
-
-       entry->nr = 0;
-       perf_do_callchain(regs, entry);
-       return entry;
-}
index 401e38be1f787c16e7b36d6429406a05229d83da..e76fcaadce03fca34f20524bc03df51f73cb2d99 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/utsname.h>
 #include <linux/uaccess.h>
 #include <linux/random.h>
+#include <linux/hw_breakpoint.h>
 
 #include <asm/cacheflush.h>
 #include <asm/leds.h>
@@ -135,6 +136,25 @@ EXPORT_SYMBOL(pm_power_off);
 void (*arm_pm_restart)(char str, const char *cmd) = arm_machine_restart;
 EXPORT_SYMBOL_GPL(arm_pm_restart);
 
+static void do_nothing(void *unused)
+{
+}
+
+/*
+ * cpu_idle_wait - Used to ensure that all the CPUs discard old value of
+ * pm_idle and update to new pm_idle value. Required while changing pm_idle
+ * handler on SMP systems.
+ *
+ * Caller must have changed pm_idle to the new value before the call. Old
+ * pm_idle value will not be used by any CPU after the return of this function.
+ */
+void cpu_idle_wait(void)
+{
+       smp_mb();
+       /* kick all the CPUs so that they exit out of pm_idle */
+       smp_call_function(do_nothing, NULL, 1);
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
 /*
  * This is our default idle handler.  We need to disable
@@ -317,6 +337,8 @@ void flush_thread(void)
        struct thread_info *thread = current_thread_info();
        struct task_struct *tsk = current;
 
+       flush_ptrace_hw_breakpoint(tsk);
+
        memset(thread->used_cp, 0, sizeof(thread->used_cp));
        memset(&tsk->thread.debug, 0, sizeof(struct debug_info));
        memset(&thread->fpstate, 0, sizeof(union fp_state));
@@ -345,6 +367,8 @@ copy_thread(unsigned long clone_flags, unsigned long stack_start,
        thread->cpu_context.sp = (unsigned long)childregs;
        thread->cpu_context.pc = (unsigned long)ret_from_fork;
 
+       clear_ptrace_hw_breakpoint(p);
+
        if (clone_flags & CLONE_SETTLS)
                thread->tp_value = regs->ARM_r3;
 
@@ -458,3 +482,24 @@ unsigned long arch_randomize_brk(struct mm_struct *mm)
        unsigned long range_end = mm->brk + 0x02000000;
        return randomize_range(mm->brk, range_end, 0) ? : mm->brk;
 }
+
+/*
+ * The vectors page is always readable from user space for the
+ * atomic helpers and the signal restart code.  Let's declare a mapping
+ * for it so it is visible through ptrace and /proc/<pid>/mem.
+ */
+
+int vectors_user_mapping(void)
+{
+       struct mm_struct *mm = current->mm;
+       return install_special_mapping(mm, 0xffff0000, PAGE_SIZE,
+                                      VM_READ | VM_EXEC |
+                                      VM_MAYREAD | VM_MAYEXEC |
+                                      VM_ALWAYSDUMP | VM_RESERVED,
+                                      NULL);
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+       return (vma->vm_start == 0xffff0000) ? "[vectors]" : NULL;
+}
index f99d489822d50fb23e46f4e7760411b766e040e7..e0cb6370ed148d9c24d6e856bc6c5c46128f38cb 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/init.h>
 #include <linux/signal.h>
 #include <linux/uaccess.h>
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
 
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -847,6 +849,232 @@ static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data)
 }
 #endif
 
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+/*
+ * Convert a virtual register number into an index for a thread_info
+ * breakpoint array. Breakpoints are identified using positive numbers
+ * whilst watchpoints are negative. The registers are laid out as pairs
+ * of (address, control), each pair mapping to a unique hw_breakpoint struct.
+ * Register 0 is reserved for describing resource information.
+ */
+static int ptrace_hbp_num_to_idx(long num)
+{
+       if (num < 0)
+               num = (ARM_MAX_BRP << 1) - num;
+       return (num - 1) >> 1;
+}
+
+/*
+ * Returns the virtual register number for the address of the
+ * breakpoint at index idx.
+ */
+static long ptrace_hbp_idx_to_num(int idx)
+{
+       long mid = ARM_MAX_BRP << 1;
+       long num = (idx << 1) + 1;
+       return num > mid ? mid - num : num;
+}
+
+/*
+ * Handle hitting a HW-breakpoint.
+ */
+static void ptrace_hbptriggered(struct perf_event *bp, int unused,
+                                    struct perf_sample_data *data,
+                                    struct pt_regs *regs)
+{
+       struct arch_hw_breakpoint *bkpt = counter_arch_bp(bp);
+       long num;
+       int i;
+       siginfo_t info;
+
+       for (i = 0; i < ARM_MAX_HBP_SLOTS; ++i)
+               if (current->thread.debug.hbp[i] == bp)
+                       break;
+
+       num = (i == ARM_MAX_HBP_SLOTS) ? 0 : ptrace_hbp_idx_to_num(i);
+
+       info.si_signo   = SIGTRAP;
+       info.si_errno   = (int)num;
+       info.si_code    = TRAP_HWBKPT;
+       info.si_addr    = (void __user *)(bkpt->trigger);
+
+       force_sig_info(SIGTRAP, &info, current);
+}
+
+/*
+ * Set ptrace breakpoint pointers to zero for this task.
+ * This is required in order to prevent child processes from unregistering
+ * breakpoints held by their parent.
+ */
+void clear_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+       memset(tsk->thread.debug.hbp, 0, sizeof(tsk->thread.debug.hbp));
+}
+
+/*
+ * Unregister breakpoints from this task and reset the pointers in
+ * the thread_struct.
+ */
+void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+       int i;
+       struct thread_struct *t = &tsk->thread;
+
+       for (i = 0; i < ARM_MAX_HBP_SLOTS; i++) {
+               if (t->debug.hbp[i]) {
+                       unregister_hw_breakpoint(t->debug.hbp[i]);
+                       t->debug.hbp[i] = NULL;
+               }
+       }
+}
+
+static u32 ptrace_get_hbp_resource_info(void)
+{
+       u8 num_brps, num_wrps, debug_arch, wp_len;
+       u32 reg = 0;
+
+       num_brps        = hw_breakpoint_slots(TYPE_INST);
+       num_wrps        = hw_breakpoint_slots(TYPE_DATA);
+       debug_arch      = arch_get_debug_arch();
+       wp_len          = arch_get_max_wp_len();
+
+       reg             |= debug_arch;
+       reg             <<= 8;
+       reg             |= wp_len;
+       reg             <<= 8;
+       reg             |= num_wrps;
+       reg             <<= 8;
+       reg             |= num_brps;
+
+       return reg;
+}
+
+static struct perf_event *ptrace_hbp_create(struct task_struct *tsk, int type)
+{
+       struct perf_event_attr attr;
+
+       ptrace_breakpoint_init(&attr);
+
+       /* Initialise fields to sane defaults. */
+       attr.bp_addr    = 0;
+       attr.bp_len     = HW_BREAKPOINT_LEN_4;
+       attr.bp_type    = type;
+       attr.disabled   = 1;
+
+       return register_user_hw_breakpoint(&attr, ptrace_hbptriggered, tsk);
+}
+
+static int ptrace_gethbpregs(struct task_struct *tsk, long num,
+                            unsigned long  __user *data)
+{
+       u32 reg;
+       int idx, ret = 0;
+       struct perf_event *bp;
+       struct arch_hw_breakpoint_ctrl arch_ctrl;
+
+       if (num == 0) {
+               reg = ptrace_get_hbp_resource_info();
+       } else {
+               idx = ptrace_hbp_num_to_idx(num);
+               if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               bp = tsk->thread.debug.hbp[idx];
+               if (!bp) {
+                       reg = 0;
+                       goto put;
+               }
+
+               arch_ctrl = counter_arch_bp(bp)->ctrl;
+
+               /*
+                * Fix up the len because we may have adjusted it
+                * to compensate for an unaligned address.
+                */
+               while (!(arch_ctrl.len & 0x1))
+                       arch_ctrl.len >>= 1;
+
+               if (idx & 0x1)
+                       reg = encode_ctrl_reg(arch_ctrl);
+               else
+                       reg = bp->attr.bp_addr;
+       }
+
+put:
+       if (put_user(reg, data))
+               ret = -EFAULT;
+
+out:
+       return ret;
+}
+
+static int ptrace_sethbpregs(struct task_struct *tsk, long num,
+                            unsigned long __user *data)
+{
+       int idx, gen_len, gen_type, implied_type, ret = 0;
+       u32 user_val;
+       struct perf_event *bp;
+       struct arch_hw_breakpoint_ctrl ctrl;
+       struct perf_event_attr attr;
+
+       if (num == 0)
+               goto out;
+       else if (num < 0)
+               implied_type = HW_BREAKPOINT_RW;
+       else
+               implied_type = HW_BREAKPOINT_X;
+
+       idx = ptrace_hbp_num_to_idx(num);
+       if (idx < 0 || idx >= ARM_MAX_HBP_SLOTS) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (get_user(user_val, data)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       bp = tsk->thread.debug.hbp[idx];
+       if (!bp) {
+               bp = ptrace_hbp_create(tsk, implied_type);
+               if (IS_ERR(bp)) {
+                       ret = PTR_ERR(bp);
+                       goto out;
+               }
+               tsk->thread.debug.hbp[idx] = bp;
+       }
+
+       attr = bp->attr;
+
+       if (num & 0x1) {
+               /* Address */
+               attr.bp_addr    = user_val;
+       } else {
+               /* Control */
+               decode_ctrl_reg(user_val, &ctrl);
+               ret = arch_bp_generic_fields(ctrl, &gen_len, &gen_type);
+               if (ret)
+                       goto out;
+
+               if ((gen_type & implied_type) != gen_type) {
+                               ret = -EINVAL;
+                               goto out;
+               }
+
+               attr.bp_len     = gen_len;
+               attr.bp_type    = gen_type;
+               attr.disabled   = !ctrl.enabled;
+       }
+
+       ret = modify_user_hw_breakpoint(bp, &attr);
+out:
+       return ret;
+}
+#endif
+
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
        int ret;
@@ -916,6 +1144,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                        break;
 #endif
 
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+               case PTRACE_GETHBPREGS:
+                       ret = ptrace_gethbpregs(child, addr,
+                                               (unsigned long __user *)data);
+                       break;
+               case PTRACE_SETHBPREGS:
+                       ret = ptrace_sethbpregs(child, addr,
+                                               (unsigned long __user *)data);
+                       break;
+#endif
+
                default:
                        ret = ptrace_request(child, request, addr, data);
                        break;
index d5231ae7355aa286bf5503e0180954f84e4f6022..336f14e0e5c212685c09f13f8ecbb30662873354 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/procinfo.h>
 #include <asm/sections.h>
 #include <asm/setup.h>
+#include <asm/smp_plat.h>
 #include <asm/mach-types.h>
 #include <asm/cacheflush.h>
 #include <asm/cachetype.h>
@@ -238,6 +239,35 @@ int cpu_architecture(void)
        return cpu_arch;
 }
 
+static int cpu_has_aliasing_icache(unsigned int arch)
+{
+       int aliasing_icache;
+       unsigned int id_reg, num_sets, line_size;
+
+       /* arch specifies the register format */
+       switch (arch) {
+       case CPU_ARCH_ARMv7:
+               asm("mcr        p15, 2, %0, c0, c0, 0 @ set CSSELR"
+                   : /* No output operands */
+                   : "r" (1));
+               isb();
+               asm("mrc        p15, 1, %0, c0, c0, 0 @ read CCSIDR"
+                   : "=r" (id_reg));
+               line_size = 4 << ((id_reg & 0x7) + 2);
+               num_sets = ((id_reg >> 13) & 0x7fff) + 1;
+               aliasing_icache = (line_size * num_sets) > PAGE_SIZE;
+               break;
+       case CPU_ARCH_ARMv6:
+               aliasing_icache = read_cpuid_cachetype() & (1 << 11);
+               break;
+       default:
+               /* I-cache aliases will be handled by D-cache aliasing code */
+               aliasing_icache = 0;
+       }
+
+       return aliasing_icache;
+}
+
 static void __init cacheid_init(void)
 {
        unsigned int cachetype = read_cpuid_cachetype();
@@ -249,10 +279,15 @@ static void __init cacheid_init(void)
                        cacheid = CACHEID_VIPT_NONALIASING;
                        if ((cachetype & (3 << 14)) == 1 << 14)
                                cacheid |= CACHEID_ASID_TAGGED;
-               } else if (cachetype & (1 << 23))
+                       else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
+                               cacheid |= CACHEID_VIPT_I_ALIASING;
+               } else if (cachetype & (1 << 23)) {
                        cacheid = CACHEID_VIPT_ALIASING;
-               else
+               } else {
                        cacheid = CACHEID_VIPT_NONALIASING;
+                       if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6))
+                               cacheid |= CACHEID_VIPT_I_ALIASING;
+               }
        } else {
                cacheid = CACHEID_VIVT;
        }
@@ -263,7 +298,7 @@ static void __init cacheid_init(void)
                cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown",
                cache_is_vivt() ? "VIVT" :
                icache_is_vivt_asid_tagged() ? "VIVT ASID tagged" :
-               cache_is_vipt_aliasing() ? "VIPT aliasing" :
+               icache_is_vipt_aliasing() ? "VIPT aliasing" :
                cache_is_vipt_nonaliasing() ? "VIPT nonaliasing" : "unknown");
 }
 
@@ -490,7 +525,7 @@ request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
 
        kernel_code.start   = virt_to_phys(_text);
        kernel_code.end     = virt_to_phys(_etext - 1);
-       kernel_data.start   = virt_to_phys(_data);
+       kernel_data.start   = virt_to_phys(_sdata);
        kernel_data.end     = virt_to_phys(_end - 1);
 
        for (i = 0; i < mi->nr_banks; i++) {
@@ -825,7 +860,8 @@ void __init setup_arch(char **cmdline_p)
        request_standard_resources(&meminfo, mdesc);
 
 #ifdef CONFIG_SMP
-       smp_init_cpus();
+       if (is_smp())
+               smp_init_cpus();
 #endif
        reserve_crashkernel();
 
index 40dc74f2b27f3362f8739f5e9898963dd27a221b..8c1959590252e7161f1da38497eddba9b0538afb 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
+#include <asm/sections.h>
 #include <asm/tlbflush.h>
 #include <asm/ptrace.h>
 #include <asm/localtimer.h>
@@ -67,12 +68,47 @@ enum ipi_msg_type {
        IPI_CPU_STOP,
 };
 
+static inline void identity_mapping_add(pgd_t *pgd, unsigned long start,
+       unsigned long end)
+{
+       unsigned long addr, prot;
+       pmd_t *pmd;
+
+       prot = PMD_TYPE_SECT | PMD_SECT_AP_WRITE;
+       if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
+               prot |= PMD_BIT4;
+
+       for (addr = start & PGDIR_MASK; addr < end;) {
+               pmd = pmd_offset(pgd + pgd_index(addr), addr);
+               pmd[0] = __pmd(addr | prot);
+               addr += SECTION_SIZE;
+               pmd[1] = __pmd(addr | prot);
+               addr += SECTION_SIZE;
+               flush_pmd_entry(pmd);
+               outer_clean_range(__pa(pmd), __pa(pmd + 1));
+       }
+}
+
+static inline void identity_mapping_del(pgd_t *pgd, unsigned long start,
+       unsigned long end)
+{
+       unsigned long addr;
+       pmd_t *pmd;
+
+       for (addr = start & PGDIR_MASK; addr < end; addr += PGDIR_SIZE) {
+               pmd = pmd_offset(pgd + pgd_index(addr), addr);
+               pmd[0] = __pmd(0);
+               pmd[1] = __pmd(0);
+               clean_pmd_entry(pmd);
+               outer_clean_range(__pa(pmd), __pa(pmd + 1));
+       }
+}
+
 int __cpuinit __cpu_up(unsigned int cpu)
 {
        struct cpuinfo_arm *ci = &per_cpu(cpu_data, cpu);
        struct task_struct *idle = ci->idle;
        pgd_t *pgd;
-       pmd_t *pmd;
        int ret;
 
        /*
@@ -101,11 +137,16 @@ int __cpuinit __cpu_up(unsigned int cpu)
         * a 1:1 mapping for the physical address of the kernel.
         */
        pgd = pgd_alloc(&init_mm);
-       pmd = pmd_offset(pgd + pgd_index(PHYS_OFFSET), PHYS_OFFSET);
-       *pmd = __pmd((PHYS_OFFSET & PGDIR_MASK) |
-                    PMD_TYPE_SECT | PMD_SECT_AP_WRITE);
-       flush_pmd_entry(pmd);
-       outer_clean_range(__pa(pmd), __pa(pmd + 1));
+       if (!pgd)
+               return -ENOMEM;
+
+       if (PHYS_OFFSET != PAGE_OFFSET) {
+#ifndef CONFIG_HOTPLUG_CPU
+               identity_mapping_add(pgd, __pa(__init_begin), __pa(__init_end));
+#endif
+               identity_mapping_add(pgd, __pa(_stext), __pa(_etext));
+               identity_mapping_add(pgd, __pa(_sdata), __pa(_edata));
+       }
 
        /*
         * We need to tell the secondary core where to find
@@ -143,8 +184,14 @@ int __cpuinit __cpu_up(unsigned int cpu)
        secondary_data.stack = NULL;
        secondary_data.pgdir = 0;
 
-       *pmd = __pmd(0);
-       clean_pmd_entry(pmd);
+       if (PHYS_OFFSET != PAGE_OFFSET) {
+#ifndef CONFIG_HOTPLUG_CPU
+               identity_mapping_del(pgd, __pa(__init_begin), __pa(__init_end));
+#endif
+               identity_mapping_del(pgd, __pa(_stext), __pa(_etext));
+               identity_mapping_del(pgd, __pa(_sdata), __pa(_edata));
+       }
+
        pgd_free(&init_mm, pgd);
 
        if (ret) {
@@ -567,7 +614,8 @@ void smp_send_stop(void)
 {
        cpumask_t mask = cpu_online_map;
        cpu_clear(smp_processor_id(), mask);
-       send_ipi_message(&mask, IPI_CPU_STOP);
+       if (!cpus_empty(mask))
+               send_ipi_message(&mask, IPI_CPU_STOP);
 }
 
 /*
index dd81a918c106ea30029c0b8ce4eb60885f8a69a1..2a161765f6d5fdc0ac07805c2a4a62957adf72a0 100644 (file)
@@ -146,6 +146,8 @@ static struct unwind_idx *unwind_find_idx(unsigned long addr)
                            addr < table->end_addr) {
                                idx = search_index(addr, table->start,
                                                   table->stop - 1);
+                               /* Move-to-front to exploit common traces */
+                               list_move(&table->list, &unwind_tables);
                                break;
                        }
                }
index b16c07914b55bb0215592a7727e0974b62108dd6..1953e3d21abf28e112b13bdc5f60f03774d6a32e 100644 (file)
@@ -8,6 +8,19 @@
 #include <asm/memory.h>
 #include <asm/page.h>
        
+#define PROC_INFO                                                      \
+       VMLINUX_SYMBOL(__proc_info_begin) = .;                          \
+       *(.proc.info.init)                                              \
+       VMLINUX_SYMBOL(__proc_info_end) = .;
+
+#ifdef CONFIG_HOTPLUG_CPU
+#define ARM_CPU_DISCARD(x)
+#define ARM_CPU_KEEP(x)                x
+#else
+#define ARM_CPU_DISCARD(x)     x
+#define ARM_CPU_KEEP(x)
+#endif
+
 OUTPUT_ARCH(arm)
 ENTRY(stext)
 
@@ -31,15 +44,18 @@ SECTIONS
                        HEAD_TEXT
                        INIT_TEXT
                _einittext = .;
-               __proc_info_begin = .;
-                       *(.proc.info.init)
-               __proc_info_end = .;
+               ARM_CPU_DISCARD(PROC_INFO)
                __arch_info_begin = .;
                        *(.arch.info.init)
                __arch_info_end = .;
                __tagtable_begin = .;
                        *(.taglist.init)
                __tagtable_end = .;
+#ifdef CONFIG_SMP_ON_UP
+               __smpalt_begin = .;
+                       *(.alt.smp.init)
+               __smpalt_end = .;
+#endif
 
                INIT_SETUP(16)
 
@@ -68,10 +84,8 @@ SECTIONS
        /DISCARD/ : {
                *(.ARM.exidx.exit.text)
                *(.ARM.extab.exit.text)
-#ifndef CONFIG_HOTPLUG_CPU
-               *(.ARM.exidx.cpuexit.text)
-               *(.ARM.extab.cpuexit.text)
-#endif
+               ARM_CPU_DISCARD(*(.ARM.exidx.cpuexit.text))
+               ARM_CPU_DISCARD(*(.ARM.extab.cpuexit.text))
 #ifndef CONFIG_HOTPLUG
                *(.ARM.exidx.devexit.text)
                *(.ARM.extab.devexit.text)
@@ -100,12 +114,11 @@ SECTIONS
                        *(.glue_7)
                        *(.glue_7t)
                *(.got)                 /* Global offset table          */
+                       ARM_CPU_KEEP(PROC_INFO)
        }
 
        RO_DATA(PAGE_SIZE)
 
-       _etext = .;                     /* End of text and rodata section */
-
 #ifdef CONFIG_ARM_UNWIND
        /*
         * Stack unwinding tables
@@ -123,6 +136,8 @@ SECTIONS
        }
 #endif
 
+       _etext = .;                     /* End of text and rodata section */
+
 #ifdef CONFIG_XIP_KERNEL
        __data_loc = ALIGN(4);          /* location in binary */
        . = PAGE_OFFSET + TEXT_OFFSET;
@@ -237,6 +252,12 @@ SECTIONS
 
        /* Default discards */
        DISCARDS
+
+#ifndef CONFIG_SMP_ON_UP
+       /DISCARD/ : {
+               *(.alt.smp.init)
+       }
+#endif
 }
 
 /*
index 81a3ecc0d104d0eddc0eb74a7609c42b082aff75..0eb3e3e5b2d1154e16233d2b72386b349a849ac4 100644 (file)
@@ -95,8 +95,6 @@ static void __init aaed2000_map_io(void)
 
 MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform")
        /* Maintainer: Nicolas Bellido Y Ortega */
-       .phys_io        = PIO_BASE,
-       .io_pg_offst    = ((VIO_BASE) >> 18) & 0xfffc,
        .map_io         = aaed2000_map_io,
        .init_irq       = aaed2000_init_irq,
        .timer          = &aaec2000_timer,
index a9cac368bfe69f184c85ce7058ec29cfe10c83a2..bc7ad5561c4caee31fe32957ec297488b998c576 100644 (file)
  */
 
 #include "hardware.h"
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #0x80000000                @ physical
-               movne   \rx, #io_p2v(0x80000000)        @ virtual
-               orr     \rx, \rx, #0x00000800
+               .macro  addruart, rp, rv
+               mov     \rp, 0x00000800
+               orr     \rv, \rp, #io_p2v(0x80000000)   @ virtual
+               orr     \rp, \rp, #0x80000000           @ physical
                .endm
 
                .macro  senduart,rd,rx
index 551f68f666bf0273bb465272887cedfbe7244b94..cff4e0a996ce992953780bc1af4f11d72aff34f3 100644 (file)
@@ -11,6 +11,6 @@
 #ifndef __ASM_ARCH_VMALLOC_H
 #define __ASM_ARCH_VMALLOC_H
 
-#define VMALLOC_END            (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END            0xd0000000
 
 #endif /* __ASM_ARCH_VMALLOC_H */
index 939bccd70569846987c6ddb304cd22c7de730bf7..851e8139ef9d1a4c9511022696b10fc17a49ff52 100644 (file)
@@ -33,6 +33,7 @@ config ARCH_AT91SAM9260
        select HAVE_AT91_USART3
        select HAVE_AT91_USART4
        select HAVE_AT91_USART5
+       select HAVE_NET_MACB
 
 config ARCH_AT91SAM9261
        bool "AT91SAM9261"
@@ -51,6 +52,7 @@ config ARCH_AT91SAM9263
        select CPU_ARM926T
        select GENERIC_CLOCKEVENTS
        select HAVE_FB_ATMEL
+       select HAVE_NET_MACB
 
 config ARCH_AT91SAM9RL
        bool "AT91SAM9RL"
@@ -66,6 +68,7 @@ config ARCH_AT91SAM9G20
        select HAVE_AT91_USART3
        select HAVE_AT91_USART4
        select HAVE_AT91_USART5
+       select HAVE_NET_MACB
 
 config ARCH_AT91SAM9G45
        bool "AT91SAM9G45"
@@ -73,6 +76,7 @@ config ARCH_AT91SAM9G45
        select GENERIC_CLOCKEVENTS
        select HAVE_AT91_USART3
        select HAVE_FB_ATMEL
+       select HAVE_NET_MACB
 
 config ARCH_AT91CAP9
        bool "AT91CAP9"
@@ -248,6 +252,12 @@ config MACH_CPU9260
          Select this if you are using a Eukrea Electromatique's
          CPU9260 Board <http://www.eukrea.com/>
 
+config MACH_FLEXIBITY
+       bool "Flexibity Connect board"
+       help
+         Select this if you are using Flexibity Connect board
+         <http://www.flexibity.com>
+
 endif
 
 # ----------------------------------------------------------
@@ -338,6 +348,7 @@ config MACH_AT91SAM9G20EK
          that embeds only one SD/MMC slot.
 
 config MACH_AT91SAM9G20EK_2MMC
+       depends on MACH_AT91SAM9G20EK
        bool "Atmel AT91SAM9G20-EK Evaluation Kit with 2 SD/MMC Slots"
        select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
@@ -383,8 +394,8 @@ if ARCH_AT91SAM9G45
 
 comment "AT91SAM9G45 Board Type"
 
-config MACH_AT91SAM9G45EKES
-       bool "Atmel AT91SAM9G45-EKES Evaluation Kit"
+config MACH_AT91SAM9M10G45EK
+       bool "Atmel AT91SAM9M10G45-EK Evaluation Kits"
        select HAVE_NAND_ATMEL_BUSWIDTH_16
        help
          Select this if you are using Atmel's AT91SAM9G45-EKES Evaluation Kit.
index ca2ac003f41f5666fb8da8c1e23b34ab3e363ea6..412b3a471a4b43e4a6053c5f57deb822a0e14633 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_MACH_USB_A9260)  += board-usb-a9260.o
 obj-$(CONFIG_MACH_QIL_A9260)   += board-qil-a9260.o
 obj-$(CONFIG_MACH_AFEB9260)    += board-afeb-9260v1.o
 obj-$(CONFIG_MACH_CPU9260)     += board-cpu9krea.o
+obj-$(CONFIG_MACH_FLEXIBITY)   += board-flexibity.o
 
 # AT91SAM9261 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9261EK) += board-sam9261ek.o
@@ -61,7 +62,6 @@ obj-$(CONFIG_MACH_AT91SAM9RLEK)       += board-sam9rlek.o
 
 # AT91SAM9G20 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o
-obj-$(CONFIG_MACH_AT91SAM9G20EK_2MMC) += board-sam9g20ek-2slot-mmc.o
 obj-$(CONFIG_MACH_CPU9G20)     += board-cpu9krea.o
 obj-$(CONFIG_MACH_STAMP9G20)   += board-stamp9g20.o
 obj-$(CONFIG_MACH_PORTUXG20)   += board-stamp9g20.o
@@ -70,7 +70,7 @@ obj-$(CONFIG_MACH_PORTUXG20)  += board-stamp9g20.o
 obj-$(CONFIG_MACH_SNAPPER_9260)        += board-snapper9260.o
 
 # AT91SAM9G45 board-specific support
-obj-$(CONFIG_MACH_AT91SAM9G45EKES) += board-sam9m10g45ek.o
+obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o
 
 # AT91CAP9 board-specific support
 obj-$(CONFIG_MACH_AT91CAP9ADK) += board-cap9adk.o
index 9b27d167bff0c0e850f21bebf2994aaf4c84554d..46bdc82d3fbf9985310db451bb2cf8a6eb4b81f7 100644 (file)
@@ -92,8 +92,6 @@ static void __init onearm_board_init(void)
 
 MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = onearm_map_io,
index 50667bed7cc9f7eb1381b39802afb4b825aa1920..cba7f7771feed1b6fc2286b76a8b63ffbdc9f398 100644 (file)
@@ -218,8 +218,6 @@ static void __init afeb9260_board_init(void)
 
 MACHINE_START(AFEB9260, "Custom afeb9260 board")
        /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = afeb9260_map_io,
index 5daff277f53e0deaccfc8665d75613440ba7bbfa..3929f1c9e4e5ce0fe10bb8ba64c02d4eae27aaed 100644 (file)
@@ -216,7 +216,7 @@ static struct atmel_nand_data __initdata eb_nand_data = {
 /*     .rdy_pin        = AT91_PIN_PC16, */
        .enable_pin     = AT91_PIN_PA15,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
+#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
        .bus_width_16   = 1,
 #else
        .bus_width_16   = 0,
@@ -318,8 +318,6 @@ static void __init eb_board_init(void)
 
 MACHINE_START(AT572D940HFEB, "Atmel AT91D940HF-EB")
        /* Maintainer: Atmel <costa.antonior@gmail.com> */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = eb_map_io,
index 44eb9f764938985abd52f7d285ad1b456507594c..b54e3e6fceb6774df2318b663131625800b25b0a 100644 (file)
@@ -198,8 +198,6 @@ static void __init cam60_board_init(void)
 
 MACHINE_START(CAM60, "KwikByte CAM60")
        /* Maintainer: KwikByte */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = cam60_map_io,
index d6940870e403fb8d7e1e15bac38ed2e6a0e4899f..e7274440ead99f8970e2abc801d2d752dced6d90 100644 (file)
@@ -399,8 +399,6 @@ static void __init cap9adk_board_init(void)
 
 MACHINE_START(AT91CAP9ADK, "Atmel AT91CAP9A-DK")
        /* Maintainer: Stelian Pop <stelian.pop@leadtechdesign.com> */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = cap9adk_map_io,
index db1f9544d2e0f9af8cb9ef46b8a3d2a126408c27..2e74a19874d11a955d90909dbfec1983508896f8 100644 (file)
@@ -162,8 +162,6 @@ static void __init carmeva_board_init(void)
 
 MACHINE_START(CARMEVA, "Carmeva")
        /* Maintainer: Conitec Datasystems */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = carmeva_map_io,
index 4bc2e9f6ebb537e2b3bf168f90c74f6e15d3fd3b..3838594578f3539d395cfd74bd4f9a90f9c21940 100644 (file)
@@ -375,8 +375,6 @@ MACHINE_START(CPUAT9260, "Eukrea CPU9260")
 MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
 #endif
        /* Maintainer: Eric Benard - EUKREA Electromatique */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = cpu9krea_map_io,
index a28d99656190e23cb4d3bdc2648a579f8197bd43..2f4dd8cdd484a50c1276fd48dcc61b68b3519c24 100644 (file)
@@ -175,8 +175,6 @@ static void __init cpuat91_board_init(void)
 
 MACHINE_START(CPUAT91, "Eukrea")
        /* Maintainer: Eric Benard - EUKREA Electromatique */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = cpuat91_map_io,
index fea2529ebcf9c781acb131aa7a1517bfc20ca772..464839dc39bd4d1c9acc0d38d17559d84a897e32 100644 (file)
@@ -257,8 +257,6 @@ static void __init csb337_board_init(void)
 
 MACHINE_START(CSB337, "Cogent CSB337")
        /* Maintainer: Bill Gatliff */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = csb337_map_io,
index cfa3f04b22053e7d8d69d7f80fddbaf24a812ae7..431688c6141267f3227f034baa9c9dab2bd9d9d3 100644 (file)
@@ -138,8 +138,6 @@ static void __init csb637_board_init(void)
 
 MACHINE_START(CSB637, "Cogent CSB637")
        /* Maintainer: Bill Gatliff */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = csb637_map_io,
index 0fd0f5bc77ea56623e83a37440da77e33f683af2..e14f0e165680ed39b5a9be326e661b9b415cb1bd 100644 (file)
@@ -225,8 +225,6 @@ static void __init dk_board_init(void)
 
 MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
        /* Maintainer: SAN People/Atmel */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = dk_map_io,
index 528656761ff74d390ee8d5c4c71d467679164b83..6cf6566ae346610a78f29f7de0f0f698f7d16e09 100644 (file)
@@ -120,8 +120,6 @@ static void __init eb9200_board_init(void)
 }
 
 MACHINE_START(ATEB9200, "Embest ATEB9200")
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = eb9200_map_io,
index 1d69908617f07cdb18e58322f9c59fe61069da44..7b58c948a957e851c82b20ab9450fdc98925a78d 100644 (file)
@@ -168,8 +168,6 @@ static void __init ecb_at91board_init(void)
 
 MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
        /* Maintainer: emQbit.com */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = ecb_at91map_io,
index 295a96609e71753d8b073f2534913d86b1b44a13..a158a0ce458fb36d09a4afe58f184c0e428ed057 100644 (file)
@@ -148,8 +148,6 @@ static void __init eco920_board_init(void)
 
 MACHINE_START(ECO920, "eco920")
        /* Maintainer: Sascha Hauer */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = eco920_map_io,
index 4cdfaac8e590fe2397204d231c1091dde3571a85..56e92c4bbc2a3222c87ddda4c178b13b33bb75dc 100644 (file)
@@ -191,8 +191,6 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
        /* Maintainer: SAN People/Atmel */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = ek_map_io,
diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
new file mode 100644 (file)
index 0000000..c8a62dc
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * linux/arch/arm/mach-at91/board-flexibity.c
+ *
+ *  Copyright (C) 2010 Flexibity
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2006 Atmel
+ *
+ * This program is free software; you can redistribute 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/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/input.h>
+#include <linux/gpio.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/board.h>
+
+#include "generic.h"
+
+static void __init flexibity_map_io(void)
+{
+       /* Initialize processor: 18.432 MHz crystal */
+       at91sam9260_initialize(18432000);
+
+       /* DBGU on ttyS0. (Rx & Tx only) */
+       at91_register_uart(0, 0, 0);
+
+       /* set serial console to ttyS0 (ie, DBGU) */
+       at91_set_serial_console(0);
+}
+
+static void __init flexibity_init_irq(void)
+{
+       at91sam9260_init_interrupts(NULL);
+}
+
+/* USB Host port */
+static struct at91_usbh_data __initdata flexibity_usbh_data = {
+       .ports          = 2,
+};
+
+/* USB Device port */
+static struct at91_udc_data __initdata flexibity_udc_data = {
+       .vbus_pin       = AT91_PIN_PC5,
+       .pullup_pin     = 0,            /* pull-up driven by UDC */
+};
+
+/* SPI devices */
+static struct spi_board_info flexibity_spi_devices[] = {
+       {       /* DataFlash chip */
+               .modalias       = "mtd_dataflash",
+               .chip_select    = 1,
+               .max_speed_hz   = 15 * 1000 * 1000,
+               .bus_num        = 0,
+       },
+};
+
+/* MCI (SD/MMC) */
+static struct at91_mmc_data __initdata flexibity_mmc_data = {
+       .slot_b         = 0,
+       .wire4          = 1,
+       .det_pin        = AT91_PIN_PC9,
+       .wp_pin         = AT91_PIN_PC4,
+};
+
+/* LEDs */
+static struct gpio_led flexibity_leds[] = {
+       {
+               .name                   = "usb1:green",
+               .gpio                   = AT91_PIN_PA12,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb1:red",
+               .gpio                   = AT91_PIN_PA13,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb2:green",
+               .gpio                   = AT91_PIN_PB26,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb2:red",
+               .gpio                   = AT91_PIN_PB27,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb3:green",
+               .gpio                   = AT91_PIN_PC8,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb3:red",
+               .gpio                   = AT91_PIN_PC6,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb4:green",
+               .gpio                   = AT91_PIN_PB4,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       },
+       {
+               .name                   = "usb4:red",
+               .gpio                   = AT91_PIN_PB5,
+               .active_low             = 1,
+               .default_trigger        = "default-on",
+       }
+};
+
+static void __init flexibity_board_init(void)
+{
+       /* Serial */
+       at91_add_device_serial();
+       /* USB Host */
+       at91_add_device_usbh(&flexibity_usbh_data);
+       /* USB Device */
+       at91_add_device_udc(&flexibity_udc_data);
+       /* SPI */
+       at91_add_device_spi(flexibity_spi_devices,
+               ARRAY_SIZE(flexibity_spi_devices));
+       /* MMC */
+       at91_add_device_mmc(0, &flexibity_mmc_data);
+       /* LEDs */
+       at91_gpio_leds(flexibity_leds, ARRAY_SIZE(flexibity_leds));
+}
+
+MACHINE_START(FLEXIBITY, "Flexibity Connect")
+       /* Maintainer: Maxim Osipov */
+       .boot_params    = AT91_SDRAM_BASE + 0x100,
+       .timer          = &at91sam926x_timer,
+       .map_io         = flexibity_map_io,
+       .init_irq       = flexibity_init_irq,
+       .init_machine   = flexibity_board_init,
+MACHINE_END
index a87956c0a74f325adb7d5b9e6247b47ff691b071..c0ce79d431a0c1f3424b232e6a746b40c9f5dc5c 100644 (file)
@@ -99,8 +99,6 @@ static void __init kafa_board_init(void)
 
 MACHINE_START(KAFA, "Sperry-Sun KAFA")
        /* Maintainer: Sergei Sharonov */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = kafa_map_io,
index fe9b9913fa3cd98eeacf1604b76351fa7de5d24a..a13d2063faff8e43dfeedab3531010e0118887b2 100644 (file)
@@ -136,8 +136,6 @@ static void __init kb9202_board_init(void)
 
 MACHINE_START(KB9200, "KB920x")
        /* Maintainer: KwikByte, Inc. */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = kb9202_map_io,
index 7c1e382330fb61de9efabe094b8bdfdbf1481e55..fe5f1d47e6e23884eb2ac6d3ab00d36aa264aba0 100644 (file)
@@ -387,8 +387,6 @@ static void __init neocore926_board_init(void)
 
 MACHINE_START(NEOCORE926, "ADENEO NEOCORE 926")
        /* Maintainer: ADENEO */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = neocore926_map_io,
index 859727e7ea301adeb807246c98bb7d2df812f51b..9d833bbc592dcf3c10cfd4233140dd0ec34db8ff 100644 (file)
@@ -156,8 +156,6 @@ static void __init picotux200_board_init(void)
 
 MACHINE_START(PICOTUX2XX, "picotux 200")
        /* Maintainer: Kleinhenz Elektronik GmbH */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = picotux200_map_io,
index 664938e8f6611857c8007251f495a1426375fe26..69d15a875b667f34a68ba4332db47c5a4f6bef4c 100644 (file)
@@ -268,8 +268,6 @@ static void __init ek_board_init(void)
 
 MACHINE_START(QIL_A9260, "CALAO QIL_A9260")
        /* Maintainer: calao-systems */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = ek_map_io,
index b4834697753499278b85aea36c710d990dd9ce49..25a26beaa728bbee99a15174925a73532ddad949 100644 (file)
@@ -212,8 +212,6 @@ static void __init ek_board_init(void)
 
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
        /* Maintainer: Olimex */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = ek_map_io,
index ba9d501b5c50a83166ba7f2ed8f53f4681a64125..de1816e0e1d967c87825bf6c4de11c8370aaf057 100644 (file)
@@ -356,8 +356,6 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
        /* Maintainer: Atmel */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = ek_map_io,
index 65eb0943194f4b0ea4ea65613435ceef4d875c75..14acc901e24cdd97ca4c939f5ae3bcfba189feff 100644 (file)
@@ -623,8 +623,6 @@ MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK")
 MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
 #endif
        /* Maintainer: Atmel */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = ek_map_io,
index 2d867fb0630f0719723b9aa0fde5ab416725ae5f..bfe490df58be9edf63ab20b001ccaf94c368ccd1 100644 (file)
@@ -454,8 +454,6 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
        /* Maintainer: Atmel */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = ek_map_io,
diff --git a/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c b/arch/arm/mach-at91/board-sam9g20ek-2slot-mmc.c
deleted file mode 100644 (file)
index c49f5c0..0000000
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- *  Copyright (C) 2005 SAN People
- *  Copyright (C) 2008 Atmel
- *  Copyright (C) 2009 Rob Emanuele
- *
- * This program is free software; you can redistribute 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/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/at73c213.h>
-#include <linux/clk.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/consumer.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.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 <mach/board.h>
-#include <mach/gpio.h>
-#include <mach/at91sam9_smc.h>
-
-#include "sam9_smc.h"
-#include "generic.h"
-
-
-static void __init ek_map_io(void)
-{
-       /* Initialize processor: 18.432 MHz crystal */
-       at91sam9260_initialize(18432000);
-
-       /* DGBU on ttyS0. (Rx & Tx only) */
-       at91_register_uart(0, 0, 0);
-
-       /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
-       at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
-                          | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
-                          | ATMEL_UART_RI);
-
-       /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
-       at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
-       /* set serial console to ttyS0 (ie, DBGU) */
-       at91_set_serial_console(0);
-}
-
-static void __init ek_init_irq(void)
-{
-       at91sam9260_init_interrupts(NULL);
-}
-
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata ek_usbh_data = {
-       .ports          = 2,
-};
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata ek_udc_data = {
-       .vbus_pin       = AT91_PIN_PC5,
-       .pullup_pin     = 0,            /* pull-up driven by UDC */
-};
-
-
-/*
- * SPI devices.
- */
-static struct spi_board_info ek_spi_devices[] = {
-#if !(defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_AT91))
-       {       /* DataFlash chip */
-               .modalias       = "mtd_dataflash",
-               .chip_select    = 1,
-               .max_speed_hz   = 15 * 1000 * 1000,
-               .bus_num        = 0,
-       },
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
-       {       /* DataFlash card */
-               .modalias       = "mtd_dataflash",
-               .chip_select    = 0,
-               .max_speed_hz   = 15 * 1000 * 1000,
-               .bus_num        = 0,
-       },
-#endif
-#endif
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct at91_eth_data __initdata ek_macb_data = {
-       .phy_irq_pin    = AT91_PIN_PB0,
-       .is_rmii        = 1,
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata ek_nand_partition[] = {
-       {
-               .name   = "Bootstrap",
-               .offset = 0,
-               .size   = 4 * SZ_1M,
-       },
-       {
-               .name   = "Partition 1",
-               .offset = MTDPART_OFS_NXTBLK,
-               .size   = 60 * SZ_1M,
-       },
-       {
-               .name   = "Partition 2",
-               .offset = MTDPART_OFS_NXTBLK,
-               .size   = MTDPART_SIZ_FULL,
-       },
-};
-
-static struct mtd_partition * __init nand_partitions(int size, int *num_partitions)
-{
-       *num_partitions = ARRAY_SIZE(ek_nand_partition);
-       return ek_nand_partition;
-}
-
-/* det_pin is not connected */
-static struct atmel_nand_data __initdata ek_nand_data = {
-       .ale            = 21,
-       .cle            = 22,
-       .rdy_pin        = AT91_PIN_PC13,
-       .enable_pin     = AT91_PIN_PC14,
-       .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-       .bus_width_16   = 1,
-#else
-       .bus_width_16   = 0,
-#endif
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
-       .ncs_read_setup         = 0,
-       .nrd_setup              = 2,
-       .ncs_write_setup        = 0,
-       .nwe_setup              = 2,
-
-       .ncs_read_pulse         = 4,
-       .nrd_pulse              = 4,
-       .ncs_write_pulse        = 4,
-       .nwe_pulse              = 4,
-
-       .read_cycle             = 7,
-       .write_cycle            = 7,
-
-       .mode                   = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
-       .tdf_cycles             = 3,
-};
-
-static void __init ek_add_device_nand(void)
-{
-       /* setup bus-width (8 or 16) */
-       if (ek_nand_data.bus_width_16)
-               ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
-       else
-               ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
-       /* configure chip-select 3 (NAND) */
-       sam9_smc_configure(3, &ek_nand_smc_config);
-
-       at91_add_device_nand(&ek_nand_data);
-}
-
-
-/*
- * MCI (SD/MMC)
- * wp_pin is not connected
- */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
-static struct mci_platform_data __initdata ek_mmc_data = {
-       .slot[0] = {
-               .bus_width      = 4,
-               .detect_pin     = AT91_PIN_PC2,
-               .wp_pin         = -ENODEV,
-       },
-       .slot[1] = {
-               .bus_width      = 4,
-               .detect_pin     = AT91_PIN_PC9,
-               .wp_pin         = -ENODEV,
-       },
-
-};
-#else
-static struct at91_mmc_data __initdata ek_mmc_data = {
-       .slot_b         = 1,    /* Only one slot so use slot B */
-       .wire4          = 1,
-       .det_pin        = AT91_PIN_PC9,
-};
-#endif
-
-/*
- * LEDs
- */
-static struct gpio_led ek_leds[] = {
-       {       /* "bottom" led, green, userled1 to be defined */
-               .name                   = "ds5",
-               .gpio                   = AT91_PIN_PB8,
-               .active_low             = 1,
-               .default_trigger        = "none",
-       },
-       {       /* "power" led, yellow */
-               .name                   = "ds1",
-               .gpio                   = AT91_PIN_PB9,
-               .default_trigger        = "heartbeat",
-       }
-};
-
-#if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
-static struct regulator_consumer_supply ek_audio_consumer_supplies[] = {
-       REGULATOR_SUPPLY("AVDD", "0-001b"),
-       REGULATOR_SUPPLY("HPVDD", "0-001b"),
-       REGULATOR_SUPPLY("DBVDD", "0-001b"),
-       REGULATOR_SUPPLY("DCVDD", "0-001b"),
-};
-
-static struct regulator_init_data ek_avdd_reg_init_data = {
-       .constraints    = {
-               .name   = "3V3",
-               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
-       },
-       .consumer_supplies = ek_audio_consumer_supplies,
-       .num_consumer_supplies = ARRAY_SIZE(ek_audio_consumer_supplies),
-};
-
-static struct fixed_voltage_config ek_vdd_pdata = {
-       .supply_name    = "board-3V3",
-       .microvolts     = 3300000,
-       .gpio           = -EINVAL,
-       .enabled_at_boot = 0,
-       .init_data      = &ek_avdd_reg_init_data,
-};
-static struct platform_device ek_voltage_regulator = {
-       .name           = "reg-fixed-voltage",
-       .id             = -1,
-       .num_resources  = 0,
-       .dev            = {
-               .platform_data  = &ek_vdd_pdata,
-       },
-};
-static void __init ek_add_regulators(void)
-{
-       platform_device_register(&ek_voltage_regulator);
-}
-#else
-static void __init ek_add_regulators(void) {}
-#endif
-
-static struct i2c_board_info __initdata ek_i2c_devices[] = {
-       {
-               I2C_BOARD_INFO("24c512", 0x50),
-       },
-};
-
-
-static void __init ek_board_init(void)
-{
-       /* Serial */
-       at91_add_device_serial();
-       /* USB Host */
-       at91_add_device_usbh(&ek_usbh_data);
-       /* USB Device */
-       at91_add_device_udc(&ek_udc_data);
-       /* SPI */
-       at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
-       /* NAND */
-       ek_add_device_nand();
-       /* Ethernet */
-       at91_add_device_eth(&ek_macb_data);
-       /* Regulators */
-       ek_add_regulators();
-       /* MMC */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
-       at91_add_device_mci(0, &ek_mmc_data);
-#else
-       at91_add_device_mmc(0, &ek_mmc_data);
-#endif
-       /* I2C */
-       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 */
-       at91_set_B_periph(AT91_PIN_PC1, 0);
-       /* SSC (for WM8731) */
-       at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
-}
-
-MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
-       /* Maintainer: Rob Emanuele */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
-       .boot_params    = AT91_SDRAM_BASE + 0x100,
-       .timer          = &at91sam926x_timer,
-       .map_io         = ek_map_io,
-       .init_irq       = ek_init_irq,
-       .init_machine   = ek_board_init,
-MACHINE_END
index 6ea9808b8868d53a0c7cefd1926f921eadd82633..ca8198b3c168bb8a333dc3d08102b082a73e66c4 100644 (file)
 #include "sam9_smc.h"
 #include "generic.h"
 
+/*
+ * board revision encoding
+ * bit 0:
+ *     0 => 1 sd/mmc slot
+ *     1 => 2 sd/mmc slots connectors (board from revision C)
+ */
+#define HAVE_2MMC      (1 << 0)
+static int inline ek_have_2mmc(void)
+{
+       return machine_is_at91sam9g20ek_2mmc() || (system_rev & HAVE_2MMC);
+}
+
 
 static void __init ek_map_io(void)
 {
@@ -94,7 +106,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
  * SPI devices.
  */
 static struct spi_board_info ek_spi_devices[] = {
-#if !defined(CONFIG_MMC_AT91)
+#if !(defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_AT91))
        {       /* DataFlash chip */
                .modalias       = "mtd_dataflash",
                .chip_select    = 1,
@@ -121,6 +133,13 @@ static struct at91_eth_data __initdata ek_macb_data = {
        .is_rmii        = 1,
 };
 
+static void __init ek_add_device_macb(void)
+{
+       if (ek_have_2mmc())
+               ek_macb_data.phy_irq_pin = AT91_PIN_PB0;
+
+       at91_add_device_eth(&ek_macb_data);
+}
 
 /*
  * NAND flash
@@ -198,13 +217,36 @@ static void __init ek_add_device_nand(void)
 
 /*
  * MCI (SD/MMC)
- * det_pin, wp_pin and vcc_pin are not connected
+ * wp_pin and vcc_pin are not connected
  */
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+static struct mci_platform_data __initdata ek_mmc_data = {
+       .slot[1] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PC9,
+       },
+
+};
+#else
 static struct at91_mmc_data __initdata ek_mmc_data = {
-       .slot_b         = 1,
+       .slot_b         = 1,    /* Only one slot so use slot B */
        .wire4          = 1,
+       .det_pin        = AT91_PIN_PC9,
 };
+#endif
 
+static void __init ek_add_device_mmc(void)
+{
+#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+       if (ek_have_2mmc()) {
+               ek_mmc_data.slot[0].bus_width = 4;
+               ek_mmc_data.slot[0].detect_pin = AT91_PIN_PC2;
+       }
+       at91_add_device_mci(0, &ek_mmc_data);
+#else
+       at91_add_device_mmc(0, &ek_mmc_data);
+#endif
+}
 
 /*
  * LEDs
@@ -223,6 +265,15 @@ static struct gpio_led ek_leds[] = {
        }
 };
 
+static void __init ek_add_device_gpio_leds(void)
+{
+       if (ek_have_2mmc()) {
+               ek_leds[0].gpio = AT91_PIN_PB8;
+               ek_leds[1].gpio = AT91_PIN_PB9;
+       }
+
+       at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+}
 
 /*
  * GPIO Buttons
@@ -336,15 +387,15 @@ static void __init ek_board_init(void)
        /* NAND */
        ek_add_device_nand();
        /* Ethernet */
-       at91_add_device_eth(&ek_macb_data);
+       ek_add_device_macb();
        /* Regulators */
        ek_add_regulators();
        /* MMC */
-       at91_add_device_mmc(0, &ek_mmc_data);
+       ek_add_device_mmc();
        /* I2C */
        at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
        /* LEDs */
-       at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
+       ek_add_device_gpio_leds();
        /* Push Buttons */
        ek_add_device_buttons();
        /* PCK0 provides MCLK to the WM8731 */
@@ -355,8 +406,15 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
        /* Maintainer: Atmel */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+       .boot_params    = AT91_SDRAM_BASE + 0x100,
+       .timer          = &at91sam926x_timer,
+       .map_io         = ek_map_io,
+       .init_irq       = ek_init_irq,
+       .init_machine   = ek_board_init,
+MACHINE_END
+
+MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
+       /* Maintainer: Atmel */
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = ek_map_io,
index ee800595594d3fa790f6d4737f59d3c9c4b8c473..7913984f6de9bbc1163c987b654afb9d955e0e87 100644 (file)
@@ -135,7 +135,7 @@ static struct atmel_nand_data __initdata ek_nand_data = {
        .rdy_pin        = AT91_PIN_PC8,
        .enable_pin     = AT91_PIN_PC14,
        .partition_info = nand_partitions,
-#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
+#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
        .bus_width_16   = 1,
 #else
        .bus_width_16   = 0,
@@ -399,10 +399,8 @@ static void __init ek_board_init(void)
        at91_pwm_leds(ek_pwm_led, ARRAY_SIZE(ek_pwm_led));
 }
 
-MACHINE_START(AT91SAM9G45EKES, "Atmel AT91SAM9G45-EKES")
+MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
        /* Maintainer: Atmel */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = ek_map_io,
index 7ac20f3a2067d6f4eeac86fb5d7e922665b8b843..3bf3408e94c18f370d5edb3991f7a8ff6dd0b208 100644 (file)
@@ -329,8 +329,6 @@ static void __init ek_board_init(void)
 
 MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
        /* Maintainer: Atmel */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = ek_map_io,
index 2c08ae4ad3a137b93a3afccc9a6a5f7d6dba3e2c..0a99b3cedd7a433b44bb0b0177aa4b5742017307 100644 (file)
@@ -177,8 +177,6 @@ static void __init snapper9260_board_init(void)
 }
 
 MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = snapper9260_map_io,
index 87958274290f352c492c141c117269bbb01a5ede..5206eef4a67eba12e1b22bd7ae0faa48ce29271a 100644 (file)
@@ -294,8 +294,6 @@ static void __init stamp9g20_board_init(void)
 
 MACHINE_START(PORTUXG20, "taskit PortuxG20")
        /* Maintainer: taskit GmbH */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = portuxg20_map_io,
@@ -305,8 +303,6 @@ MACHINE_END
 
 MACHINE_START(STAMP9G20, "taskit Stamp9G20")
        /* Maintainer: taskit GmbH */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = stamp9g20_map_io,
index 905d6ef768078dd4e75f0ac2058c267091161315..07784baeae841f2d98709b71cc1fe45917b820f1 100644 (file)
@@ -228,8 +228,6 @@ static void __init ek_board_init(void)
 
 MACHINE_START(USB_A9260, "CALAO USB_A9260")
        /* Maintainer: calao-systems */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = ek_map_io,
index b6a3480383e58b19580417c705203637e7615438..b614508931fd92cc1b7b95a4da438d246cf5f86e 100644 (file)
@@ -244,8 +244,6 @@ static void __init ek_board_init(void)
 
 MACHINE_START(USB_A9263, "CALAO USB_A9263")
        /* Maintainer: calao-systems */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91sam926x_timer,
        .map_io         = ek_map_io,
index e22bf051f835a1485453c7e8dea1102160dc416a..89df00a9d2f72bfd768df2986db8d792fcd3c3d2 100644 (file)
@@ -594,8 +594,6 @@ static void __init yl9200_board_init(void)
 
 MACHINE_START(YL9200, "uCdragon YL-9200")
        /* Maintainer: S.Birtles */
-       .phys_io        = AT91_BASE_SYS,
-       .io_pg_offst    = (AT91_VA_BASE_SYS >> 18) & 0xfffc,
        .boot_params    = AT91_SDRAM_BASE + 0x100,
        .timer          = &at91rm9200_timer,
        .map_io         = yl9200_map_io,
index d34cdb8abdca652dfcc64523e089361ed3ff2c0e..063ac44a020423119b52749dc3c866b6dd7eb965 100644 (file)
 #define AT91_DBGU_CIDR (AT91_SF + 0)   /* CIDR in PS segment */
 #define AT91_DBGU_EXID (AT91_SF + 4)   /* EXID in PS segment */
 
+/*
+ * Support defines for the simple Power Controller module.
+ */
+#define        AT91_PS_CR      (AT91_PS + 0)   /* PS Control register */
+#define        AT91_PS_CR_CPU  (1 << 0)        /* CPU clock disable bit */
+
 #endif /* AT91X40_H */
index 9e750a1c1b5a80fbab076f70314f8ffd7f5a1bd2..0f959faf74a9ffe7eb9ddc02ee6d6fddebcae419 100644 (file)
 #include <mach/hardware.h>
 #include <mach/at91_dbgu.h>
 
-       .macro  addruart, rx, tmp
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                                         @ MMU enabled?
-       ldreq   \rx, =(AT91_BASE_SYS + AT91_DBGU)               @ System peripherals (phys address)
-       ldrne   \rx, =(AT91_VA_BASE_SYS + AT91_DBGU)            @ System peripherals (virt address)
+       .macro  addruart, rp, rv
+       ldr     \rp, =(AT91_BASE_SYS + AT91_DBGU)               @ System peripherals (phys address)
+       ldr     \rv, =(AT91_VA_BASE_SYS + AT91_DBGU)            @ System peripherals (virt address)
        .endm
 
        .macro  senduart,rd,rx
index ee8db152592e087c8fe986dd1c7d7e557d473ad4..36af14bc13bbbbc88aad80487b6d3cc85b924f0b 100644 (file)
@@ -32,7 +32,11 @@ static inline void arch_idle(void)
         * Disable the processor clock.  The processor will be automatically
         * re-enabled by an interrupt or by a reset.
         */
+#ifdef AT91_PS
+       at91_sys_write(AT91_PS_CR, AT91_PS_CR_CPU);
+#else
        at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK);
+#endif
 #ifndef CONFIG_CPU_ARM920T
        /*
         * Set the processor (CP15) into 'Wait for Interrupt' mode.
index 2f139196d63de611d4e00ff8d55e5994f375dcf4..73eb066d23292e5757f5592d711531eeca920888 100644 (file)
@@ -167,8 +167,6 @@ static void __init bcmring_fixup(struct machine_desc *desc,
 
 MACHINE_START(BCMRING, "BCMRING")
        /* Maintainer: Broadcom Corporation */
-       .phys_io = MM_IO_START,
-       .io_pg_offst = (MM_IO_BASE >> 18) & 0xfffc,
        .fixup = bcmring_fixup,
        .map_io = bcmring_map_io,
        .init_irq = bcmring_init_irq,
index 29c0a911df262f6d70b5c369afa4788c44f0c07a..77eb35c89cd02161ee1678b049b6d80490423c09 100644 (file)
@@ -691,7 +691,7 @@ int dma_init(void)
 
        memset(&gDMA, 0, sizeof(gDMA));
 
-       init_MUTEX_LOCKED(&gDMA.lock);
+       sema_init(&gDMA.lock, 0);
        init_waitqueue_head(&gDMA.freeChannelQ);
 
        /* Initialize the Hardware */
@@ -1574,7 +1574,7 @@ int dma_init_mem_map(DMA_MemMap_t *memMap)
 {
        memset(memMap, 0, sizeof(*memMap));
 
-       init_MUTEX(&memMap->lock);
+       sema_init(&memMap->lock, 1);
 
        return 0;
 }
index 35e2ead8395c5f05447bca5efeebd7c4e8d9cafe..3db3a09fd3986e7ee452997e75a13180a38475b1 100644 (file)
@@ -22,4 +22,4 @@
  * 0xe0000000 to 0xefffffff. This gives us 256 MB of vm space and handles
  * larger physical memory designs better.
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x30000000)
+#define VMALLOC_END       0xf0000000
index dc1c4939b0cedc6a03ad5cb7b8e9ba1e5e3f4dad..e3152631eb377e33490536729ae3656bf6575f24 100644 (file)
@@ -67,21 +67,21 @@ static void bcmring_unmask_irq2(unsigned int irq)
 }
 
 static struct irq_chip bcmring_irq0_chip = {
-       .typename = "ARM-INTC0",
+       .name = "ARM-INTC0",
        .ack = bcmring_mask_irq0,
        .mask = bcmring_mask_irq0,      /* mask a specific interrupt, blocking its delivery. */
        .unmask = bcmring_unmask_irq0,  /* unmaks an interrupt */
 };
 
 static struct irq_chip bcmring_irq1_chip = {
-       .typename = "ARM-INTC1",
+       .name = "ARM-INTC1",
        .ack = bcmring_mask_irq1,
        .mask = bcmring_mask_irq1,
        .unmask = bcmring_unmask_irq1,
 };
 
 static struct irq_chip bcmring_irq2_chip = {
-       .typename = "ARM-SINTC",
+       .name = "ARM-SINTC",
        .ack = bcmring_mask_irq2,
        .mask = bcmring_mask_irq2,
        .unmask = bcmring_unmask_irq2,
index 5f18eccdc7252a767c2c4e0bcf4a6167a8b0775a..4a74b2c959bd71391baf377f3e1c3d383fb9a944 100644 (file)
@@ -64,8 +64,6 @@ void __init autcpu12_map_io(void)
 
 MACHINE_START(AUTCPU12, "autronix autcpu12")
        /* Maintainer: Thomas Gleixner */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0020000,
        .map_io         = autcpu12_map_io,
        .init_irq       = clps711x_init_irq,
index 71a80b5b8ad6135eba4821251138c5e730c5ecf8..5a1689d48793c701ee462c277914335eb8a08325 100644 (file)
@@ -55,8 +55,6 @@ static void __init cdb89712_map_io(void)
 
 MACHINE_START(CDB89712, "Cirrus-CDB89712")
        /* Maintainer: Ray Lehtiniemi */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = cdb89712_map_io,
        .init_irq       = clps711x_init_irq,
index 8ada2018497871ef25d414c583af7fa0f0f41b51..16481cf3e931efe7754bf759386567dcbe277809 100644 (file)
@@ -56,8 +56,6 @@ static void __init ceiva_map_io(void)
 
 MACHINE_START(CEIVA, "CEIVA/Polaroid Photo MAX Digital Picture Frame")
        /* Maintainer: Rob Scott */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = ceiva_map_io,
        .init_irq       = clps711x_init_irq,
index 3c3bf45039ff05f44c122adbc3bb1cceded613ab..67b5abb4a60a803af7a714e7d082611c5014c4c8 100644 (file)
@@ -37,8 +37,6 @@ fixup_clep7312(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312")
        /* Maintainer: Nobody */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .fixup          = fixup_clep7312,
        .map_io         = clps711x_map_io,
index 4a7a2322979a17c3dcb833bf44122f8af51bba8a..98ca5b2e940dd6a8347d473fbfeae006e45272c2 100644 (file)
@@ -57,8 +57,6 @@ fixup_edb7211(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)")
        /* Maintainer: Jon McClintock */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0020100,   /* 0xc0000000 - 0xc001ffff can be video RAM */
        .fixup          = fixup_edb7211,
        .map_io         = edb7211_map_io,
index a696099aa4f8f22ddd32e836b4bbb124acdc4ea0..b1cb479e71e909df2228f964ac451bbed40b69f2 100644 (file)
@@ -75,8 +75,6 @@ fortunet_fixup(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(FORTUNET, "ARM-FortuNet")
        /* Maintainer: FortuNet Inc. */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf0000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000000,
        .fixup          = fortunet_fixup,
        .map_io         = clps711x_map_io,
index 072cc6b61ba30b7b6e363040b40d409e8a43e38f..507c6873b7ee7e3b297864838a9767c01e77807b 100644 (file)
 #include <mach/hardware.h>
 #include <asm/hardware/clps7111.h>
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #CLPS7111_PHYS_BASE
-               movne   \rx, #CLPS7111_VIRT_BASE
+               .macro  addruart, rp, rv
 #ifndef CONFIG_DEBUG_CLPS711X_UART2
-               add     \rx, \rx, #0x0000       @ UART1
+               mov     \rp, #0x0000    @ UART1
 #else
-               add     \rx, \rx, #0x1000       @ UART2
+               mov     \rp, #0x1000    @ UART2
 #endif
+               orr     \rv, \rp, #CLPS7111_VIRT_BASE
+               orr     \rp, \rp, #CLPS7111_PHYS_BASE
                .endm
 
                .macro  senduart,rd,rx
index ea6cc7beff287939e117cbc57beed7f3ffa5e155..30b3a287ed8865d897adccbfb2f318cfa4212e9b 100644 (file)
@@ -17,4 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000
index 0d94a30fd6fc84745555fc4daabdb5617db728a0..cefbce0480b95e0c6566a513f32c17ac030691b4 100644 (file)
@@ -89,8 +89,6 @@ static void __init p720t_map_io(void)
 
 MACHINE_START(P720T, "ARM-Prospector720T")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xff000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .fixup          = fixup_p720t,
        .map_io         = p720t_map_io,
index 9df8391fd78ac9ebfbb33425261ff9c631db79b1..90fe9ab8591db4f7d96744328c7026ba47dd73df 100644 (file)
@@ -142,8 +142,6 @@ static void __init cns3420_map_io(void)
 }
 
 MACHINE_START(CNS3420VB, "Cavium Networks CNS3420 Validation Board")
-       .phys_io        = CNS3XXX_UART0_BASE,
-       .io_pg_offst    = (CNS3XXX_UART0_BASE_VIRT >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = cns3420_map_io,
        .init_irq       = cns3xxx_init_irq,
index d16ce7eb00e9092a765bc7968e40f7e5d0fb5ee8..56d828634db5d82a81a711f27bed2f6e9d6ce4d8 100644 (file)
  * published by the Free Software Foundation.
  */
 
-               .macro  addruart,rx
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx,      #0x10000000
-               movne   \rx,      #0xf0000000   @ virtual base
-               orr     \rx, \rx, #0x00009000
+               .macro  addruart,rp,rv
+               mov     \rp, #0x00009000
+               orr     \rv, \rp, #0xf0000000   @ virtual base
+               orr     \rp, \rp, #0x10000000
                .endm
 
 #include <asm/hardware/debug-pl01x.S>
index c3994f341e4942869bf24e8c56075be61acda2fc..7f3cdbfc0fbb5229f25b360f4477f28968991cf3 100644 (file)
@@ -597,8 +597,6 @@ static void __init da830_evm_map_io(void)
 }
 
 MACHINE_START(DAVINCI_DA830_EVM, "DaVinci DA830/OMAP-L137 EVM")
-       .phys_io        = IO_PHYS,
-       .io_pg_offst    = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
        .boot_params    = (DA8XX_DDR_BASE + 0x100),
        .map_io         = da830_evm_map_io,
        .init_irq       = cp_intc_init,
index fdc2cc500fc6ba712db2e9b53d1f31439c153818..b26f5cbfce3e2f5f1d8b4e8ee47a5e138e1a2999 100644 (file)
@@ -817,8 +817,6 @@ static void __init da850_evm_map_io(void)
 }
 
 MACHINE_START(DAVINCI_DA850_EVM, "DaVinci DA850/OMAP-L138 EVM")
-       .phys_io        = IO_PHYS,
-       .io_pg_offst    = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
        .boot_params    = (DA8XX_DDR_BASE + 0x100),
        .map_io         = da850_evm_map_io,
        .init_irq       = cp_intc_init,
index a3191015efee04b4a4f4cc2907db4417a5b8dcb4..6e7cad13352ce6518fe6877bd5b184ab9c78ec59 100644 (file)
@@ -351,8 +351,6 @@ static __init void dm355_evm_init(void)
 }
 
 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     = davinci_irq_init,
index f1d8132cf0c3945c89a4828ec21c42485f6ec5a5..543f9911b281e86b086bf970cfedfdf48c7165f8 100644 (file)
@@ -270,8 +270,6 @@ static __init void dm355_leopard_init(void)
 }
 
 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     = davinci_irq_init,
index 84acef1d0b3d98be0797c1f4c439d58d77173ede..944a0cbaf5cb7cdbaf2fe3f29fbdead6b0174850 100644 (file)
@@ -613,8 +613,6 @@ static __init void dm365_evm_init(void)
 }
 
 MACHINE_START(DAVINCI_DM365_EVM, "DaVinci DM365 EVM")
-       .phys_io        = IO_PHYS,
-       .io_pg_offst    = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
        .boot_params    = (0x80000100),
        .map_io         = dm365_evm_map_io,
        .init_irq       = davinci_irq_init,
index 34c8b418cd726fc9baaf0b44c3b608c52349ee40..d59fba15ba8de949e6ae1142cada534219d6c4a3 100644 (file)
@@ -706,8 +706,6 @@ static __init void davinci_evm_init(void)
 
 MACHINE_START(DAVINCI_EVM, "DaVinci DM644x EVM")
        /* Maintainer: MontaVista Software <source@mvista.com> */
-       .phys_io      = IO_PHYS,
-       .io_pg_offst  = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
        .boot_params  = (DAVINCI_DDR_BASE + 0x100),
        .map_io       = davinci_evm_map_io,
        .init_irq     = davinci_irq_init,
index 4502f346b2b04fe45550bdd4dc4742281ce92aab..6890488fb92b4eb9e67af4138767e2f6efd3a60f 100644 (file)
@@ -786,8 +786,6 @@ void __init dm646x_board_setup_refclk(struct clk *clk)
 }
 
 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_irq_init,
@@ -796,8 +794,6 @@ MACHINE_START(DAVINCI_DM6467_EVM, "DaVinci DM646x EVM")
 MACHINE_END
 
 MACHINE_START(DAVINCI_DM6467TEVM, "DaVinci DM6467T 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_irq_init,
index 4c30e929bbf94231f53d6ee64178a148061961db..a4def889275ccbea6e7064377c2dc8e474a67c1d 100644 (file)
@@ -275,8 +275,6 @@ static __init void davinci_ntosd2_init(void)
 
 MACHINE_START(NEUROS_OSD2, "Neuros OSD2")
        /* Maintainer: Neuros Technologies <neuros@groups.google.com> */
-       .phys_io        = IO_PHYS,
-       .io_pg_offst    = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
        .boot_params    = (DAVINCI_DDR_BASE + 0x100),
        .map_io          = davinci_ntosd2_map_io,
        .init_irq       = davinci_irq_init,
index 23e664a1a802a2c3d22b058cccd8b221b337dabf..9bdf8aafcc840f8fc4f15e9e70a9f153db1ba9d2 100644 (file)
@@ -154,8 +154,6 @@ static __init void davinci_sffsdr_init(void)
 
 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_irq_init,
index fe2a9d9c8bb7bb37a20a6f1b7ded622aac444dc9..b4de35b78904a0fda72e13a2c702211c998cd3ac 100644 (file)
@@ -164,8 +164,6 @@ console_initcall(tnetv107x_evm_console_init);
 #endif
 
 MACHINE_START(TNETV107X, "TNETV107X EVM")
-       .phys_io        = TNETV107X_IO_BASE,
-       .io_pg_offst    = (TNETV107X_IO_VIRT >> 18) & 0xfffc,
        .boot_params    = (TNETV107X_DDR_BASE + 0x100),
        .map_io         = tnetv107x_init,
        .init_irq       = cp_intc_init,
index f761dfdb8689b3f191e784b228731d2eff12fbe0..9f1befc5ac387d2d0124c080c88458a67dc0b30f 100644 (file)
@@ -29,35 +29,39 @@ davinci_uart_phys:  .word   0
 davinci_uart_virt:     .word   0
                .popsection
 
-               .macro addruart, rx, tmp
+               .macro addruart, rp, rv
 
                /* Use davinci_uart_phys/virt if already configured */
-10:            mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               ldreq   \rx, =__virt_to_phys(davinci_uart_phys)
-               ldrne   \rx, =davinci_uart_virt
-               ldr     \rx, [\rx]
-               cmp     \rx, #0                 @ is port configured?
+10:            mrc     p15, 0, \rp, c1, c0
+               tst     \rp, #1                 @ MMU enabled?
+               ldreq   \rp, =__virt_to_phys(davinci_uart_phys)
+               ldrne   \rp, =davinci_uart_phys
+               add     \rv, \rp, #4            @ davinci_uart_virt
+               ldr     \rp, [\rp, #0]
+               ldr     \rv, [\rv, #0]
+               cmp     \rp, #0                 @ is port configured?
+               cmpne   \rv, #0
                bne     99f                     @ already configured
 
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
+               /* Check the debug UART address set in uncompress.h */
+               mrc     p15, 0, \rp, c1, c0
+               tst     \rp, #1                 @ MMU enabled?
 
                /* Copy uart phys address from decompressor uart info */
-               ldreq   \tmp, =__virt_to_phys(davinci_uart_phys)
-               ldrne   \tmp, =davinci_uart_phys
-               ldreq   \rx, =DAVINCI_UART_INFO
-               ldrne   \rx, =__phys_to_virt(DAVINCI_UART_INFO)
-               ldr     \rx, [\rx, #0]
-               str     \rx, [\tmp]
+               ldreq   \rv, =__virt_to_phys(davinci_uart_phys)
+               ldrne   \rv, =davinci_uart_phys
+               ldreq   \rp, =DAVINCI_UART_INFO
+               ldrne   \rp, =__phys_to_virt(DAVINCI_UART_INFO)
+               ldr     \rp, [\rp, #0]
+               str     \rp, [\rv]
 
                /* Copy uart virt address from decompressor uart info */
-               ldreq   \tmp, =__virt_to_phys(davinci_uart_virt)
-               ldrne   \tmp, =davinci_uart_virt
-               ldreq   \rx, =DAVINCI_UART_INFO
-               ldrne   \rx, =__phys_to_virt(DAVINCI_UART_INFO)
-               ldr     \rx, [\rx, #4]
-               str     \rx, [\tmp]
+               ldreq   \rv, =__virt_to_phys(davinci_uart_virt)
+               ldrne   \rv, =davinci_uart_virt
+               ldreq   \rp, =DAVINCI_UART_INFO
+               ldrne   \rp, =__phys_to_virt(DAVINCI_UART_INFO)
+               ldr     \rp, [\rp, #4]
+               str     \rp, [\rv]
 
                b       10b
 99:
index bef70460fbc669353907355d3b9ca04f0a8308f3..95925aa76dd9483fe2c556e706981530b85f9627 100644 (file)
@@ -94,8 +94,6 @@ static void __init dove_db_init(void)
 }
 
 MACHINE_START(DOVE_DB, "Marvell DB-MV88AP510-BP Development Board")
-       .phys_io        = DOVE_SB_REGS_PHYS_BASE,
-       .io_pg_offst    = ((DOVE_SB_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = dove_db_init,
        .map_io         = dove_map_io,
index 1521d13f1d14928a12a1a8b79ad4fd4d5037e3c1..da8bf2bad3b1df0036527ba11b9d1df5ee50bc80 100644 (file)
@@ -8,12 +8,11 @@
 
 #include <mach/bridge-regs.h>
 
-       .macro  addruart, rx, tmp
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                                 @ MMU enabled?
-       ldreq   \rx, =DOVE_SB_REGS_PHYS_BASE
-       ldrne   \rx, =DOVE_SB_REGS_VIRT_BASE
-       orr     \rx, \rx, #0x00012000
+       .macro  addruart, rp, rv
+       ldr     \rp, =DOVE_SB_REGS_PHYS_BASE
+       ldr     \rv, =DOVE_SB_REGS_VIRT_BASE
+       orr     \rp, \rp, #0x00012000
+       orr     \rv, \rv, #0x00012000
        .endm
 
 #define UART_SHIFT     2
index c7bc7fbb11a647800ee6b4fa032c14539eb3f70c..5df4099fc14fbd7798d521baf68a0da69aa0ba70 100644 (file)
@@ -280,8 +280,6 @@ arch_initcall(ebsa110_init);
 
 MACHINE_START(EBSA110, "EBSA110")
        /* Maintainer: Russell King */
-       .phys_io        = 0xe0000000,
-       .io_pg_offst    = ((0xe0000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000400,
        .reserve_lp0    = 1,
        .reserve_lp2    = 1,
index ebbd89f0e6c0e8967171396e4113e82c6826d266..7ef5690fd08c876cc27366d0b38451988daf066c 100644 (file)
  *
 **/
 
-               .macro  addruart, rx, tmp
-               mov     \rx, #0xf0000000
-               orr     \rx, \rx, #0x00000be0
+               .macro  addruart, rp, rv
+               mov     \rp, #0xf0000000
+               orr     \rp, \rp, #0x00000be0
+               mov     \rp, \rv
                .endm
 
 #define UART_SHIFT     2
index 9b44c19e95ec5167af7b5607ae5ff05a58e7e4f9..60bde56fba4cf3e4ef90cea65ceb2bf8e2db3111 100644 (file)
@@ -7,4 +7,4 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x1f000000)
+#define VMALLOC_END       0xdf000000
index f744f676783f3024c0d18be2bff733432b260d9c..61b98ce4b6735455e148cbf76f397d0a1331cc42 100644 (file)
@@ -33,8 +33,6 @@ static void __init adssphere_init_machine(void)
 
 MACHINE_START(ADSSPHERE, "ADS Sphere 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,
index c2ce9034ba87f5b856cb6e1cae89fb69060b8ffe..4b04316521318fb025c0821c9b4c63f52ae60f72 100644 (file)
@@ -124,8 +124,6 @@ static void __init edb93xx_init_machine(void)
 #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,
@@ -137,8 +135,6 @@ MACHINE_END
 #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,
@@ -150,8 +146,6 @@ MACHINE_END
 #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,
@@ -163,8 +157,6 @@ MACHINE_END
 #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,
@@ -176,8 +168,6 @@ MACHINE_END
 #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,
@@ -189,8 +179,6 @@ MACHINE_END
 #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,
@@ -202,8 +190,6 @@ MACHINE_END
 #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,
@@ -215,8 +201,6 @@ MACHINE_END
 #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,
index d97168c0ba336fa22179328b9dc72316807c13bb..9bd3152bff9a1257ec6410968ca6847d7f0a661d 100644 (file)
@@ -33,8 +33,6 @@ static void __init gesbc9312_init_machine(void)
 
 MACHINE_START(GESBC9312, "Glomation GESBC-9312-sx")
        /* 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,
index 5cd22444e2236ae8fb73e59641e8dd82347f0fdf..b25bc90763673df4551e1bf0b6935a1d31e126f0 100644 (file)
  */
 #include <mach/ep93xx-regs.h>
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                         @ MMU enabled?
-               ldreq   \rx, =EP93XX_APB_PHYS_BASE      @ Physical base
-               ldrne   \rx, =EP93XX_APB_VIRT_BASE      @ virtual base
-               orr     \rx, \rx, #0x000c0000
+               .macro  addruart, rp, rv
+               ldr     \rp, =EP93XX_APB_PHYS_BASE      @ Physical base
+               ldr     \rv, =EP93XX_APB_VIRT_BASE      @ virtual base
+               orr     \rp, \rp, #0x000c0000
+               orr     \rv, \rv, #0x000c0000
                .endm
 
 #include <asm/hardware/debug-pl01x.S>
index 2ba776320a8282e978d989eea0377d6511dc3ab7..7adea6258efeb01af639824f3e13b46da0b1fee5 100644 (file)
@@ -77,8 +77,6 @@ static void __init micro9_init_machine(void)
 #ifdef CONFIG_MACH_MICRO9H
 MACHINE_START(MICRO9, "Contec Micro9-High")
        /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
-       .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,
@@ -90,8 +88,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_MICRO9M
 MACHINE_START(MICRO9M, "Contec Micro9-Mid")
        /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = EP93XX_SDCE3_PHYS_BASE_ASYNC + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
@@ -103,8 +99,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_MICRO9L
 MACHINE_START(MICRO9L, "Contec Micro9-Lite")
        /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
-       .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,
@@ -116,8 +110,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_MICRO9S
 MACHINE_START(MICRO9S, "Contec Micro9-Slim")
        /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
-       .phys_io        = EP93XX_APB_PHYS_BASE,
-       .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = EP93XX_SDCE3_PHYS_BASE_ASYNC + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
index 5dded5884133f89e27898567a61163c583fa8f3d..f22ce8db7947b616f7f45cf7fe6cf7eeebec62f2 100644 (file)
@@ -65,8 +65,6 @@ static void __init simone_init_machine(void)
 
 MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
 /* Maintainer: Ryan Mallon <ryan@bluewatersys.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,
index a12c89301297f6bb32985854df3a404dcc18fc97..ac601fe2b448b4ec06d08817d193f5c57b1376bc 100644 (file)
@@ -163,8 +163,6 @@ static void __init snappercl15_init_machine(void)
 
 MACHINE_START(SNAPPER_CL15, "Bluewater Systems Snapper CL15")
        /* Maintainer: Ryan Mallon <ryan@bluewatersys.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,
index 93aeab8af705e8dd3dde989b1658e81e6ed60062..c2d2cf40ead920f323a717185b9fc715d704d96d 100644 (file)
@@ -257,8 +257,6 @@ static void __init ts72xx_init_machine(void)
 
 MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC")
        /* 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         = ts72xx_map_io,
        .init_irq       = ep93xx_init_irq,
index 1b996b26d2e0d06ee020a2fe2e763874536a9920..5b1a8db779be1dc733a985220ab626460783ff48 100644 (file)
@@ -86,8 +86,6 @@ fixup_cats(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(CATS, "Chalice-CATS")
        /* Maintainer: Philip Blundell */
-       .phys_io        = DC21285_ARMCSR_BASE,
-       .io_pg_offst    = ((0xfe000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .soft_reboot    = 1,
        .fixup          = fixup_cats,
index 30040fd588cc01661de7b4c01519c9d330e9f014..2ef69ff44ba8070daafeb9a7d9b9c325d33b72a0 100644 (file)
@@ -15,8 +15,6 @@
 
 MACHINE_START(EBSA285, "EBSA285")
        /* Maintainer: Russell King */
-       .phys_io        = DC21285_ARMCSR_BASE,
-       .io_pg_offst    = ((0xfe000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .video_start    = 0x000a0000,
        .video_end      = 0x000bffff,
index 60dda1318f2285785829c46c399889d5da495c89..3c9e0c40c679196ba02766ad7949ae1d504c1bf7 100644 (file)
 
 #ifndef CONFIG_DEBUG_DC21285_PORT
        /* For NetWinder debugging */
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #0x7c000000        @ physical
-               movne   \rx, #0xff000000        @ virtual
-               orr     \rx, \rx, #0x000003f8
+               .macro  addruart, rp, rv
+               mov     \rp, #0x000003f8
+               orr     \rv, \rp, #0x7c000000   @ physical
+               orr     \rp, \rp, #0xff000000   @ virtual
                .endm
 
 #define UART_SHIFT     0
                .equ    dc21285_high, ARMCSR_BASE & 0xff000000
                .equ    dc21285_low,  ARMCSR_BASE & 0x00ffffff
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #0x42000000
-               movne   \rx, #dc21285_high
+               .macro  addruart, rp, rv
                .if     dc21285_low
-               orrne   \rx, \rx, #dc21285_low
+               mov     \rp, #dc21285_low
+               .else
+               mov     \rp, #0
                .endif
+               orr     \rv, \rp, #0x42000000
+               orr     \rp, \rp, #dc21285_high
                .endm
 
                .macro  senduart,rd,rx
index d0958d860a3cb52f16f9464cf625c13498f3ec73..0ffbb7c85e59e738ce5d1966788ae72f52252ffe 100644 (file)
@@ -7,4 +7,4 @@
  */
 
 
-#define VMALLOC_END       (PAGE_OFFSET + 0x30000000)
+#define VMALLOC_END       0xf0000000
index ac7ffa6fc413e78a93a4e308cf1b137a39adc4fd..06e514f372d0f2a702d79d28963f48e18ac26aa6 100644 (file)
@@ -648,8 +648,6 @@ fixup_netwinder(struct machine_desc *desc, struct tag *tags,
 
 MACHINE_START(NETWINDER, "Rebel-NetWinder")
        /* Maintainer: Russell King/Rebel.com */
-       .phys_io        = DC21285_ARMCSR_BASE,
-       .io_pg_offst    = ((0xfe000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .video_start    = 0x000a0000,
        .video_end      = 0x000bffff,
index e2c9f0690b1622b69b5b3e828209ec86160809b6..3285e91ca8c1dcc53b9bff733cb1c181be431e53 100644 (file)
@@ -15,8 +15,6 @@
 
 MACHINE_START(PERSONAL_SERVER, "Compaq-PersonalServer")
        /* Maintainer: Jamey Hicks / George France */
-       .phys_io        = DC21285_ARMCSR_BASE,
-       .io_pg_offst    = ((0xfe000000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = footbridge_map_io,
        .init_irq       = footbridge_init_irq,
index 01f1d6daab448ccad6473d15e5555d20aac26bd2..2ba096de00348e2be706127107eb2b845d2e83a1 100644 (file)
@@ -101,8 +101,6 @@ static void __init ib4220b_init(void)
 }
 
 MACHINE_START(NAS4220B, "Raidsonic NAS IB-4220-B")
-       .phys_io        = 0x7fffc000,
-       .io_pg_offst    = ((0xffffc000) >> 18) & 0xfffc,
        .boot_params    = 0x100,
        .map_io         = gemini_map_io,
        .init_irq       = gemini_init_irq,
index e0de968e32a6e0eb24d98298557a471375b897f4..a9a0d8b0194296ab86072eb150fac5db5782af0e 100644 (file)
@@ -85,8 +85,6 @@ static void __init rut1xx_init(void)
 }
 
 MACHINE_START(RUT100, "Teltonika RUT100")
-       .phys_io        = 0x7fffc000,
-       .io_pg_offst    = ((0xffffc000) >> 18) & 0xfffc,
        .boot_params    = 0x100,
        .map_io         = gemini_map_io,
        .init_irq       = gemini_init_irq,
index 36538c15b3c4341b04062ffd663cb6240427ac37..8b88d50d4337db51378737a70bfd4bc2959b7b3b 100644 (file)
@@ -133,8 +133,6 @@ static void __init wbd111_init(void)
 }
 
 MACHINE_START(WBD111, "Wiliboard WBD-111")
-       .phys_io        = 0x7fffc000,
-       .io_pg_offst    = ((0xffffc000) >> 18) & 0xfffc,
        .boot_params    = 0x100,
        .map_io         = gemini_map_io,
        .init_irq       = gemini_init_irq,
index ece8b4c6511030f125ae67c10ffc35c4875c78a3..1eebcecd1c3312109213aba372cd915a2525961b 100644 (file)
@@ -133,8 +133,6 @@ static void __init wbd222_init(void)
 }
 
 MACHINE_START(WBD222, "Wiliboard WBD-222")
-       .phys_io        = 0x7fffc000,
-       .io_pg_offst    = ((0xffffc000) >> 18) & 0xfffc,
        .boot_params    = 0x100,
        .map_io         = gemini_map_io,
        .init_irq       = gemini_init_irq,
index ad477047069ddc9188e33657f3ad0b5338b83e11..f40e006d296e66d884d63525e25d7db45517f41c 100644 (file)
  */
 #include <mach/hardware.h>
 
-       .macro  addruart, rx, tmp
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                                 @ MMU enabled?
-       ldreq   \rx, =GEMINI_UART_BASE                  @ physical
-       ldrne   \rx, =IO_ADDRESS(GEMINI_UART_BASE)      @ virtual
+       .macro  addruart, rp, rv
+       ldr     \rp, =GEMINI_UART_BASE                  @ physical
+       ldr     \rv, =IO_ADDRESS(GEMINI_UART_BASE)      @ virtual
        .endm
 
 #define UART_SHIFT     2
index 78be457dc32431cc7e2c1a351a22286eb32d6669..79f0b896e446c6023ce53e2c6df71232c710644b 100644 (file)
@@ -30,8 +30,6 @@
 
 MACHINE_START(H7201, "Hynix GMS30C7201")
        /* Maintainer: Robert Schwebel, Pengutronix */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf0000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0001000,
        .map_io         = h720x_map_io,
        .init_irq       = h720x_init_irq,
index 8c0ba99d683fea6747cd9b39cb7ca6f4a68d796a..cc28b1efe0472e23e382a84ee016743f04e10995 100644 (file)
@@ -72,8 +72,6 @@ static void __init init_eval_h7202(void)
 
 MACHINE_START(H7202, "Hynix HMS30C7202")
        /* Maintainer: Robert Schwebel, Pengutronix */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf0000000) >> 18) & 0xfffc,
        .boot_params    = 0x40000100,
        .map_io         = h720x_map_io,
        .init_irq       = h7202_init_irq,
index 27cafd12f033cbba19bd507e5a90ac198c1db8e1..c2093e835720f55bc137362b3d12f8895f2a83b8 100644 (file)
                .equ    io_virt, IO_VIRT
                .equ    io_phys, IO_PHYS
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                @ MMU enabled?
-               moveq   \rx, #io_phys          @ physical base address
-               movne   \rx, #io_virt          @ virtual address
-               add     \rx, \rx, #0x00020000   @ UART1
+               .macro  addruart, rp, rv
+               mov     \rp, #0x00020000        @ UART1
+               add     \rv, \rp, #io_virt      @ virtual address
+               add     \rp, \rp, #io_phys      @ physical base address
                .endm
 
                .macro  senduart,rd,rx
index ff1460d6841ba9c76f85e54d11d0709c4de801a3..a45915b88756d4e8e786e653bba677c5e36488b0 100644 (file)
@@ -5,6 +5,6 @@
 #ifndef __ARCH_ARM_VMALLOC_H
 #define __ARCH_ARM_VMALLOC_H
 
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000
 
 #endif
index 2f7e2728970d66966a959542f106fb9a216860ea..197f9e241cffc36e06543fe1eadc60582955fd1a 100644 (file)
@@ -147,8 +147,8 @@ choice
        default MACH_EUKREA_MBIMX27_BASEBOARD
 
 config MACH_EUKREA_MBIMX27_BASEBOARD
-       prompt "Eukrea MBIMX27 development board"
-       bool
+       bool "Eukrea MBIMX27 development board"
+       select IMX_HAVE_PLATFORM_IMX_SSI
        select IMX_HAVE_PLATFORM_IMX_UART
        select IMX_HAVE_PLATFORM_SPI_IMX
        help
@@ -164,6 +164,15 @@ config MACH_MX27_3DS
          Include support for MX27PDK platform. This includes specific
          configurations for the board and its peripherals.
 
+config MACH_IMX27_VISSTRIM_M10
+       bool "Vista Silicon i.MX27 Visstrim_m10"
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       help
+         Include support for Visstrim_m10 platform and its different variants.
+         This includes specific configurations for the board and its
+         peripherals.
+
 config MACH_IMX27LITE
        bool "LogicPD MX27 LITEKIT platform"
        select IMX_HAVE_PLATFORM_IMX_UART
@@ -174,6 +183,7 @@ config MACH_IMX27LITE
 config MACH_PCA100
        bool "Phytec phyCARD-s (pca100)"
        select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_SSI
        select IMX_HAVE_PLATFORM_IMX_UART
        select IMX_HAVE_PLATFORM_MXC_NAND
        select IMX_HAVE_PLATFORM_SPI_IMX
index 46a9fdfbbd157101e22fbd19e1edb6d2c2d893af..5582692bb176958f89c67bd3b70d230b7664b536 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_MACH_PCM038) += mach-pcm038.o
 obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o
 obj-$(CONFIG_MACH_MX27_3DS) += mach-mx27_3ds.o
 obj-$(CONFIG_MACH_IMX27LITE) += mach-imx27lite.o
+obj-$(CONFIG_MACH_IMX27_VISSTRIM_M10) += mach-imx27_visstrim_m10.o
 obj-$(CONFIG_MACH_CPUIMX27) += mach-cpuimx27.o
 obj-$(CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD) += eukrea_mbimx27-baseboard.o
 obj-$(CONFIG_MACH_PCA100) += mach-pca100.o
index c05096c38301038292e9b9f6e0bb10990c31433e..daca30b2d5b1ad5d77c03e8166910a8b7ca5a066 100644 (file)
@@ -592,7 +592,7 @@ static struct clk_lookup lookups[] __initdata = {
        _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk)
        _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk)
        _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
-       _REGISTER_CLOCK("spi_imx.0", NULL, spi_clk)
+       _REGISTER_CLOCK("imx1-cspi.0", NULL, spi_clk)
        _REGISTER_CLOCK("imx-mmc.0", NULL, sdhc_clk)
        _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
        _REGISTER_CLOCK(NULL, "mshc", mshc_clk)
index bb419ef4d133bb7c12f962bad2c961b337247d4c..cf15ea516a72c4e177d1d4d66374ea0a4ed8676f 100644 (file)
@@ -1172,9 +1172,9 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "pwm", pwm_clk[0])
        _REGISTER_CLOCK(NULL, "sdhc1", sdhc_clk[0])
        _REGISTER_CLOCK(NULL, "sdhc2", sdhc_clk[1])
-       _REGISTER_CLOCK(NULL, "cspi1", cspi_clk[0])
-       _REGISTER_CLOCK(NULL, "cspi2", cspi_clk[1])
-       _REGISTER_CLOCK(NULL, "cspi3", cspi_clk[2])
+       _REGISTER_CLOCK("imx21-cspi.0", NULL, cspi_clk[0])
+       _REGISTER_CLOCK("imx21-cspi.1", NULL, cspi_clk[1])
+       _REGISTER_CLOCK("imx21-cspi.2", NULL, cspi_clk[2])
        _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0])
        _REGISTER_CLOCK(NULL, "csi", csi_clk[0])
        _REGISTER_CLOCK("imx21-hcd.0", NULL, usb_clk[0])
index 5a1aa15c8a16140f17e75ea451b5441c9c413d10..98a25bada783fef44c1c5911dcc5cd7ca7ab8c9a 100644 (file)
@@ -594,27 +594,27 @@ DEFINE_CLOCK(uart2_clk1,   0, PCCR1, 30, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(uart1_clk1,   0, PCCR1, 31, NULL, NULL, &ipg_clk);
 
 /* Clocks we cannot directly gate, but drivers need their rates */
-DEFINE_CLOCK(cspi1_clk,    0, 0,      0, NULL, &cspi1_clk1, &per2_clk);
-DEFINE_CLOCK(cspi2_clk,    1, 0,      0, NULL, &cspi2_clk1, &per2_clk);
-DEFINE_CLOCK(cspi3_clk,    2, 0,      0, NULL, &cspi13_clk1, &per2_clk);
-DEFINE_CLOCK(sdhc1_clk,    0, 0,      0, NULL, &sdhc1_clk1, &per2_clk);
-DEFINE_CLOCK(sdhc2_clk,    1, 0,      0, NULL, &sdhc2_clk1, &per2_clk);
-DEFINE_CLOCK(sdhc3_clk,    2, 0,      0, NULL, &sdhc3_clk1, &per2_clk);
-DEFINE_CLOCK(pwm_clk,      0, 0,      0, NULL, &pwm_clk1, &per1_clk);
-DEFINE_CLOCK(gpt1_clk,     0, 0,      0, NULL, &gpt1_clk1, &per1_clk);
-DEFINE_CLOCK(gpt2_clk,     1, 0,      0, NULL, &gpt2_clk1, &per1_clk);
-DEFINE_CLOCK(gpt3_clk,     2, 0,      0, NULL, &gpt3_clk1, &per1_clk);
-DEFINE_CLOCK(gpt4_clk,     3, 0,      0, NULL, &gpt4_clk1, &per1_clk);
-DEFINE_CLOCK(gpt5_clk,     4, 0,      0, NULL, &gpt5_clk1, &per1_clk);
-DEFINE_CLOCK(gpt6_clk,     5, 0,      0, NULL, &gpt6_clk1, &per1_clk);
-DEFINE_CLOCK(uart1_clk,    0, 0,      0, NULL, &uart1_clk1, &per1_clk);
-DEFINE_CLOCK(uart2_clk,    1, 0,      0, NULL, &uart2_clk1, &per1_clk);
-DEFINE_CLOCK(uart3_clk,    2, 0,      0, NULL, &uart3_clk1, &per1_clk);
-DEFINE_CLOCK(uart4_clk,    3, 0,      0, NULL, &uart4_clk1, &per1_clk);
-DEFINE_CLOCK(uart5_clk,    4, 0,      0, NULL, &uart5_clk1, &per1_clk);
-DEFINE_CLOCK(uart6_clk,    5, 0,      0, NULL, &uart6_clk1, &per1_clk);
-DEFINE_CLOCK1(lcdc_clk,    0, 0,      0, parent, &lcdc_clk1, &per3_clk);
-DEFINE_CLOCK1(csi_clk,     0, 0,      0, parent, &csi_clk1, &per4_clk);
+DEFINE_CLOCK(cspi1_clk,    0, NULL,   0, NULL, &cspi1_clk1, &per2_clk);
+DEFINE_CLOCK(cspi2_clk,    1, NULL,   0, NULL, &cspi2_clk1, &per2_clk);
+DEFINE_CLOCK(cspi3_clk,    2, NULL,   0, NULL, &cspi13_clk1, &per2_clk);
+DEFINE_CLOCK(sdhc1_clk,    0, NULL,   0, NULL, &sdhc1_clk1, &per2_clk);
+DEFINE_CLOCK(sdhc2_clk,    1, NULL,   0, NULL, &sdhc2_clk1, &per2_clk);
+DEFINE_CLOCK(sdhc3_clk,    2, NULL,   0, NULL, &sdhc3_clk1, &per2_clk);
+DEFINE_CLOCK(pwm_clk,      0, NULL,   0, NULL, &pwm_clk1, &per1_clk);
+DEFINE_CLOCK(gpt1_clk,     0, NULL,   0, NULL, &gpt1_clk1, &per1_clk);
+DEFINE_CLOCK(gpt2_clk,     1, NULL,   0, NULL, &gpt2_clk1, &per1_clk);
+DEFINE_CLOCK(gpt3_clk,     2, NULL,   0, NULL, &gpt3_clk1, &per1_clk);
+DEFINE_CLOCK(gpt4_clk,     3, NULL,   0, NULL, &gpt4_clk1, &per1_clk);
+DEFINE_CLOCK(gpt5_clk,     4, NULL,   0, NULL, &gpt5_clk1, &per1_clk);
+DEFINE_CLOCK(gpt6_clk,     5, NULL,   0, NULL, &gpt6_clk1, &per1_clk);
+DEFINE_CLOCK(uart1_clk,    0, NULL,   0, NULL, &uart1_clk1, &per1_clk);
+DEFINE_CLOCK(uart2_clk,    1, NULL,   0, NULL, &uart2_clk1, &per1_clk);
+DEFINE_CLOCK(uart3_clk,    2, NULL,   0, NULL, &uart3_clk1, &per1_clk);
+DEFINE_CLOCK(uart4_clk,    3, NULL,   0, NULL, &uart4_clk1, &per1_clk);
+DEFINE_CLOCK(uart5_clk,    4, NULL,   0, NULL, &uart5_clk1, &per1_clk);
+DEFINE_CLOCK(uart6_clk,    5, NULL,   0, NULL, &uart6_clk1, &per1_clk);
+DEFINE_CLOCK1(lcdc_clk,    0, NULL,   0, parent, &lcdc_clk1, &per3_clk);
+DEFINE_CLOCK1(csi_clk,     0, NULL,   0, parent, &csi_clk1, &per4_clk);
 
 #define _REGISTER_CLOCK(d, n, c) \
        { \
@@ -640,9 +640,9 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk)
        _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk)
        _REGISTER_CLOCK("mxc-mmc.2", NULL, sdhc3_clk)
-       _REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
-       _REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
-       _REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
+       _REGISTER_CLOCK("imx27-cspi.0", NULL, cspi1_clk)
+       _REGISTER_CLOCK("imx27-cspi.1", NULL, cspi2_clk)
+       _REGISTER_CLOCK("imx27-cspi.2", NULL, cspi3_clk)
        _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
        _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk)
index a8d94f078196cb2b14b74cb12170abc3546acb6b..81979486218ed0eb96f09a12ba078404f28ab595 100644 (file)
@@ -9,10 +9,12 @@
 #include <mach/mx1.h>
 #include <mach/devices-common.h>
 
-#define imx1_add_i2c_imx(pdata)                \
-       imx_add_imx_i2c(0, MX1_I2C_BASE_ADDR, SZ_4K, MX1_INT_I2C, pdata)
+extern const struct imx_imx_i2c_data imx1_imx_i2c_data __initconst;
+#define imx1_add_imx_i2c(pdata)                \
+       imx_add_imx_i2c(&imx1_imx_i2c_data, pdata)
 
-#define imx1_add_imx_uart0(pdata)      \
-       imx_add_imx_uart_3irq(0, MX1_UART1_BASE_ADDR, 0xd0, MX1_INT_UART1RX, MX1_INT_UART1TX, MX1_INT_UART1RTS, pdata)
-#define imx1_add_imx_uart1(pdata)      \
-       imx_add_imx_uart_3irq(0, MX1_UART2_BASE_ADDR, 0xd0, MX1_INT_UART2RX, MX1_INT_UART2TX, MX1_INT_UART2RTS, pdata)
+extern const struct imx_imx_uart_3irq_data imx1_imx_uart_data[] __initconst;
+#define imx1_add_imx_uart(id, pdata)   \
+       imx_add_imx_uart_3irq(&imx1_imx_uart_data[id], pdata)
+#define imx1_add_imx_uart0(pdata)      imx1_add_imx_uart(0, pdata)
+#define imx1_add_imx_uart1(pdata)      imx1_add_imx_uart(1, pdata)
index 42788e99d127290714f89af20d75859060f0bcd4..d189039749b0902a7d081a644b6e8d2e97a82a21 100644 (file)
@@ -9,22 +9,28 @@
 #include <mach/mx21.h>
 #include <mach/devices-common.h>
 
-#define imx21_add_i2c_imx(pdata)       \
-       imx_add_imx_i2c(0, MX2x_I2C_BASE_ADDR, SZ_4K, MX2x_INT_I2C, pdata)
+extern const struct imx_imx_i2c_data imx21_imx_i2c_data __initconst;
+#define imx21_add_imx_i2c(pdata)       \
+       imx_add_imx_i2c(&imx21_imx_i2c_data, pdata)
 
-#define imx21_add_imx_uart0(pdata)     \
-       imx_add_imx_uart_1irq(0, MX21_UART1_BASE_ADDR, SZ_4K, MX21_INT_UART1, pdata)
-#define imx21_add_imx_uart1(pdata)     \
-       imx_add_imx_uart_1irq(1, MX21_UART2_BASE_ADDR, SZ_4K, MX21_INT_UART2, pdata)
-#define imx21_add_imx_uart2(pdata)     \
-       imx_add_imx_uart_1irq(2, MX21_UART3_BASE_ADDR, SZ_4K, MX21_INT_UART3, pdata)
-#define imx21_add_imx_uart3(pdata)     \
-       imx_add_imx_uart_1irq(3, MX21_UART4_BASE_ADDR, SZ_4K, MX21_INT_UART4, pdata)
+extern const struct imx_imx_ssi_data imx21_imx_ssi_data[] __initconst;
+#define imx21_add_imx_ssi(id, pdata)   \
+       imx_add_imx_ssi(&imx21_imx_ssi_data[id], pdata)
 
+extern const struct imx_imx_uart_1irq_data imx21_imx_uart_data[] __initconst;
+#define imx21_add_imx_uart(id, pdata)  \
+       imx_add_imx_uart_1irq(&imx21_imx_uart_data[id], pdata)
+#define imx21_add_imx_uart0(pdata)     imx21_add_imx_uart(0, pdata)
+#define imx21_add_imx_uart1(pdata)     imx21_add_imx_uart(1, pdata)
+#define imx21_add_imx_uart2(pdata)     imx21_add_imx_uart(2, pdata)
+#define imx21_add_imx_uart3(pdata)     imx21_add_imx_uart(3, pdata)
+
+extern const struct imx_mxc_nand_data imx21_mxc_nand_data __initconst;
 #define imx21_add_mxc_nand(pdata)      \
-       imx_add_mxc_nand_v1(MX21_NFC_BASE_ADDR, MX21_INT_NANDFC, pdata)
+       imx_add_mxc_nand(&imx21_mxc_nand_data, pdata)
 
-#define imx21_add_spi_imx0(pdata)      \
-       imx_add_spi_imx(0, MX21_CSPI1_BASE_ADDR, SZ_4K, MX21_INT_CSPI1, pdata)
-#define imx21_add_spi_imx1(pdata)      \
-       imx_add_spi_imx(1, MX21_CSPI2_BASE_ADDR, SZ_4K, MX21_INT_CSPI2, pdata)
+extern const struct imx_spi_imx_data imx21_cspi_data[] __initconst;
+#define imx21_add_cspi(id, pdata)      \
+       imx_add_spi_imx(&imx21_cspi_data[id], pdata)
+#define imx21_add_spi_imx0(pdata)      imx21_add_cspi(0, pdata)
+#define imx21_add_spi_imx1(pdata)      imx21_add_cspi(1, pdata)
index 65e7bb7ec2e8864400445bb4dc1cc953503e1312..7011690364f270286b8e4bc06d3c58edc868c434 100644 (file)
@@ -9,30 +9,35 @@
 #include <mach/mx27.h>
 #include <mach/devices-common.h>
 
-#define imx27_add_i2c_imx0(pdata)      \
-       imx_add_imx_i2c(0, MX27_I2C1_BASE_ADDR, SZ_4K, MX27_INT_I2C1, pdata)
-#define imx27_add_i2c_imx1(pdata)      \
-       imx_add_imx_i2c(1, MX27_I2C2_BASE_ADDR, SZ_4K, MX27_INT_I2C2, pdata)
+extern const struct imx_fec_data imx27_fec_data __initconst;
+#define imx27_add_fec(pdata)   \
+       imx_add_fec(&imx27_fec_data, pdata)
 
-#define imx27_add_imx_uart0(pdata)     \
-       imx_add_imx_uart_1irq(0, MX27_UART1_BASE_ADDR, SZ_4K, MX27_INT_UART1, pdata)
-#define imx27_add_imx_uart1(pdata)     \
-       imx_add_imx_uart_1irq(1, MX27_UART2_BASE_ADDR, SZ_4K, MX27_INT_UART2, pdata)
-#define imx27_add_imx_uart2(pdata)     \
-       imx_add_imx_uart_1irq(2, MX27_UART3_BASE_ADDR, SZ_4K, MX27_INT_UART3, pdata)
-#define imx27_add_imx_uart3(pdata)     \
-       imx_add_imx_uart_1irq(3, MX27_UART4_BASE_ADDR, SZ_4K, MX27_INT_UART4, pdata)
-#define imx27_add_imx_uart4(pdata)     \
-       imx_add_imx_uart_1irq(4, MX27_UART5_BASE_ADDR, SZ_4K, MX27_INT_UART5, pdata)
-#define imx27_add_imx_uart5(pdata)     \
-       imx_add_imx_uart_1irq(5, MX27_UART6_BASE_ADDR, SZ_4K, MX27_INT_UART6, pdata)
+extern const struct imx_imx_i2c_data imx27_imx_i2c_data[] __initconst;
+#define imx27_add_imx_i2c(id, pdata)   \
+       imx_add_imx_i2c(&imx27_imx_i2c_data[id], pdata)
 
+extern const struct imx_imx_ssi_data imx27_imx_ssi_data[] __initconst;
+#define imx27_add_imx_ssi(id, pdata)    \
+       imx_add_imx_ssi(&imx27_imx_ssi_data[id], pdata)
+
+extern const struct imx_imx_uart_1irq_data imx27_imx_uart_data[] __initconst;
+#define imx27_add_imx_uart(id, pdata)  \
+       imx_add_imx_uart_1irq(&imx27_imx_uart_data[id], pdata)
+#define imx27_add_imx_uart0(pdata)     imx27_add_imx_uart(0, pdata)
+#define imx27_add_imx_uart1(pdata)     imx27_add_imx_uart(1, pdata)
+#define imx27_add_imx_uart2(pdata)     imx27_add_imx_uart(2, pdata)
+#define imx27_add_imx_uart3(pdata)     imx27_add_imx_uart(3, pdata)
+#define imx27_add_imx_uart4(pdata)     imx27_add_imx_uart(4, pdata)
+#define imx27_add_imx_uart5(pdata)     imx27_add_imx_uart(5, pdata)
+
+extern const struct imx_mxc_nand_data imx27_mxc_nand_data __initconst;
 #define imx27_add_mxc_nand(pdata)      \
-       imx_add_mxc_nand_v1(MX27_NFC_BASE_ADDR, MX27_INT_NANDFC, pdata)
+       imx_add_mxc_nand(&imx27_mxc_nand_data, pdata)
 
-#define imx27_add_spi_imx0(pdata)      \
-       imx_add_spi_imx(0, MX27_CSPI1_BASE_ADDR, SZ_4K, MX27_INT_CSPI1, pdata)
-#define imx27_add_spi_imx1(pdata)      \
-       imx_add_spi_imx(1, MX27_CSPI2_BASE_ADDR, SZ_4K, MX27_INT_CSPI2, pdata)
-#define imx27_add_spi_imx2(pdata)      \
-       imx_add_spi_imx(2, MX27_CSPI3_BASE_ADDR, SZ_4K, MX27_INT_CSPI3, pdata)
+extern const struct imx_spi_imx_data imx27_cspi_data[] __initconst;
+#define imx27_add_cspi(id, pdata)      \
+       imx_add_spi_imx(&imx27_cspi_data[id], pdata)
+#define imx27_add_spi_imx0(pdata)      imx27_add_cspi(0, pdata)
+#define imx27_add_spi_imx1(pdata)      imx27_add_cspi(1, pdata)
+#define imx27_add_spi_imx2(pdata)      imx27_add_cspi(2, pdata)
index 9c271a752b84da4e0380bf9fed2c86a5658a9640..fba5047de8b1fde5ee532f6291bcfee700257a66 100644 (file)
@@ -314,27 +314,6 @@ struct platform_device mxc_fb_device = {
        },
 };
 
-#ifdef CONFIG_MACH_MX27
-static struct resource mxc_fec_resources[] = {
-       {
-               .start = MX27_FEC_BASE_ADDR,
-               .end = MX27_FEC_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX27_INT_FEC,
-               .end = MX27_INT_FEC,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_fec_device = {
-       .name = "fec",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_fec_resources),
-       .resource = mxc_fec_resources,
-};
-#endif
-
 static struct resource mxc_pwm_resources[] = {
        {
                .start = MX2x_PWM_BASE_ADDR,
@@ -480,41 +459,6 @@ struct platform_device mxc_usbh2 = {
 };
 #endif
 
-#define DEFINE_IMX_SSI_DMARES(_name, ssin, suffix)                     \
-       {                                                               \
-               .name = _name,                                          \
-               .start = MX2x_DMA_REQ_SSI ## ssin ## _ ## suffix,       \
-               .end = MX2x_DMA_REQ_SSI ## ssin ## _ ## suffix,         \
-               .flags = IORESOURCE_DMA,                                \
-       }
-
-#define DEFINE_IMX_SSI_DEVICE(n, ssin, baseaddr, irq)                  \
-       static struct resource imx_ssi_resources ## n[] = {             \
-               {                                                       \
-                       .start = MX2x_SSI ## ssin ## _BASE_ADDR,        \
-                       .end = MX2x_SSI ## ssin ## _BASE_ADDR + 0x6f,   \
-                       .flags = IORESOURCE_MEM,                        \
-               }, {                                                    \
-                       .start = MX2x_INT_SSI1,                         \
-                       .end = MX2x_INT_SSI1,                           \
-                       .flags = IORESOURCE_IRQ,                        \
-               },                                                      \
-               DEFINE_IMX_SSI_DMARES("tx0", ssin, TX0),                \
-               DEFINE_IMX_SSI_DMARES("rx0", ssin, RX0),                \
-               DEFINE_IMX_SSI_DMARES("tx1", ssin, TX1),                \
-               DEFINE_IMX_SSI_DMARES("rx1", ssin, RX1),                \
-       };                                                              \
-                                                                       \
-       struct platform_device imx_ssi_device ## n = {                  \
-               .name = "imx-ssi",                                      \
-               .id = n,                                                \
-               .num_resources = ARRAY_SIZE(imx_ssi_resources ## n),    \
-               .resource = imx_ssi_resources ## n,                     \
-       }
-
-DEFINE_IMX_SSI_DEVICE(0, 1, MX2x_SSI1_BASE_ADDR, MX2x_INT_SSI1);
-DEFINE_IMX_SSI_DEVICE(1, 2, MX2x_SSI1_BASE_ADDR, MX2x_INT_SSI1);
-
 /* GPIO port description */
 #define DEFINE_MXC_GPIO_PORT_IRQ(SOC, n, _irq)                         \
        {                                                               \
index efd4527506a5e661da74c95e9d756c0674ca3d33..807f02a031c9454ce3534e26f508cd34fdc2b36e 100644 (file)
@@ -16,7 +16,6 @@ extern struct platform_device mxc_gpt5;
 extern struct platform_device mxc_wdt;
 extern struct platform_device mxc_w1_master_device;
 extern struct platform_device mxc_fb_device;
-extern struct platform_device mxc_fec_device;
 extern struct platform_device mxc_pwm_device;
 extern struct platform_device mxc_sdhc_device0;
 extern struct platform_device mxc_sdhc_device1;
@@ -26,7 +25,5 @@ extern struct platform_device mxc_otg_host;
 extern struct platform_device mxc_usbh1;
 extern struct platform_device mxc_usbh2;
 extern struct platform_device mx21_usbhc_device;
-extern struct platform_device imx_ssi_device0;
-extern struct platform_device imx_ssi_device1;
 extern struct platform_device imx_kpp_device;
 #endif
index 4edc5f43920109011d6e8f8fd64234e3fe3cb992..026263c665cae060cfca17ca86ad2fb36c8c2cad 100644 (file)
 #include <mach/hardware.h>
 #include <mach/mmc.h>
 #include <mach/spi.h>
-#include <mach/ssi.h>
 #include <mach/audmux.h>
 
 #include "devices-imx27.h"
 #include "devices.h"
 
-static int eukrea_mbimx27_pins[] = {
+static const int eukrea_mbimx27_pins[] __initconst = {
        /* UART2 */
        PE3_PF_UART2_CTS,
        PE4_PF_UART2_RTS,
@@ -311,7 +310,8 @@ static struct imxmmc_platform_data sdhc_pdata = {
        .dat3_card_detect = 1,
 };
 
-struct imx_ssi_platform_data eukrea_mbimx27_ssi_pdata = {
+static const
+struct imx_ssi_platform_data eukrea_mbimx27_ssi_pdata __initconst = {
        .flags = IMX_SSI_DMA | IMX_SSI_USE_I2S_SLAVE,
 };
 
@@ -357,7 +357,7 @@ void __init eukrea_mbimx27_baseboard_init(void)
        i2c_register_board_info(0, eukrea_mbimx27_i2c_devices,
                                ARRAY_SIZE(eukrea_mbimx27_i2c_devices));
 
-       mxc_register_device(&imx_ssi_device0, &eukrea_mbimx27_ssi_pdata);
+       imx27_add_imx_ssi(0, &eukrea_mbimx27_ssi_pdata);
 
 #if defined(CONFIG_TOUCHSCREEN_ADS7846) \
        || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
index 6830afd1d2baf01bc60aa959d15841aed48e26a6..745ee60fb068fee9dca479142b0c283bf14659a6 100644 (file)
@@ -46,7 +46,7 @@
 #include "devices-imx27.h"
 #include "devices.h"
 
-static int eukrea_cpuimx27_pins[] = {
+static const int eukrea_cpuimx27_pins[] __initconst = {
        /* UART1 */
        PE12_PF_UART1_TXD,
        PE13_PF_UART1_RXD,
@@ -157,7 +157,6 @@ cpuimx27_nand_board_info __initconst = {
 
 static struct platform_device *platform_devices[] __initdata = {
        &eukrea_cpuimx27_nor_mtd_device,
-       &mxc_fec_device,
        &mxc_wdt,
        &mxc_w1_master_device,
 };
@@ -259,8 +258,9 @@ static void __init eukrea_cpuimx27_init(void)
        i2c_register_board_info(0, eukrea_cpuimx27_i2c_devices,
                                ARRAY_SIZE(eukrea_cpuimx27_i2c_devices));
 
-       imx27_add_i2c_imx0(&cpuimx27_i2c1_data);
+       imx27_add_imx_i2c(0, &cpuimx27_i2c1_data);
 
+       imx27_add_fec(NULL);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
 #if defined(CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2)
@@ -307,8 +307,6 @@ static struct sys_timer eukrea_cpuimx27_timer = {
 };
 
 MACHINE_START(CPUIMX27, "EUKREA CPUIMX27")
-       .phys_io        = MX27_AIPI_BASE_ADDR,
-       .io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX27_PHYS_OFFSET + 0x100,
        .map_io         = mx27_map_io,
        .init_irq       = mx27_init_irq,
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
new file mode 100644 (file)
index 0000000..59716fa
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * mach-imx27_visstrim_m10.c
+ *
+ * Copyright 2010  Javier Martin <javier.martin@vista-silicon.com>
+ *
+ * Based on mach-pcm038.c, mach-pca100.c, mach-mx27ads.c and others.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pca953x.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/common.h>
+#include <mach/mmc.h>
+#include <mach/iomux.h>
+#include <mach/mxc_ehci.h>
+
+#include "devices-imx27.h"
+#include "devices.h"
+
+#define OTG_PHY_CS_GPIO (GPIO_PORTF + 17)
+#define SDHC1_IRQ IRQ_GPIOB(25)
+
+static const int visstrim_m10_pins[] __initconst = {
+       /* UART1 (console) */
+       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,
+       /* 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,
+       /* Both I2Cs */
+       PD17_PF_I2C_DATA,
+       PD18_PF_I2C_CLK,
+       PC5_PF_I2C2_SDA,
+       PC6_PF_I2C2_SCL,
+       /* USB OTG */
+       OTG_PHY_CS_GPIO | GPIO_GPIO | GPIO_OUT,
+       PC9_PF_USBOTG_DATA0,
+       PC11_PF_USBOTG_DATA1,
+       PC10_PF_USBOTG_DATA2,
+       PC13_PF_USBOTG_DATA3,
+       PC12_PF_USBOTG_DATA4,
+       PC7_PF_USBOTG_DATA5,
+       PC8_PF_USBOTG_DATA6,
+       PE25_PF_USBOTG_DATA7,
+       PE24_PF_USBOTG_CLK,
+       PE2_PF_USBOTG_DIR,
+       PE0_PF_USBOTG_NXT,
+       PE1_PF_USBOTG_STP,
+       PB23_PF_USB_PWR,
+       PB24_PF_USB_OC,
+};
+
+/* GPIOs used as events for applications */
+static struct gpio_keys_button visstrim_gpio_keys[] = {
+       {
+               .type   = EV_KEY,
+               .code   = KEY_RESTART,
+               .gpio   = (GPIO_PORTC + 15),
+               .desc   = "Default config",
+               .active_low = 0,
+               .wakeup = 1,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_RECORD,
+               .gpio   = (GPIO_PORTF + 14),
+               .desc   = "Record",
+               .active_low = 0,
+               .wakeup = 1,
+       },
+       {
+               .type   = EV_KEY,
+               .code   = KEY_STOP,
+               .gpio   = (GPIO_PORTF + 13),
+               .desc   = "Stop",
+               .active_low = 0,
+               .wakeup = 1,
+       }
+};
+
+static struct gpio_keys_platform_data visstrim_gpio_keys_platform_data = {
+       .buttons        = visstrim_gpio_keys,
+       .nbuttons       = ARRAY_SIZE(visstrim_gpio_keys),
+};
+
+static struct platform_device visstrim_gpio_keys_device = {
+       .name   = "gpio-keys",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &visstrim_gpio_keys_platform_data,
+       },
+};
+
+/* Visstrim_SM10 has a microSD slot connected to sdhc1 */
+static int visstrim_m10_sdhc1_init(struct device *dev,
+               irq_handler_t detect_irq, void *data)
+{
+       int ret;
+
+       ret = request_irq(SDHC1_IRQ, detect_irq, IRQF_TRIGGER_FALLING,
+                               "mmc-detect", data);
+       return ret;
+}
+
+static void visstrim_m10_sdhc1_exit(struct device *dev, void *data)
+{
+       free_irq(SDHC1_IRQ, data);
+}
+
+static struct imxmmc_platform_data visstrim_m10_sdhc_pdata = {
+       .init = visstrim_m10_sdhc1_init,
+       .exit = visstrim_m10_sdhc1_exit,
+};
+
+/* Visstrim_SM10 NOR flash */
+static struct physmap_flash_data visstrim_m10_flash_data = {
+       .width = 2,
+};
+
+static struct resource visstrim_m10_flash_resource = {
+       .start = 0xc0000000,
+       .end = 0xc0000000 + SZ_64M - 1,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device visstrim_m10_nor_mtd_device = {
+       .name = "physmap-flash",
+       .id = 0,
+       .dev = {
+               .platform_data = &visstrim_m10_flash_data,
+       },
+       .num_resources = 1,
+       .resource = &visstrim_m10_flash_resource,
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+       &visstrim_gpio_keys_device,
+       &visstrim_m10_nor_mtd_device,
+};
+
+/* Visstrim_M10 uses UART0 as console */
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+/* I2C */
+static const struct imxi2c_platform_data visstrim_m10_i2c_data __initconst = {
+       .bitrate = 100000,
+};
+
+static struct pca953x_platform_data visstrim_m10_pca9555_pdata = {
+       .gpio_base = 240, /* After MX27 internal GPIOs */
+       .invert = 0,
+};
+
+static struct i2c_board_info visstrim_m10_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("pca9555", 0x20),
+               .platform_data = &visstrim_m10_pca9555_pdata,
+       },
+};
+
+/* USB OTG */
+static int otg_phy_init(struct platform_device *pdev)
+{
+       gpio_set_value(OTG_PHY_CS_GPIO, 0);
+       return 0;
+}
+
+static struct mxc_usbh_platform_data visstrim_m10_usbotg_pdata = {
+       .init = otg_phy_init,
+       .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT,
+       .flags  = MXC_EHCI_POWER_PINS_ENABLED,
+};
+
+static void __init visstrim_m10_board_init(void)
+{
+       int ret;
+
+       ret = mxc_gpio_setup_multiple_pins(visstrim_m10_pins,
+                       ARRAY_SIZE(visstrim_m10_pins), "VISSTRIM_M10");
+       if (ret)
+               pr_err("Failed to setup pins (%d)\n", ret);
+
+       imx27_add_imx_uart0(&uart_pdata);
+
+       i2c_register_board_info(0, visstrim_m10_i2c_devices,
+                               ARRAY_SIZE(visstrim_m10_i2c_devices));
+       imx27_add_imx_i2c(0, &visstrim_m10_i2c_data);
+       imx27_add_imx_i2c(1, &visstrim_m10_i2c_data);
+       mxc_register_device(&mxc_sdhc_device0, &visstrim_m10_sdhc_pdata);
+       mxc_register_device(&mxc_otg_host, &visstrim_m10_usbotg_pdata);
+       imx27_add_fec(NULL);
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
+
+static void __init visstrim_m10_timer_init(void)
+{
+       mx27_clocks_init((unsigned long)25000000);
+}
+
+static struct sys_timer visstrim_m10_timer = {
+       .init   = visstrim_m10_timer_init,
+};
+
+MACHINE_START(IMX27_VISSTRIM_M10, "Vista Silicon Visstrim_M10")
+       .boot_params    = MX27_PHYS_OFFSET + 0x100,
+       .map_io         = mx27_map_io,
+       .init_irq       = mx27_init_irq,
+       .init_machine   = visstrim_m10_board_init,
+       .timer          = &visstrim_m10_timer,
+MACHINE_END
index 22a2b5d912136590addc1fcd05f32d905b1af8d0..bbdbc75127d3fd6a09d03bcfad7562eb31808640 100644 (file)
@@ -27,7 +27,7 @@
 #include "devices-imx27.h"
 #include "devices.h"
 
-static unsigned int mx27lite_pins[] = {
+static const int mx27lite_pins[] __initconst = {
        /* UART1 */
        PE12_PF_UART1_TXD,
        PE13_PF_UART1_RXD,
@@ -58,16 +58,12 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
        .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");
        imx27_add_imx_uart0(&uart_pdata);
-       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+       imx27_add_fec(NULL);
 }
 
 static void __init mx27lite_timer_init(void)
@@ -80,8 +76,6 @@ static struct sys_timer mx27lite_timer = {
 };
 
 MACHINE_START(IMX27LITE, "LogicPD i.MX27LITE")
-       .phys_io        = MX27_AIPI_BASE_ADDR,
-       .io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX27_PHYS_OFFSET + 0x100,
        .map_io         = mx27_map_io,
        .init_irq       = mx27_init_irq,
index 77a760cfadc0260dba05324318e00e3d5605defd..6187ce9ba7d54157d0455cd304cc2ec1be650f77 100644 (file)
@@ -32,7 +32,7 @@
 #include "devices-imx1.h"
 #include "devices.h"
 
-static int mx1ads_pins[] = {
+static const int mx1ads_pins[] __initconst = {
        /* UART1 */
        PC9_PF_UART1_CTS,
        PC10_PF_UART1_RTS,
@@ -131,7 +131,7 @@ static void __init mx1ads_init(void)
        i2c_register_board_info(0, mx1ads_i2c_devices,
                                ARRAY_SIZE(mx1ads_i2c_devices));
 
-       imx1_add_i2c_imx(&mx1ads_i2c_data);
+       imx1_add_imx_i2c(&mx1ads_i2c_data);
 }
 
 static void __init mx1ads_timer_init(void)
@@ -145,8 +145,6 @@ struct sys_timer mx1ads_timer = {
 
 MACHINE_START(MX1ADS, "Freescale MX1ADS")
        /* Maintainer: Sascha Hauer, Pengutronix */
-       .phys_io        = MX1_IO_BASE_ADDR,
-       .io_pg_offst    = (MX1_IO_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX1_PHYS_OFFSET + 0x100,
        .map_io         = mx1_map_io,
        .init_irq       = mx1_init_irq,
@@ -155,8 +153,6 @@ MACHINE_START(MX1ADS, "Freescale MX1ADS")
 MACHINE_END
 
 MACHINE_START(MXLADS, "Freescale MXLADS")
-       .phys_io        = MX1_IO_BASE_ADDR,
-       .io_pg_offst    = (MX1_IO_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX1_PHYS_OFFSET + 0x100,
        .map_io         = mx1_map_io,
        .init_irq       = mx1_init_irq,
index 96d7f8189f3253a0feb79d0278c51abbc3e4e5bf..e1282e9f50ffe38f5861c48209a92b241686d324 100644 (file)
@@ -67,7 +67,7 @@
 #define MX21ADS_IO_LED4_ON      0x4000
 #define MX21ADS_IO_LED3_ON      0x8000
 
-static unsigned int mx21ads_pins[] = {
+static const int mx21ads_pins[] __initconst = {
 
        /* CS8900A */
        (GPIO_PORTE | GPIO_GPIO | GPIO_IN | 11),
@@ -314,8 +314,6 @@ static struct sys_timer mx21ads_timer = {
 
 MACHINE_START(MX21ADS, "Freescale i.MX21ADS")
        /* maintainer: Freescale Semiconductor, Inc. */
-       .phys_io        = MX21_AIPI_BASE_ADDR,
-       .io_pg_offst    = ((MX21_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX21_PHYS_OFFSET + 0x100,
        .map_io         = mx21ads_map_io,
        .init_irq       = mx21_init_irq,
index e66ffaa1c26c26dbd4ba2b7d7b75c2455b06f5a1..b8bbd31aa850c4332a602d92a79e0d8749afe4fb 100644 (file)
@@ -33,7 +33,7 @@
 #include "devices-imx27.h"
 #include "devices.h"
 
-static unsigned int mx27pdk_pins[] = {
+static const int mx27pdk_pins[] __initconst = {
        /* UART1 */
        PE12_PF_UART1_TXD,
        PE13_PF_UART1_RXD,
@@ -64,10 +64,6 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct platform_device *platform_devices[] __initdata = {
-       &mxc_fec_device,
-};
-
 /*
  * Matrix keyboard
  */
@@ -94,7 +90,7 @@ static void __init mx27pdk_init(void)
        mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins),
                "mx27pdk");
        imx27_add_imx_uart0(&uart_pdata);
-       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+       imx27_add_fec(NULL);
        mxc_register_device(&imx_kpp_device, &mx27_3ds_keymap_data);
 }
 
@@ -109,8 +105,6 @@ static struct sys_timer mx27pdk_timer = {
 
 MACHINE_START(MX27_3DS, "Freescale MX27PDK")
        /* maintainer: Freescale Semiconductor, Inc. */
-       .phys_io        = MX27_AIPI_BASE_ADDR,
-       .io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX27_PHYS_OFFSET + 0x100,
        .map_io         = mx27_map_io,
        .init_irq       = mx27_init_irq,
index 9c77da98a10eec59060e016088a63516a343aff2..a1e4bc573afc20081720fcb21cbd604e14ce5ff0 100644 (file)
@@ -66,7 +66,7 @@
 /* to determine the correct external crystal reference */
 #define CKIH_27MHZ_BIT_SET      (1 << 3)
 
-static unsigned int mx27ads_pins[] = {
+static const int mx27ads_pins[] __initconst = {
        /* UART0 */
        PE12_PF_UART1_TXD,
        PE13_PF_UART1_RXD,
@@ -284,7 +284,6 @@ static struct imxmmc_platform_data sdhc2_pdata = {
 
 static struct platform_device *platform_devices[] __initdata = {
        &mx27ads_nor_mtd_device,
-       &mxc_fec_device,
        &mxc_w1_master_device,
 };
 
@@ -308,11 +307,12 @@ static void __init mx27ads_board_init(void)
        /* only the i2c master 1 is used on this CPU card */
        i2c_register_board_info(1, mx27ads_i2c_devices,
                                ARRAY_SIZE(mx27ads_i2c_devices));
-       imx27_add_i2c_imx1(&mx27ads_i2c1_data);
+       imx27_add_imx_i2c(1, &mx27ads_i2c1_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);
 
+       imx27_add_fec(NULL);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
 
@@ -347,8 +347,6 @@ static void __init mx27ads_map_io(void)
 
 MACHINE_START(MX27ADS, "Freescale i.MX27ADS")
        /* maintainer: Freescale Semiconductor, Inc. */
-       .phys_io        = MX27_AIPI_BASE_ADDR,
-       .io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX27_PHYS_OFFSET + 0x100,
        .map_io         = mx27ads_map_io,
        .init_irq       = mx27_init_irq,
index a3a1e452d4c5a15bef12ced37d70d275fabd2fad..38d3a4ae17c765f2a4779e67f2ac9967cd130f12 100644 (file)
@@ -37,7 +37,7 @@
 #include "devices-imx27.h"
 #include "devices.h"
 
-static unsigned int mxt_td60_pins[] __initdata = {
+static const int mxt_td60_pins[] __initconst = {
        /* UART0 */
        PE12_PF_UART1_TXD,
        PE13_PF_UART1_RXD,
@@ -231,10 +231,6 @@ static struct imxmmc_platform_data sdhc1_pdata = {
        .exit = mxt_td60_sdhc1_exit,
 };
 
-static struct platform_device *platform_devices[] __initdata = {
-       &mxc_fec_device,
-};
-
 static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
@@ -255,12 +251,11 @@ static void __init mxt_td60_board_init(void)
        i2c_register_board_info(1, mxt_td60_i2c2_devices,
                                ARRAY_SIZE(mxt_td60_i2c2_devices));
 
-       imx27_add_i2c_imx0(&mxt_td60_i2c0_data);
-       imx27_add_i2c_imx1(&mxt_td60_i2c1_data);
+       imx27_add_imx_i2c(0, &mxt_td60_i2c0_data);
+       imx27_add_imx_i2c(1, &mxt_td60_i2c1_data);
        mxc_register_device(&mxc_fb_device, &mxt_td60_fb_data);
        mxc_register_device(&mxc_sdhc_device0, &sdhc1_pdata);
-
-       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+       imx27_add_fec(NULL);
 }
 
 static void __init mxt_td60_timer_init(void)
@@ -274,8 +269,6 @@ static struct sys_timer mxt_td60_timer = {
 
 MACHINE_START(MXT_TD60, "Maxtrack i-MXT TD60")
        /* maintainer: Maxtrack Industrial */
-       .phys_io        = MX27_AIPI_BASE_ADDR,
-       .io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX27_PHYS_OFFSET + 0x100,
        .map_io         = mx27_map_io,
        .init_irq       = mx27_init_irq,
index 23c9e1f37b9c022bee669908e7aeca791de3b4b4..8c720d44602ab1af61cd18b36316ec44e3613dcc 100644 (file)
@@ -38,7 +38,6 @@
 #include <mach/iomux-mx27.h>
 #include <asm/mach/time.h>
 #include <mach/audmux.h>
-#include <mach/ssi.h>
 #include <mach/mxc_nand.h>
 #include <mach/irqs.h>
 #include <mach/mmc.h>
@@ -55,7 +54,7 @@
 #define SPI1_SS1 (GPIO_PORTD + 27)
 #define SD2_CD (GPIO_PORTC + 29)
 
-static int pca100_pins[] = {
+static const int pca100_pins[] __initconst = {
        /* UART1 */
        PE12_PF_UART1_TXD,
        PE13_PF_UART1_RXD,
@@ -174,7 +173,6 @@ pca100_nand_board_info __initconst = {
 
 static struct platform_device *platform_devices[] __initdata = {
        &mxc_w1_master_device,
-       &mxc_fec_device,
        &mxc_wdt,
 };
 
@@ -193,11 +191,9 @@ static struct i2c_board_info pca100_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"
+               I2C_BOARD_INFO("pcf8563", 0x51),
        }, {
                I2C_BOARD_INFO("lm75", 0x4a),
-               .type = "lm75"
        }
 };
 
@@ -252,7 +248,7 @@ static void pca100_ac97_cold_reset(struct snd_ac97 *ac97)
        msleep(2);
 }
 
-static struct imx_ssi_platform_data pca100_ssi_pdata = {
+static const struct imx_ssi_platform_data pca100_ssi_pdata __initconst = {
        .ac97_reset             = pca100_ac97_cold_reset,
        .ac97_warm_reset        = pca100_ac97_warm_reset,
        .flags                  = IMX_SSI_USE_AC97,
@@ -389,7 +385,7 @@ static void __init pca100_init(void)
        if (ret)
                printk(KERN_ERR "pca100: Failed to setup pins (%d)\n", ret);
 
-       mxc_register_device(&imx_ssi_device0, &pca100_ssi_pdata);
+       imx27_add_imx_ssi(0, &pca100_ssi_pdata);
 
        imx27_add_imx_uart0(&uart_pdata);
 
@@ -401,7 +397,7 @@ static void __init pca100_init(void)
        i2c_register_board_info(1, pca100_i2c_devices,
                                ARRAY_SIZE(pca100_i2c_devices));
 
-       imx27_add_i2c_imx1(&pca100_i2c1_data);
+       imx27_add_imx_i2c(1, &pca100_i2c1_data);
 
 #if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
        mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_IN);
@@ -436,6 +432,7 @@ static void __init pca100_init(void)
 
        mxc_register_device(&mxc_fb_device, &pca100_fb_data);
 
+       imx27_add_fec(NULL);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 }
 
@@ -449,8 +446,6 @@ static struct sys_timer pca100_timer = {
 };
 
 MACHINE_START(PCA100, "phyCARD-i.MX27")
-       .phys_io        = MX27_AIPI_BASE_ADDR,
-       .io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX27_PHYS_OFFSET + 0x100,
        .map_io         = mx27_map_io,
        .init_irq       = mx27_init_irq,
index 9212e8f37001d050418b505bdb7c8874b94cd9f0..49a97ce0742665b9e82b5a12224a06b6c80307da 100644 (file)
@@ -43,7 +43,7 @@
 #include "devices-imx27.h"
 #include "devices.h"
 
-static int pcm038_pins[] = {
+static const int pcm038_pins[] __initconst = {
        /* UART1 */
        PE12_PF_UART1_TXD,
        PE13_PF_UART1_RXD,
@@ -173,7 +173,6 @@ pcm038_nand_board_info __initconst = {
 static struct platform_device *platform_devices[] __initdata = {
        &pcm038_nor_mtd_device,
        &mxc_w1_master_device,
-       &mxc_fec_device,
        &pcm038_sram_mtd_device,
        &mxc_wdt,
 };
@@ -257,7 +256,7 @@ static struct regulator_init_data cam_data = {
        .consumer_supplies = cam_consumers,
 };
 
-struct mc13783_regulator_init_data pcm038_regulators[] = {
+static struct mc13783_regulator_init_data pcm038_regulators[] = {
        {
                .id = MC13783_REGU_VCAM,
                .init_data = &cam_data,
@@ -309,7 +308,7 @@ static void __init pcm038_init(void)
        i2c_register_board_info(1, pcm038_i2c_devices,
                                ARRAY_SIZE(pcm038_i2c_devices));
 
-       imx27_add_i2c_imx1(&pcm038_i2c1_data);
+       imx27_add_imx_i2c(1, &pcm038_i2c1_data);
 
        /* PE18 for user-LED D40 */
        mxc_gpio_mode(GPIO_PORTE | 18 | GPIO_GPIO | GPIO_OUT);
@@ -325,6 +324,7 @@ static void __init pcm038_init(void)
 
        mxc_register_device(&mxc_usbh2, &usbh2_pdata);
 
+       imx27_add_fec(NULL);
        platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
 
 #ifdef CONFIG_MACH_PCM970_BASEBOARD
@@ -342,8 +342,6 @@ static struct sys_timer pcm038_timer = {
 };
 
 MACHINE_START(PCM038, "phyCORE-i.MX27")
-       .phys_io        = MX27_AIPI_BASE_ADDR,
-       .io_pg_offst    = ((MX27_AIPI_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX27_PHYS_OFFSET + 0x100,
        .map_io         = mx27_map_io,
        .init_irq       = mx27_init_irq,
index 88bf0d1e26e6ebb3400e07db4f545e3f86c97b9b..1fbdd3faa7abf5a8d68e7981e46791a7acac7369 100644 (file)
@@ -95,7 +95,7 @@ static struct platform_device dm9000x_device = {
        }
 };
 
-static int mxc_uart1_pins[] = {
+static const int mxc_uart1_pins[] = {
        PC9_PF_UART1_CTS,
        PC10_PF_UART1_RTS,
        PC11_PF_UART1_TXD,
@@ -147,8 +147,6 @@ static struct sys_timer scb9328_timer = {
 
 MACHINE_START(SCB9328, "Synertronixx scb9328")
     /* Sascha Hauer */
-       .phys_io        = 0x00200000,
-       .io_pg_offst    = ((0xe0200000) >> 18) & 0xfffc,
        .boot_params    = 0x08000100,
        .map_io         = mx1_map_io,
        .init_irq       = mx1_init_irq,
index f490a406d57e737b46a343cb0c780e83f72cb056..9110d9cca7a2dc4b66adc85950541b5a9a7bc81b 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "devices.h"
 
-static int pcm970_pins[] = {
+static const int pcm970_pins[] __initconst = {
        /* SDHC */
        PB4_PF_SD2_D0,
        PB5_PF_SD2_D1,
@@ -200,7 +200,7 @@ static struct resource pcm970_sja1000_resources[] = {
        },
 };
 
-struct sja1000_platform_data pcm970_sja1000_platform_data = {
+static struct sja1000_platform_data pcm970_sja1000_platform_data = {
        .osc_freq       = 16000000,
        .ocr            = OCR_TX1_PULLDOWN | OCR_TX0_PUSHPULL,
        .cdr            = CDR_CBP,
index 87a6888ae011ba71e3764f02ab97a1b74260e839..a1f598fd3a567292a6abf0f9857a5f455ed9c614 100644 (file)
  *
 */
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #0x16000000        @ physical base address
-               movne   \rx, #0xf0000000        @ virtual base
-               addne   \rx, \rx, #0x16000000 >> 4
+               .macro  addruart, rp, rv
+               mov     \rp, #0x16000000        @ physical base address
+               mov     \rv, #0xf0000000        @ virtual base
+               add     \rv, \rv, #0x16000000 >> 4
                .endm
 
 #include <asm/hardware/debug-pl01x.S>
index e87ab0b37bddb353810f97bd25461a536cf167c1..e056e7cf5645f8c936f4144f8d584f2772ae9bf2 100644 (file)
@@ -17,4 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000
index 6ab5a03ab9d8b0a7f45311595b0ee1fa16474ef3..548208f11179c0aafbed4b3d23b5fc998196f1d3 100644 (file)
@@ -500,8 +500,6 @@ static struct sys_timer ap_timer = {
 
 MACHINE_START(INTEGRATOR, "ARM-Integrator")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_io        = 0x16000000,
-       .io_pg_offst    = ((0xf1600000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = ap_map_io,
        .reserve        = integrator_reserve,
index 05db40e3c4f75a7fcf661718269cdcf330d7f9cc..6258c90d020c30edf75faa7f06976d6cedef2e7e 100644 (file)
@@ -599,8 +599,6 @@ static struct sys_timer cp_timer = {
 
 MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_io        = 0x16000000,
-       .io_pg_offst    = ((0xf1600000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = intcp_map_io,
        .reserve        = integrator_reserve,
index c9d6ba46963da99c4f5c8ede984a27f470238024..e664466d51bf47a410235c19a1e60a9170e0a0bc 100644 (file)
  * published by the Free Software Foundation.
  */
 
-       .macro  addruart, rx, tmp
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                 @ mmu enabled?
-       moveq   \rx, #0xff000000        @ physical
-       orreq   \rx, \rx, #0x00d80000
-       movne   \rx, #0xfe000000        @ virtual
-       orrne   \rx, \rx, #0x00e80000
-       orr     \rx, \rx, #0x00002300
-       orr     \rx, \rx, #0x00000040
+       .macro  addruart, rp, rv
+       mov     \rp, #0x00002300
+       orr     \rp, \rp, #0x00000040
+       orr     \rv, \rp, #0xfe000000   @ virtual
+       orr     \rv, \rv, #0x00e80000
+       orr     \rp, \rp, #0xff000000   @ physical
+       orr     \rp, \rp, #0x00d80000
        .endm
 
 #define UART_SHIFT     2
index f91f3154577df1b0e1373239c756dd6d5fd1e33a..9b5a63f5d07d4368fcc6247d8815a2e272ac1ebf 100644 (file)
@@ -91,8 +91,6 @@ static struct sys_timer iq81340mc_timer = {
 
 MACHINE_START(IQ81340MC, "Intel IQ81340MC")
        /* Maintainer: Dan Williams <dan.j.williams@intel.com> */
-       .phys_io        = IOP13XX_PMMR_PHYS_MEM_BASE,
-       .io_pg_offst    = (IOP13XX_PMMR_VIRT_MEM_BASE >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = iop13xx_map_io,
        .init_irq       = iop13xx_init_irq,
index ddb7a3435de9e906e0017549a39a255d975bc05b..df3492a9c280e25e7201fae6947bee6b0f7e9b47 100644 (file)
@@ -93,8 +93,6 @@ static struct sys_timer iq81340sc_timer = {
 
 MACHINE_START(IQ81340SC, "Intel IQ81340SC")
        /* Maintainer: Dan Williams <dan.j.williams@intel.com> */
-       .phys_io        = IOP13XX_PMMR_PHYS_MEM_BASE,
-       .io_pg_offst    = (IOP13XX_PMMR_VIRT_MEM_BASE >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = iop13xx_map_io,
        .init_irq       = iop13xx_init_irq,
index f34b0ed806305474221051fa2b000199330b9e73..7149fcc16c8a0d87fda786bb76ebe24bda621ef0 100644 (file)
@@ -164,10 +164,10 @@ static void iop13xx_msi_nop(unsigned int irq)
 static struct irq_chip iop13xx_msi_chip = {
        .name = "PCI-MSI",
        .ack = iop13xx_msi_nop,
-       .enable = unmask_msi_irq,
-       .disable = mask_msi_irq,
-       .mask = mask_msi_irq,
-       .unmask = unmask_msi_irq,
+       .irq_enable = unmask_msi_irq,
+       .irq_disable = mask_msi_irq,
+       .irq_mask = mask_msi_irq,
+       .irq_unmask = unmask_msi_irq,
 };
 
 int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
index 2bef9b6e1cc91700c631fb93438589db938bbd67..779f924af302d6894b50484d15d31370485be9b6 100644 (file)
@@ -203,8 +203,6 @@ static void __init em7210_init_machine(void)
 }
 
 MACHINE_START(EM7210, "Lanner EM7210")
-       .phys_io        = IQ31244_UART,
-       .io_pg_offst    = ((IQ31244_UART) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = em7210_map_io,
        .init_irq       = iop32x_init_irq,
index 10384fc37cb29d4315931483151c961e63e2d033..c6b6f9c5650d11183678163dc05799c9512955d8 100644 (file)
@@ -207,8 +207,6 @@ static void __init glantank_init_machine(void)
 
 MACHINE_START(GLANTANK, "GLAN Tank")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-       .phys_io        = GLANTANK_UART,
-       .io_pg_offst    = ((GLANTANK_UART) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = glantank_map_io,
        .init_irq       = iop32x_init_irq,
index 736afe1edd1f668c4f84850b1604a3fc98a699b2..ff9e76c09f35b28ec0c551ad107b37d27b398d20 100644 (file)
  * published by the Free Software Foundation.
  */
 
-               .macro  addruart, rx, tmp
-               mov     \rx, #0xfe000000        @ physical as well as virtual
-               orr     \rx, \rx, #0x00800000   @ location of the UART
+               .macro  addruart, rp, rv
+               mov     \rp, #0xfe000000        @ physical as well as virtual
+               orr     \rp, \rp, #0x00800000   @ location of the UART
+               mov     \rv, \rp
                .endm
 
 #define UART_SHIFT     0
index d6ac85ff109deef02935213bc33577f0be2da42a..fde962c057f0e8489ce61c074c707a562337add1 100644 (file)
@@ -313,8 +313,6 @@ __setup("force_ep80219", force_ep80219_setup);
 
 MACHINE_START(IQ31244, "Intel IQ31244")
        /* Maintainer: Intel Corp. */
-       .phys_io        = IQ31244_UART,
-       .io_pg_offst    = ((IQ31244_UART) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = iq31244_map_io,
        .init_irq       = iop32x_init_irq,
@@ -329,8 +327,6 @@ MACHINE_END
  */
 MACHINE_START(EP80219, "Intel EP80219")
        /* Maintainer: Intel Corp. */
-       .phys_io        = IQ31244_UART,
-       .io_pg_offst    = ((IQ31244_UART) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = iq31244_map_io,
        .init_irq       = iop32x_init_irq,
index c6a0e4ee9d911d1b5d311be33b0fd537f65d93c4..3a95950e8737a05095ec02a91646ea6c6bc0674f 100644 (file)
@@ -186,8 +186,6 @@ static void __init iq80321_init_machine(void)
 
 MACHINE_START(IQ80321, "Intel IQ80321")
        /* Maintainer: Intel Corp. */
-       .phys_io        = IQ80321_UART,
-       .io_pg_offst    = ((IQ80321_UART) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = iq80321_map_io,
        .init_irq       = iop32x_init_irq,
index f108a31afc2b9f2440bc90d56d1745829d7936eb..626aa375915dcf06fb841fa90129a514bbf1aac6 100644 (file)
@@ -327,8 +327,6 @@ static void __init n2100_init_machine(void)
 
 MACHINE_START(N2100, "Thecus N2100")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-       .phys_io        = N2100_UART,
-       .io_pg_offst    = ((N2100_UART) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = n2100_map_io,
        .init_irq       = iop32x_init_irq,
index addb2da78422b0ff58df52a64dce48fe57bdd169..40c500dd1fac61ec3f520fe0fb0fab6934d43a74 100644 (file)
  * published by the Free Software Foundation.
  */
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ mmu enabled?
-               moveq   \rx, #0xff000000        @ physical
-               movne   \rx, #0xfe000000        @ virtual
-               orr     \rx, \rx, #0x00ff0000
-               orr     \rx, \rx, #0x0000f700
+               .macro  addruart, rp, rv
+               mov     \rp, #0x00ff0000
+               orr     \rp, \rp, #0x0000f700
+               orr     \rv, #0xfe000000        @ virtual
+               orr     \rp, #0xff000000        @ physical
                .endm
 
 #define UART_SHIFT     2
index c6ff5523b380f95e26fc4282d895d1e03c54614b..c565f8d1e3a46826d66c2a4d5718d3732c7bb2eb 100644 (file)
@@ -141,8 +141,6 @@ static void __init iq80331_init_machine(void)
 
 MACHINE_START(IQ80331, "Intel IQ80331")
        /* Maintainer: Intel Corp. */
-       .phys_io        = 0xfefff000,
-       .io_pg_offst    = ((0xfffff000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = iop3xx_map_io,
        .init_irq       = iop33x_init_irq,
index fbf55140939407f322af2f1c75441550edb37414..36a9efb254c25e69aa532ec70bcf6334352c33ff 100644 (file)
@@ -141,8 +141,6 @@ static void __init iq80332_init_machine(void)
 
 MACHINE_START(IQ80332, "Intel IQ80332")
        /* Maintainer: Intel Corp. */
-       .phys_io        = 0xfefff000,
-       .io_pg_offst    = ((0xfffff000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = iop3xx_map_io,
        .init_irq       = iop33x_init_irq,
index 1a557e0d055b56626e5e0b37206b032a055c4818..88663ab1d2ad949cdca45c4a1ae49e71bec35b58 100644 (file)
@@ -253,8 +253,6 @@ static void __init enp2611_init_machine(void)
 
 MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
        /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
-       .phys_io        = IXP2000_UART_PHYS_BASE,
-       .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = enp2611_map_io,
        .init_irq       = ixp2000_init_irq,
index 6a827681680fe20b833c07bc1990c488d1c20dae..0ef533b209721380abef4ffbd68d5c6a94a1c140 100644 (file)
  *
 */
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #0xc0000000        @ Physical base
-               movne   \rx, #0xfe000000        @ virtual base
-               orrne   \rx, \rx, #0x00f00000
-               orr     \rx, \rx, #0x00030000
+               .macro  addruart, rp, rv
+               mov     \rp, #0x00030000
 #ifdef __ARMEB__
-               orr     \rx, \rx, #0x00000003
+               orr     \rp, \rp, #0x00000003
 #endif
+               orr     \rv, \rp, #0xfe000000   @ virtual base
+               orr     \rv, \rv, #0x00f00000
+               orr     \rp, \rp, #0xc0000000   @ Physical base
                .endm
 
 #define UART_SHIFT     2
index 55e5c69352ad4de2395659e8dccc3a1e4e00a637..dfffc1e817faaa1a478653c5cba9077500237998 100644 (file)
@@ -170,8 +170,6 @@ void __init ixdp2400_init_irq(void)
 
 MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_io        = IXP2000_UART_PHYS_BASE,
-       .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = ixdp2x00_map_io,
        .init_irq       = ixdp2400_init_irq,
index 237b61a85e9a397f6d398c53a686edbd186515ac..cd4c9bcff2b512f9571af54f3734a2b790bae614 100644 (file)
@@ -285,8 +285,6 @@ void __init ixdp2800_init_irq(void)
 
 MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_io        = IXP2000_UART_PHYS_BASE,
-       .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = ixdp2x00_map_io,
        .init_irq       = ixdp2800_init_irq,
index 0369ec4242a687e61c7c4305de54fcec5d4f696b..6c121bdbe31192731948d73280f2918557c70417 100644 (file)
@@ -416,8 +416,6 @@ static void __init ixdp2x01_init_machine(void)
 #ifdef CONFIG_ARCH_IXDP2401
 MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_io        = IXP2000_UART_PHYS_BASE,
-       .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = ixdp2x01_map_io,
        .init_irq       = ixdp2x01_init_irq,
@@ -429,8 +427,6 @@ MACHINE_END
 #ifdef CONFIG_ARCH_IXDP2801
 MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_io        = IXP2000_UART_PHYS_BASE,
-       .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = ixdp2x01_map_io,
        .init_irq       = ixdp2x01_init_irq,
@@ -444,8 +440,6 @@ MACHINE_END
  */
 MACHINE_START(IXDP28X5, "Intel IXDP2805/2855 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_io        = IXP2000_UART_PHYS_BASE,
-       .io_pg_offst    = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = ixdp2x01_map_io,
        .init_irq       = ixdp2x01_init_irq,
index 1c06bfc5a7efc5909fe1dd1897b9bcd285388ad0..e25e5fe183ba976b319e3b2a912e13795a43caaf 100644 (file)
@@ -85,8 +85,6 @@ static void __init espresso_init(void)
 
 MACHINE_START(ESPRESSO, "IP Fabrics Double Espresso")
        /* Maintainer: Lennert Buytenhek */
-       .phys_io        = IXP23XX_PERIPHERAL_PHYS,
-       .io_pg_offst    = ((IXP23XX_PERIPHERAL_VIRT >> 18)) & 0xfffc,
        .map_io         = ixp23xx_map_io,
        .init_irq       = ixp23xx_init_irq,
        .timer          = &ixp23xx_timer,
index a82e375465e283651c4f8e96ea7913c4a77f4b35..f7c6eef7fa220d58a57b72e852002d22f14efe8f 100644 (file)
  */
 #include <mach/ixp23xx.h>
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                         @ mmu enabled?
-               ldreq   \rx, =IXP23XX_PERIPHERAL_PHYS   @ physical
-               ldrne   \rx, =IXP23XX_PERIPHERAL_VIRT   @ virtual
+               .macro  addruart, rp, rv
+               ldr     \rp, =IXP23XX_PERIPHERAL_PHYS   @ physical
+               ldr     \rv, =IXP23XX_PERIPHERAL_VIRT   @ virtual
 #ifdef __ARMEB__
-               orr     \rx, \rx, #0x00000003
+               orr     \rp, \rp, #0x00000003
+               orr     \rv, \rv, #0x00000003
 #endif
                .endm
 
index f1b124a709abd232b63625f6ddc143fd4b17730a..664e39c2a903e81a2491ea7a8d4eab1af02c2ac8 100644 (file)
@@ -328,8 +328,6 @@ static void __init ixdp2351_init(void)
 
 MACHINE_START(IXDP2351, "Intel IXDP2351 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_io        = IXP23XX_PERIPHERAL_PHYS,
-       .io_pg_offst    = ((IXP23XX_PERIPHERAL_VIRT >> 18)) & 0xfffc,
        .map_io         = ixdp2351_map_io,
        .init_irq       = ixdp2351_init_irq,
        .timer          = &ixp23xx_timer,
index 6d38d769761c1b727b7a2da2a1b096bc20fe4e76..76c61ba73218778987cec85683909e70ccf897fa 100644 (file)
@@ -171,8 +171,6 @@ static void __init roadrunner_init(void)
 
 MACHINE_START(ROADRUNNER, "ADI Engineering RoadRunner Development Platform")
        /* Maintainer: Deepak Saxena */
-       .phys_io        = IXP23XX_PERIPHERAL_PHYS,
-       .io_pg_offst    = ((IXP23XX_PERIPHERAL_VIRT >> 18)) & 0xfffc,
        .map_io         = ixp23xx_map_io,
        .init_irq       = ixp23xx_init_irq,
        .timer          = &ixp23xx_timer,
index d8bc86d76f1d2248b0d936f5cd1413c0ce0ba469..73745ff102d5da3e20beb6451b9736a2bf20cb00 100644 (file)
@@ -164,8 +164,6 @@ static void __init avila_init(void)
 
 MACHINE_START(AVILA, "Gateworks Avila Network Platform")
        /* Maintainer: Deepak Saxena <dsaxena@plexity.net> */
-       .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,
@@ -181,8 +179,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_LOFT
 MACHINE_START(LOFT, "Giant Shoulder Inc Loft board")
        /* Maintainer: Tom Billman <kernel@giantshoulderinc.com> */
-       .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,
index 31a47f6a8939d8fc1bc0ce7c0e78db0495e5b5df..355e3de3873371050a9794761def1761fd0ef34f 100644 (file)
@@ -109,8 +109,6 @@ static void __init coyote_init(void)
 #ifdef CONFIG_ARCH_ADI_COYOTE
 MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote")
        /* Maintainer: MontaVista Software, Inc. */
-       .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,
@@ -126,8 +124,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_IXDPG425
 MACHINE_START(IXDPG425, "Intel IXDPG425")
        /* Maintainer: MontaVista Software, Inc. */
-       .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,
index 7c1fa54a6145a987a4d41a4910421231a62a2ea5..d398229cfaa5d40b09e13effcf660dc71e97df8f 100644 (file)
@@ -279,8 +279,6 @@ static void __init dsmg600_init(void)
 
 MACHINE_START(DSMG600, "D-Link DSM-G600 RevA")
        /* Maintainer: www.nslu2-linux.org */
-       .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
-       .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
index e7f4befba4224b364c5d601ffe7359ef474fbc60..727ee39ce11c1ec786dc8cc498d7631996cc0490 100644 (file)
@@ -270,8 +270,6 @@ static void __init fsg_init(void)
 
 MACHINE_START(FSG, "Freecom FSG-3")
        /* Maintainer: www.nslu2-linux.org */
-       .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,
index 2583b2a13174ef02959fb62b70d96c68a978073a..9dc0b4eaa65adbac3ca17e7c7c565f793c440356 100644 (file)
@@ -96,8 +96,6 @@ static void __init gateway7001_init(void)
 #ifdef CONFIG_MACH_GATEWAY7001
 MACHINE_START(GATEWAY7001, "Gateway 7001 AP")
        /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
-       .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,
index 1c28048209c14c233407902fd86364f153fbaf9c..d0e4861ac03d5bc39c0f201d60e956f43559c28a 100644 (file)
@@ -496,8 +496,6 @@ subsys_initcall(gmlr_pci_init);
 
 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,
index c67586b79400c8a02084389e297539208dcdb5c1..77abead362277492e076f6d734a182241275314b 100644 (file)
@@ -164,8 +164,6 @@ static void __init gtwx5715_init(void)
 
 MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)")
        /* Maintainer: George Joseph */
-       .phys_io        = IXP4XX_UART2_BASE_PHYS,
-       .io_pg_offst    = ((IXP4XX_UART2_BASE_VIRT) >> 18) & 0xfffc,
        .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
        .timer          = &ixp4xx_timer,
index 3fc66d6d00a01f9d5b559f65ce096ebbf5576717..b974a49c0aff45a6a1ca1967b501f7d80588e757 100644 (file)
  * published by the Free Software Foundation.
 */
 
-                .macro  addruart, rx, tmp
-                mrc     p15, 0, \rx, c1, c0
-                tst     \rx, #1                 @ MMU enabled?
-                moveq   \rx, #0xc8000000
-                movne   \rx, #0xff000000
-               orrne   \rx, \rx, #0x00b00000
+                .macro  addruart, rp, rv
 #ifdef __ARMEB__
-                add     \rx,\rx,#3              @ Uart regs are at off set of 3 if
-                                               @ byte writes used - Big Endian.
+                mov     \rp, #3         @ Uart regs are at off set of 3 if
+                                       @ byte writes used - Big Endian.
+#else
+               mov     \rp, #0
 #endif
+                orr     \rv, \rp, #0xff000000  @ virtual
+               orr     \rv, \rv, #0x00b00000
+                orr     \rp, \rp, #0xc8000000  @ physical
                 .endm
 
 #define UART_SHIFT     2
index ea9ee4ed0a3e06a6b2f8135557b05a70c6240fbb..140783386785511a8997a8926a20a9d353bd8091 100644 (file)
@@ -257,8 +257,6 @@ static void __init ixdp425_init(void)
 #ifdef CONFIG_ARCH_IXDP425
 MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .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,
@@ -270,8 +268,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_IXDP465
 MACHINE_START(IXDP465, "Intel IXDP465 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .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,
@@ -283,8 +279,6 @@ MACHINE_END
 #ifdef CONFIG_ARCH_PRPMC1100
 MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .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,
@@ -296,8 +290,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_KIXRP435
 MACHINE_START(KIXRP435, "Intel KIXRP435 Reference Platform")
        /* Maintainer: MontaVista Software, Inc. */
-       .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,
index e3ee880aa1e687ae3df927bddaf95de4206710c4..f18fee748878e961136a837755dc460d3c35574b 100644 (file)
@@ -314,8 +314,6 @@ static void __init nas100d_init(void)
 
 MACHINE_START(NAS100D, "Iomega NAS 100d")
        /* Maintainer: www.nslu2-linux.org */
-       .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
-       .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
index c14e0034be4b42b134175d4614a764db59f04ec8..f79b62eb7614ec091d098b0276881a569d521d78 100644 (file)
@@ -300,8 +300,6 @@ static void __init nslu2_init(void)
 
 MACHINE_START(NSLU2, "Linksys NSLU2")
        /* Maintainer: www.nslu2-linux.org */
-       .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
-       .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .map_io         = ixp4xx_map_io,
        .init_irq       = ixp4xx_init_irq,
index 465cc5cce687df05de98c8e926994417462aac87..4e72cfdd3c461d2dba2fc03161998645d353e7f5 100644 (file)
@@ -236,8 +236,6 @@ static void __init vulcan_init(void)
 
 MACHINE_START(ARCOM_VULCAN, "Arcom/Eurotech Vulcan")
        /* Maintainer: Marc Zyngier <maz@misterjones.org> */
-       .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,
index 4dd74863daa9cb4e56c074108436abd2ea39b33d..5d148c7bc4fbd167473efb36fa2cd3e62e68aecb 100644 (file)
@@ -97,8 +97,6 @@ static void __init wg302v2_init(void)
 #ifdef CONFIG_MACH_WG302V2
 MACHINE_START(WG302V2, "Netgear WG302 v2 / WAG302 v2")
        /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
-       .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,
index cc25501b57fa8edf270752e0a719f2564965f44a..34106335c728f31527dc59dbc05d5978165ae365 100644 (file)
@@ -58,6 +58,12 @@ config MACH_TS41X
          QNAP TS-410, TS-410U, TS-419P and TS-419U Turbo NAS
          devices.
 
+config MACH_DOCKSTAR
+       bool "Seagate FreeAgent DockStar"
+       help
+         Say 'Y' here if you want your kernel to support the
+         Seagate FreeAgent DockStar.
+
 config MACH_OPENRD
         bool
 
@@ -100,6 +106,12 @@ config MACH_NETSPACE_MAX_V2
          Say 'Y' here if you want your kernel to support the
          LaCie Network Space Max v2 NAS.
 
+config MACH_D2NET_V2
+       bool "LaCie d2 Network v2 NAS Board"
+       help
+         Say 'Y' here if you want your kernel to support the
+         LaCie d2 Network v2 NAS.
+
 config MACH_NET2BIG_V2
        bool "LaCie 2Big Network v2 NAS Board"
        help
index 295d7baa6ae11150956e004330259859ef3c4ec6..5dcaa81a2ec39f0f6b60a13438651ab381fc6eb4 100644 (file)
@@ -7,14 +7,16 @@ obj-$(CONFIG_MACH_MV88F6281GTW_GE)    += mv88f6281gtw_ge-setup.o
 obj-$(CONFIG_MACH_SHEEVAPLUG)          += sheevaplug-setup.o
 obj-$(CONFIG_MACH_ESATA_SHEEVAPLUG)    += sheevaplug-setup.o
 obj-$(CONFIG_MACH_GURUPLUG)            += guruplug-setup.o
+obj-$(CONFIG_MACH_DOCKSTAR)            += dockstar-setup.o
 obj-$(CONFIG_MACH_TS219)               += ts219-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_TS41X)               += ts41x-setup.o tsx1x-common.o
 obj-$(CONFIG_MACH_OPENRD)              += openrd-setup.o
-obj-$(CONFIG_MACH_NETSPACE_V2)         += netspace_v2-setup.o
-obj-$(CONFIG_MACH_INETSPACE_V2)                += netspace_v2-setup.o
-obj-$(CONFIG_MACH_NETSPACE_MAX_V2)     += netspace_v2-setup.o
-obj-$(CONFIG_MACH_NET2BIG_V2)          += netxbig_v2-setup.o
-obj-$(CONFIG_MACH_NET5BIG_V2)          += netxbig_v2-setup.o
+obj-$(CONFIG_MACH_NETSPACE_V2)         += netspace_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_INETSPACE_V2)                += netspace_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_NETSPACE_MAX_V2)     += netspace_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_D2NET_V2)            += d2net_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_NET2BIG_V2)          += netxbig_v2-setup.o lacie_v2-common.o
+obj-$(CONFIG_MACH_NET5BIG_V2)          += netxbig_v2-setup.o lacie_v2-common.o
 obj-$(CONFIG_MACH_T5325)               += t5325-setup.o
 
 obj-$(CONFIG_CPU_IDLE)                 += cpuidle.o
diff --git a/arch/arm/mach-kirkwood/d2net_v2-setup.c b/arch/arm/mach-kirkwood/d2net_v2-setup.c
new file mode 100644 (file)
index 0000000..4aa86e4
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * arch/arm/mach-kirkwood/d2net_v2-setup.c
+ *
+ * LaCie d2 Network Space v2 Board Setup
+ *
+ * Copyright (C) 2010 Simon Guinot <sguinot@lacie.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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/input.h>
+#include <linux/gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include <mach/leds-ns2.h>
+#include "common.h"
+#include "mpp.h"
+#include "lacie_v2-common.h"
+
+/*****************************************************************************
+ * Ethernet
+ ****************************************************************************/
+
+static struct mv643xx_eth_platform_data d2net_v2_ge00_data = {
+       .phy_addr       = MV643XX_ETH_PHY_ADDR(8),
+};
+
+/*****************************************************************************
+ * SATA
+ ****************************************************************************/
+
+static struct mv_sata_platform_data d2net_v2_sata_data = {
+       .n_ports        = 2,
+};
+
+/*****************************************************************************
+ * GPIO keys
+ ****************************************************************************/
+
+#define D2NET_V2_GPIO_PUSH_BUTTON          34
+#define D2NET_V2_GPIO_POWER_SWITCH_ON      13
+#define D2NET_V2_GPIO_POWER_SWITCH_OFF     15
+
+#define D2NET_V2_SWITCH_POWER_ON           0x1
+#define D2NET_V2_SWITCH_POWER_OFF          0x2
+
+static struct gpio_keys_button d2net_v2_buttons[] = {
+       [0] = {
+               .type           = EV_SW,
+               .code           = D2NET_V2_SWITCH_POWER_ON,
+               .gpio           = D2NET_V2_GPIO_POWER_SWITCH_ON,
+               .desc           = "Back power switch (on|auto)",
+               .active_low     = 0,
+       },
+       [1] = {
+               .type           = EV_SW,
+               .code           = D2NET_V2_SWITCH_POWER_OFF,
+               .gpio           = D2NET_V2_GPIO_POWER_SWITCH_OFF,
+               .desc           = "Back power switch (auto|off)",
+               .active_low     = 0,
+       },
+       [2] = {
+               .code           = KEY_POWER,
+               .gpio           = D2NET_V2_GPIO_PUSH_BUTTON,
+               .desc           = "Front Push Button",
+               .active_low     = 1,
+       },
+};
+
+static struct gpio_keys_platform_data d2net_v2_button_data = {
+       .buttons        = d2net_v2_buttons,
+       .nbuttons       = ARRAY_SIZE(d2net_v2_buttons),
+};
+
+static struct platform_device d2net_v2_gpio_buttons = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &d2net_v2_button_data,
+       },
+};
+
+/*****************************************************************************
+ * GPIO LEDs
+ ****************************************************************************/
+
+#define D2NET_V2_GPIO_RED_LED          12
+
+static struct gpio_led d2net_v2_gpio_led_pins[] = {
+       {
+               .name   = "d2net_v2:red:fail",
+               .gpio   = D2NET_V2_GPIO_RED_LED,
+       },
+};
+
+static struct gpio_led_platform_data d2net_v2_gpio_leds_data = {
+       .num_leds       = ARRAY_SIZE(d2net_v2_gpio_led_pins),
+       .leds           = d2net_v2_gpio_led_pins,
+};
+
+static struct platform_device d2net_v2_gpio_leds = {
+       .name           = "leds-gpio",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &d2net_v2_gpio_leds_data,
+       },
+};
+
+/*****************************************************************************
+ * Dual-GPIO CPLD LEDs
+ ****************************************************************************/
+
+#define D2NET_V2_GPIO_BLUE_LED_SLOW    29
+#define D2NET_V2_GPIO_BLUE_LED_CMD     30
+
+static struct ns2_led d2net_v2_led_pins[] = {
+       {
+               .name   = "d2net_v2:blue:sata",
+               .cmd    = D2NET_V2_GPIO_BLUE_LED_CMD,
+               .slow   = D2NET_V2_GPIO_BLUE_LED_SLOW,
+       },
+};
+
+static struct ns2_led_platform_data d2net_v2_leds_data = {
+       .num_leds       = ARRAY_SIZE(d2net_v2_led_pins),
+       .leds           = d2net_v2_led_pins,
+};
+
+static struct platform_device d2net_v2_leds = {
+       .name           = "leds-ns2",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &d2net_v2_leds_data,
+       },
+};
+
+/*****************************************************************************
+ * General Setup
+ ****************************************************************************/
+
+static unsigned int d2net_v2_mpp_config[] __initdata = {
+       MPP0_SPI_SCn,
+       MPP1_SPI_MOSI,
+       MPP2_SPI_SCK,
+       MPP3_SPI_MISO,
+       MPP6_SYSRST_OUTn,
+       MPP7_GPO,               /* Request power-off */
+       MPP8_TW0_SDA,
+       MPP9_TW0_SCK,
+       MPP10_UART0_TXD,
+       MPP11_UART0_RXD,
+       MPP12_GPO,              /* Red led */
+       MPP13_GPIO,             /* Rear power switch (on|auto) */
+       MPP14_GPIO,             /* USB fuse */
+       MPP15_GPIO,             /* Rear power switch (auto|off) */
+       MPP16_GPIO,             /* SATA 0 power */
+       MPP21_SATA0_ACTn,
+       MPP24_GPIO,             /* USB mode select */
+       MPP26_GPIO,             /* USB device vbus */
+       MPP28_GPIO,             /* USB enable host vbus */
+       MPP29_GPIO,             /* Blue led (slow register) */
+       MPP30_GPIO,             /* Blue led (command register) */
+       MPP34_GPIO,             /* Power button (1 = Released, 0 = Pushed) */
+       MPP35_GPIO,             /* Inhibit power-off */
+       0
+};
+
+#define D2NET_V2_GPIO_POWER_OFF                7
+
+static void d2net_v2_power_off(void)
+{
+       gpio_set_value(D2NET_V2_GPIO_POWER_OFF, 1);
+}
+
+static void __init d2net_v2_init(void)
+{
+       /*
+        * Basic setup. Needs to be called early.
+        */
+       kirkwood_init();
+       kirkwood_mpp_conf(d2net_v2_mpp_config);
+
+       lacie_v2_hdd_power_init(1);
+
+       kirkwood_ehci_init();
+       kirkwood_ge00_init(&d2net_v2_ge00_data);
+       kirkwood_sata_init(&d2net_v2_sata_data);
+       kirkwood_uart0_init();
+       lacie_v2_register_flash();
+       lacie_v2_register_i2c_devices();
+
+       platform_device_register(&d2net_v2_leds);
+       platform_device_register(&d2net_v2_gpio_leds);
+       platform_device_register(&d2net_v2_gpio_buttons);
+
+       if (gpio_request(D2NET_V2_GPIO_POWER_OFF, "power-off") == 0 &&
+           gpio_direction_output(D2NET_V2_GPIO_POWER_OFF, 0) == 0)
+               pm_power_off = d2net_v2_power_off;
+       else
+               pr_err("d2net_v2: failed to configure power-off GPIO\n");
+}
+
+MACHINE_START(D2NET_V2, "LaCie d2 Network v2")
+       .boot_params    = 0x00000100,
+       .init_machine   = d2net_v2_init,
+       .map_io         = kirkwood_map_io,
+       .init_irq       = kirkwood_init_irq,
+       .timer          = &lacie_v2_timer,
+MACHINE_END
index 16f6691e7c685cc6af9266b56bcd0af1265a60ef..9ea71182d31ac5aea51d7a31d5e60ac98c1bc830 100644 (file)
@@ -97,8 +97,6 @@ subsys_initcall(db88f6281_pci_init);
 
 MACHINE_START(DB88F6281_BP, "Marvell DB-88F6281-BP Development Board")
        /* Maintainer: Saeed Bishara <saeed@marvell.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = db88f6281_init,
        .map_io         = kirkwood_map_io,
diff --git a/arch/arm/mach-kirkwood/dockstar-setup.c b/arch/arm/mach-kirkwood/dockstar-setup.c
new file mode 100644 (file)
index 0000000..433ea36
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * arch/arm/mach-kirkwood/dockstar-setup.c
+ *
+ * Seagate FreeAgent DockStar 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/ata_platform.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/kirkwood.h>
+#include <plat/mvsdio.h>
+#include "common.h"
+#include "mpp.h"
+
+static struct mtd_partition dockstar_nand_parts[] = {
+       {
+               .name = "u-boot",
+               .offset = 0,
+               .size = SZ_1M
+       }, {
+               .name = "uImage",
+               .offset = MTDPART_OFS_NXTBLK,
+               .size = SZ_4M
+       }, {
+               .name = "root",
+               .offset = MTDPART_OFS_NXTBLK,
+               .size = MTDPART_SIZ_FULL
+       },
+};
+
+static struct mv643xx_eth_platform_data dockstar_ge00_data = {
+       .phy_addr       = MV643XX_ETH_PHY_ADDR(0),
+};
+
+static struct gpio_led dockstar_led_pins[] = {
+       {
+               .name                   = "dockstar:green:health",
+               .default_trigger        = "default-on",
+               .gpio                   = 46,
+               .active_low             = 1,
+       },
+       {
+               .name                   = "dockstar:orange:misc",
+               .default_trigger        = "none",
+               .gpio                   = 47,
+               .active_low             = 1,
+       },
+};
+
+static struct gpio_led_platform_data dockstar_led_data = {
+       .leds           = dockstar_led_pins,
+       .num_leds       = ARRAY_SIZE(dockstar_led_pins),
+};
+
+static struct platform_device dockstar_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &dockstar_led_data,
+       }
+};
+
+static unsigned int dockstar_mpp_config[] __initdata = {
+       MPP29_GPIO,     /* USB Power Enable */
+       MPP46_GPIO,     /* LED green */
+       MPP47_GPIO,     /* LED orange */
+       0
+};
+
+static void __init dockstar_init(void)
+{
+       /*
+        * Basic setup. Needs to be called early.
+        */
+       kirkwood_init();
+
+       /* setup gpio pin select */
+       kirkwood_mpp_conf(dockstar_mpp_config);
+
+       kirkwood_uart0_init();
+       kirkwood_nand_init(ARRAY_AND_SIZE(dockstar_nand_parts), 25);
+
+       if (gpio_request(29, "USB Power Enable") != 0 ||
+           gpio_direction_output(29, 1) != 0)
+               printk(KERN_ERR "can't set up GPIO 29 (USB Power Enable)\n");
+       kirkwood_ehci_init();
+
+       kirkwood_ge00_init(&dockstar_ge00_data);
+
+       platform_device_register(&dockstar_leds);
+}
+
+MACHINE_START(DOCKSTAR, "Seagate FreeAgent DockStar")
+       .boot_params    = 0x00000100,
+       .init_machine   = dockstar_init,
+       .map_io         = kirkwood_map_io,
+       .init_irq       = kirkwood_init_irq,
+       .timer          = &kirkwood_timer,
+MACHINE_END
index 54d07c89d4ffe2e278c501ec6e4ddda0e6171cda..8f47dc0a2feff75a9d546373f7565dc4e4585862 100644 (file)
@@ -121,8 +121,6 @@ static void __init guruplug_init(void)
 
 MACHINE_START(GURUPLUG, "Marvell GuruPlug Reference Board")
        /* Maintainer: Siddarth Gore <gores@marvell.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = guruplug_init,
        .map_io         = kirkwood_map_io,
index d0606774dea7de3baa03e4291dd016b0825dde07..db06ae437d08c69fa126edf696b377bdca54262e 100644 (file)
@@ -8,12 +8,11 @@
 
 #include <mach/bridge-regs.h>
 
-       .macro  addruart, rx, tmp
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                                 @ MMU enabled?
-       ldreq   \rx, =KIRKWOOD_REGS_PHYS_BASE
-       ldrne   \rx, =KIRKWOOD_REGS_VIRT_BASE
-       orr     \rx, \rx, #0x00012000
+       .macro  addruart, rp, rv
+       ldr     \rp, =KIRKWOOD_REGS_PHYS_BASE
+       ldr     \rv, =KIRKWOOD_REGS_VIRT_BASE
+       orr     \rp, \rp, #0x00012000
+       orr     \rv, \rv, #0x00012000
        .endm
 
 #define UART_SHIFT     2
diff --git a/arch/arm/mach-kirkwood/include/mach/leds-netxbig.h b/arch/arm/mach-kirkwood/include/mach/leds-netxbig.h
new file mode 100644 (file)
index 0000000..24b536e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * arch/arm/mach-kirkwood/include/mach/leds-netxbig.h
+ *
+ * Platform data structure for netxbig LED driver
+ *
+ * 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_LEDS_NETXBIG_H
+#define __MACH_LEDS_NETXBIG_H
+
+struct netxbig_gpio_ext {
+       unsigned        *addr;
+       int             num_addr;
+       unsigned        *data;
+       int             num_data;
+       unsigned        enable;
+};
+
+enum netxbig_led_mode {
+       NETXBIG_LED_OFF,
+       NETXBIG_LED_ON,
+       NETXBIG_LED_SATA,
+       NETXBIG_LED_TIMER1,
+       NETXBIG_LED_TIMER2,
+       NETXBIG_LED_MODE_NUM,
+};
+
+#define NETXBIG_LED_INVALID_MODE NETXBIG_LED_MODE_NUM
+
+struct netxbig_led_timer {
+       unsigned long           delay_on;
+       unsigned long           delay_off;
+       enum netxbig_led_mode   mode;
+};
+
+struct netxbig_led {
+       const char      *name;
+       const char      *default_trigger;
+       int             mode_addr;
+       int             *mode_val;
+       int             bright_addr;
+};
+
+struct netxbig_led_platform_data {
+       struct netxbig_gpio_ext *gpio_ext;
+       struct netxbig_led_timer *timer;
+       int                     num_timer;
+       struct netxbig_led      *leds;
+       int                     num_leds;
+};
+
+#endif /* __MACH_LEDS_NETXBIG_H */
diff --git a/arch/arm/mach-kirkwood/lacie_v2-common.c b/arch/arm/mach-kirkwood/lacie_v2-common.c
new file mode 100644 (file)
index 0000000..d3ea1b6
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * arch/arm/mach-kirkwood/lacie_v2-common.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/init.h>
+#include <linux/mtd/physmap.h>
+#include <linux/spi/flash.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+#include <linux/i2c/at24.h>
+#include <linux/gpio.h>
+#include <asm/mach/time.h>
+#include <mach/kirkwood.h>
+#include <mach/irqs.h>
+#include <plat/time.h>
+#include "common.h"
+
+/*****************************************************************************
+ * 512KB SPI Flash on Boot Device (MACRONIX MX25L4005)
+ ****************************************************************************/
+
+static struct mtd_partition lacie_v2_flash_parts[] = {
+       {
+               .name = "u-boot",
+               .size = MTDPART_SIZ_FULL,
+               .offset = 0,
+               .mask_flags = MTD_WRITEABLE, /* force read-only */
+       },
+};
+
+static const struct flash_platform_data lacie_v2_flash = {
+       .type           = "mx25l4005a",
+       .name           = "spi_flash",
+       .parts          = lacie_v2_flash_parts,
+       .nr_parts       = ARRAY_SIZE(lacie_v2_flash_parts),
+};
+
+static struct spi_board_info __initdata lacie_v2_spi_slave_info[] = {
+       {
+               .modalias       = "m25p80",
+               .platform_data  = &lacie_v2_flash,
+               .irq            = -1,
+               .max_speed_hz   = 20000000,
+               .bus_num        = 0,
+               .chip_select    = 0,
+       },
+};
+
+void __init lacie_v2_register_flash(void)
+{
+       spi_register_board_info(lacie_v2_spi_slave_info,
+                               ARRAY_SIZE(lacie_v2_spi_slave_info));
+       kirkwood_spi_init();
+}
+
+/*****************************************************************************
+ * I2C devices
+ ****************************************************************************/
+
+static struct at24_platform_data at24c04 = {
+       .byte_len       = SZ_4K / 8,
+       .page_size      = 16,
+};
+
+/*
+ * i2c addr | chip         | description
+ * 0x50     | HT24LC04     | eeprom (512B)
+ */
+
+static struct i2c_board_info __initdata lacie_v2_i2c_info[] = {
+       {
+               I2C_BOARD_INFO("24c04", 0x50),
+               .platform_data  = &at24c04,
+       }
+};
+
+void __init lacie_v2_register_i2c_devices(void)
+{
+       kirkwood_i2c_init();
+       i2c_register_board_info(0, lacie_v2_i2c_info,
+                               ARRAY_SIZE(lacie_v2_i2c_info));
+}
+
+/*****************************************************************************
+ * Hard Disk power
+ ****************************************************************************/
+
+static int __initdata lacie_v2_gpio_hdd_power[] = { 16, 17, 41, 42, 43 };
+
+void __init lacie_v2_hdd_power_init(int hdd_num)
+{
+       int i;
+       int err;
+
+       /* Power up all hard disks. */
+       for (i = 0; i < hdd_num; i++) {
+               err = gpio_request(lacie_v2_gpio_hdd_power[i], NULL);
+               if (err == 0) {
+                       err = gpio_direction_output(
+                                       lacie_v2_gpio_hdd_power[i], 1);
+                       /* Free the HDD power GPIOs. This allow user-space to
+                        * configure them via the gpiolib sysfs interface. */
+                       gpio_free(lacie_v2_gpio_hdd_power[i]);
+               }
+               if (err)
+                       pr_err("Failed to power up HDD%d\n", i + 1);
+       }
+}
+
+/*****************************************************************************
+ * Timer
+ ****************************************************************************/
+
+static void lacie_v2_timer_init(void)
+{
+       kirkwood_tclk = 166666667;
+       orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
+}
+
+struct sys_timer lacie_v2_timer = {
+       .init = lacie_v2_timer_init,
+};
diff --git a/arch/arm/mach-kirkwood/lacie_v2-common.h b/arch/arm/mach-kirkwood/lacie_v2-common.h
new file mode 100644 (file)
index 0000000..af52131
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * arch/arm/mach-kirkwood/lacie_v2-common.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 __ARCH_KIRKWOOD_LACIE_V2_COMMON_H
+#define __ARCH_KIRKWOOD_LACIE_V2_COMMON_H
+
+void lacie_v2_register_flash(void);
+void lacie_v2_register_i2c_devices(void);
+void lacie_v2_hdd_power_init(int hdd_num);
+
+extern struct sys_timer lacie_v2_timer;
+
+#endif
index c6b92b42eb4e5a627fcceb74b61078bc8e589f4a..1e5266f57e2a2d3e6a46d7761e8b622c5f3928ca 100644 (file)
@@ -163,8 +163,6 @@ 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,
index d26bf324738bde48e5be8b5c5cf13978a9f03730..5e286441b8f45f5f571e001b48d16fe7685362ac 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/spi/flash.h>
-#include <linux/spi/spi.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
-#include <linux/i2c.h>
-#include <linux/i2c/at24.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/time.h>
 #include <mach/kirkwood.h>
 #include <mach/leds-ns2.h>
-#include <plat/time.h>
 #include "common.h"
 #include "mpp.h"
-
-/*****************************************************************************
- * 512KB SPI Flash on Boot Device (MACRONIX MX25L4005)
- ****************************************************************************/
-
-static struct mtd_partition netspace_v2_flash_parts[] = {
-       {
-               .name = "u-boot",
-               .size = MTDPART_SIZ_FULL,
-               .offset = 0,
-               .mask_flags = MTD_WRITEABLE, /* force read-only */
-       },
-};
-
-static const struct flash_platform_data netspace_v2_flash = {
-       .type           = "mx25l4005a",
-       .name           = "spi_flash",
-       .parts          = netspace_v2_flash_parts,
-       .nr_parts       = ARRAY_SIZE(netspace_v2_flash_parts),
-};
-
-static struct spi_board_info __initdata netspace_v2_spi_slave_info[] = {
-       {
-               .modalias       = "m25p80",
-               .platform_data  = &netspace_v2_flash,
-               .irq            = -1,
-               .max_speed_hz   = 20000000,
-               .bus_num        = 0,
-               .chip_select    = 0,
-       },
-};
+#include "lacie_v2-common.h"
 
 /*****************************************************************************
  * Ethernet
@@ -83,27 +46,6 @@ static struct mv643xx_eth_platform_data netspace_v2_ge00_data = {
        .phy_addr       = MV643XX_ETH_PHY_ADDR(8),
 };
 
-/*****************************************************************************
- * I2C devices
- ****************************************************************************/
-
-static struct at24_platform_data at24c04 = {
-       .byte_len       = SZ_4K / 8,
-       .page_size      = 16,
-};
-
-/*
- * i2c addr | chip         | description
- * 0x50     | HT24LC04     | eeprom (512B)
- */
-
-static struct i2c_board_info __initdata netspace_v2_i2c_info[] = {
-       {
-               I2C_BOARD_INFO("24c04", 0x50),
-               .platform_data  = &at24c04,
-       }
-};
-
 /*****************************************************************************
  * SATA
  ****************************************************************************/
@@ -112,35 +54,6 @@ static struct mv_sata_platform_data netspace_v2_sata_data = {
        .n_ports        = 2,
 };
 
-#define NETSPACE_V2_GPIO_SATA0_POWER   16
-#define NETSPACE_V2_GPIO_SATA1_POWER   17
-
-static void __init netspace_v2_sata_power_init(void)
-{
-       int err;
-
-       err = gpio_request(NETSPACE_V2_GPIO_SATA0_POWER, "SATA0 power");
-       if (err == 0) {
-               err = gpio_direction_output(NETSPACE_V2_GPIO_SATA0_POWER, 1);
-               if (err)
-                       gpio_free(NETSPACE_V2_GPIO_SATA0_POWER);
-       }
-       if (err)
-               pr_err("netspace_v2: failed to setup SATA0 power\n");
-
-       if (machine_is_netspace_max_v2()) {
-               err = gpio_request(NETSPACE_V2_GPIO_SATA1_POWER, "SATA1 power");
-               if (err == 0) {
-                       err = gpio_direction_output(
-                                       NETSPACE_V2_GPIO_SATA1_POWER, 1);
-                       if (err)
-                               gpio_free(NETSPACE_V2_GPIO_SATA1_POWER);
-               }
-               if (err)
-                       pr_err("netspace_v2: failed to setup SATA1 power\n");
-       }
-}
-
 /*****************************************************************************
  * GPIO keys
  ****************************************************************************/
@@ -223,20 +136,6 @@ static struct platform_device netspace_v2_leds = {
        },
 };
 
-/*****************************************************************************
- * Timer
- ****************************************************************************/
-
-static void netspace_v2_timer_init(void)
-{
-       kirkwood_tclk = 166666667;
-       orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
-}
-
-struct sys_timer netspace_v2_timer = {
-       .init = netspace_v2_timer_init,
-};
-
 /*****************************************************************************
  * General Setup
  ****************************************************************************/
@@ -291,18 +190,17 @@ static void __init netspace_v2_init(void)
        kirkwood_init();
        kirkwood_mpp_conf(netspace_v2_mpp_config);
 
-       netspace_v2_sata_power_init();
+       if (machine_is_netspace_max_v2())
+               lacie_v2_hdd_power_init(2);
+       else
+               lacie_v2_hdd_power_init(1);
 
        kirkwood_ehci_init();
        kirkwood_ge00_init(&netspace_v2_ge00_data);
        kirkwood_sata_init(&netspace_v2_sata_data);
        kirkwood_uart0_init();
-       spi_register_board_info(netspace_v2_spi_slave_info,
-                               ARRAY_SIZE(netspace_v2_spi_slave_info));
-       kirkwood_spi_init();
-       kirkwood_i2c_init();
-       i2c_register_board_info(0, netspace_v2_i2c_info,
-                               ARRAY_SIZE(netspace_v2_i2c_info));
+       lacie_v2_register_flash();
+       lacie_v2_register_i2c_devices();
 
        platform_device_register(&netspace_v2_leds);
        platform_device_register(&netspace_v2_gpio_leds);
@@ -317,36 +215,30 @@ static void __init netspace_v2_init(void)
 
 #ifdef CONFIG_MACH_NETSPACE_V2
 MACHINE_START(NETSPACE_V2, "LaCie Network Space v2")
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = netspace_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &netspace_v2_timer,
+       .timer          = &lacie_v2_timer,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_INETSPACE_V2
 MACHINE_START(INETSPACE_V2, "LaCie Internet Space v2")
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = netspace_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &netspace_v2_timer,
+       .timer          = &lacie_v2_timer,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_NETSPACE_MAX_V2
 MACHINE_START(NETSPACE_MAX_V2, "LaCie Network Space Max v2")
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = netspace_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &netspace_v2_timer,
+       .timer          = &lacie_v2_timer,
 MACHINE_END
 #endif
index 2bd14c5079de7c0e7379439523aed3422173f383..a1b45d501aef57393a47e0d99e67a423ae3355fc 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/spi/flash.h>
-#include <linux/spi/spi.h>
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
-#include <linux/i2c.h>
-#include <linux/i2c/at24.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
 #include <linux/gpio_keys.h>
 #include <linux/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/mach/time.h>
 #include <mach/kirkwood.h>
-#include <plat/time.h>
+#include <mach/leds-netxbig.h>
 #include "common.h"
 #include "mpp.h"
-
-/*****************************************************************************
- * 512KB SPI Flash on Boot Device (MACRONIX MX25L4005)
- ****************************************************************************/
-
-static struct mtd_partition netxbig_v2_flash_parts[] = {
-       {
-               .name = "u-boot",
-               .size = MTDPART_SIZ_FULL,
-               .offset = 0,
-               .mask_flags = MTD_WRITEABLE, /* force read-only */
-       },
-};
-
-static const struct flash_platform_data netxbig_v2_flash = {
-       .type           = "mx25l4005a",
-       .name           = "spi_flash",
-       .parts          = netxbig_v2_flash_parts,
-       .nr_parts       = ARRAY_SIZE(netxbig_v2_flash_parts),
-};
-
-static struct spi_board_info __initdata netxbig_v2_spi_slave_info[] = {
-       {
-               .modalias       = "m25p80",
-               .platform_data  = &netxbig_v2_flash,
-               .irq            = -1,
-               .max_speed_hz   = 20000000,
-               .bus_num        = 0,
-               .chip_select    = 0,
-       },
-};
+#include "lacie_v2-common.h"
 
 /*****************************************************************************
  * Ethernet
@@ -85,27 +49,6 @@ static struct mv643xx_eth_platform_data netxbig_v2_ge01_data = {
        .phy_addr       = MV643XX_ETH_PHY_ADDR(0),
 };
 
-/*****************************************************************************
- * I2C devices
- ****************************************************************************/
-
-static struct at24_platform_data at24c04 = {
-       .byte_len       = SZ_4K / 8,
-       .page_size      = 16,
-};
-
-/*
- * i2c addr | chip         | description
- * 0x50     | HT24LC04     | eeprom (512B)
- */
-
-static struct i2c_board_info __initdata netxbig_v2_i2c_info[] = {
-       {
-               I2C_BOARD_INFO("24c04", 0x50),
-               .platform_data  = &at24c04,
-       }
-};
-
 /*****************************************************************************
  * SATA
  ****************************************************************************/
@@ -114,34 +57,6 @@ static struct mv_sata_platform_data netxbig_v2_sata_data = {
        .n_ports        = 2,
 };
 
-static int __initdata netxbig_v2_gpio_hdd_power[] = { 16, 17, 41, 42, 43 };
-
-static void __init netxbig_v2_sata_power_init(void)
-{
-       int i;
-       int err;
-       int hdd_nb;
-
-       if (machine_is_net2big_v2())
-               hdd_nb = 2;
-       else
-               hdd_nb = 5;
-
-       /* Power up all hard disks. */
-       for (i = 0; i < hdd_nb; i++) {
-               err = gpio_request(netxbig_v2_gpio_hdd_power[i], NULL);
-               if (err == 0) {
-                       err = gpio_direction_output(
-                                       netxbig_v2_gpio_hdd_power[i], 1);
-                       /* Free the HDD power GPIOs. This allow user-space to
-                        * configure them via the gpiolib sysfs interface. */
-                       gpio_free(netxbig_v2_gpio_hdd_power[i]);
-               }
-               if (err)
-                       pr_err("netxbig_v2: failed to power up HDD%d\n", i + 1);
-       }
-}
-
 /*****************************************************************************
  * GPIO keys
  ****************************************************************************/
@@ -190,7 +105,7 @@ static struct platform_device netxbig_v2_gpio_buttons = {
 };
 
 /*****************************************************************************
- * GPIO LEDs
+ * GPIO extension LEDs
  ****************************************************************************/
 
 /*
@@ -200,19 +115,32 @@ static struct platform_device netxbig_v2_gpio_buttons = {
  * - address register : bit [0-2] -> GPIO [47-49]
  * - data register    : bit [0-2] -> GPIO [44-46]
  * - enable register  : GPIO 29
- *
+ */
+
+static int netxbig_v2_gpio_ext_addr[] = { 47, 48, 49 };
+static int netxbig_v2_gpio_ext_data[] = { 44, 45, 46 };
+
+static struct netxbig_gpio_ext netxbig_v2_gpio_ext = {
+       .addr           = netxbig_v2_gpio_ext_addr,
+       .num_addr       = ARRAY_SIZE(netxbig_v2_gpio_ext_addr),
+       .data           = netxbig_v2_gpio_ext_data,
+       .num_data       = ARRAY_SIZE(netxbig_v2_gpio_ext_data),
+       .enable         = 29,
+};
+
+/*
  * Address register selection:
  *
  * addr | register
  * ----------------------------
  *   0  | front LED
  *   1  | front LED brightness
- *   2  | HDD LED brightness
- *   3  | HDD1 LED
- *   4  | HDD2 LED
- *   5  | HDD3 LED
- *   6  | HDD4 LED
- *   7  | HDD5 LED
+ *   2  | SATA LED brightness
+ *   3  | SATA0 LED
+ *   4  | SATA1 LED
+ *   5  | SATA2 LED
+ *   6  | SATA3 LED
+ *   7  | SATA4 LED
  *
  * Data register configuration:
  *
@@ -233,30 +161,107 @@ static struct platform_device netxbig_v2_gpio_buttons = {
  *   6  | blink blue on=1 sec and red on=1 sec
  *   7  | blink blue on=0.5 sec and blue off=2.5 sec
  *
- * data | HDD LED mode
+ * data | SATA LED mode
  * -------------------------------------------------
- *   0  | fix blue on
+ *   0  | fix off
  *   1  | SATA activity blink
  *   2  | fix red on
  *   3  | blink blue on=1 sec and blue off=1 sec
  *   4  | blink red on=1 sec and red off=1 sec
  *   5  | blink blue on=2.5 sec and red on=0.5 sec
  *   6  | blink blue on=1 sec and red on=1 sec
- *   7  | blink blue on=0.5 sec and blue off=2.5 sec
+ *   7  | fix blue on
  */
 
-/*****************************************************************************
- * Timer
- ****************************************************************************/
+static int netxbig_v2_red_mled[NETXBIG_LED_MODE_NUM] = {
+       [NETXBIG_LED_OFF]       = 0,
+       [NETXBIG_LED_ON]        = 2,
+       [NETXBIG_LED_SATA]      = NETXBIG_LED_INVALID_MODE,
+       [NETXBIG_LED_TIMER1]    = 4,
+       [NETXBIG_LED_TIMER2]    = NETXBIG_LED_INVALID_MODE,
+};
 
-static void netxbig_v2_timer_init(void)
-{
-       kirkwood_tclk = 166666667;
-       orion_time_init(IRQ_KIRKWOOD_BRIDGE, kirkwood_tclk);
-}
+static int netxbig_v2_blue_pwr_mled[NETXBIG_LED_MODE_NUM] = {
+       [NETXBIG_LED_OFF]       = 0,
+       [NETXBIG_LED_ON]        = 1,
+       [NETXBIG_LED_SATA]      = NETXBIG_LED_INVALID_MODE,
+       [NETXBIG_LED_TIMER1]    = 3,
+       [NETXBIG_LED_TIMER2]    = 7,
+};
+
+static int netxbig_v2_blue_sata_mled[NETXBIG_LED_MODE_NUM] = {
+       [NETXBIG_LED_OFF]       = 0,
+       [NETXBIG_LED_ON]        = 7,
+       [NETXBIG_LED_SATA]      = 1,
+       [NETXBIG_LED_TIMER1]    = 3,
+       [NETXBIG_LED_TIMER2]    = NETXBIG_LED_INVALID_MODE,
+};
+
+static struct netxbig_led_timer netxbig_v2_led_timer[] = {
+       [0] = {
+               .delay_on       = 500,
+               .delay_off      = 500,
+               .mode           = NETXBIG_LED_TIMER1,
+       },
+       [1] = {
+               .delay_on       = 500,
+               .delay_off      = 1000,
+               .mode           = NETXBIG_LED_TIMER2,
+       },
+};
+
+#define NETXBIG_LED(_name, maddr, mval, baddr)                 \
+       { .name         = _name,                                \
+         .mode_addr    = maddr,                                \
+         .mode_val     = mval,                                 \
+         .bright_addr  = baddr }
+
+static struct netxbig_led net2big_v2_leds_ctrl[] = {
+       NETXBIG_LED("net2big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled,  1),
+       NETXBIG_LED("net2big-v2:red:power",  0, netxbig_v2_red_mled,       1),
+       NETXBIG_LED("net2big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2),
+       NETXBIG_LED("net2big-v2:red:sata0",  3, netxbig_v2_red_mled,       2),
+       NETXBIG_LED("net2big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2),
+       NETXBIG_LED("net2big-v2:red:sata1",  4, netxbig_v2_red_mled,       2),
+};
+
+static struct netxbig_led_platform_data net2big_v2_leds_data = {
+       .gpio_ext       = &netxbig_v2_gpio_ext,
+       .timer          = netxbig_v2_led_timer,
+       .num_timer      = ARRAY_SIZE(netxbig_v2_led_timer),
+       .leds           = net2big_v2_leds_ctrl,
+       .num_leds       = ARRAY_SIZE(net2big_v2_leds_ctrl),
+};
+
+static struct netxbig_led net5big_v2_leds_ctrl[] = {
+       NETXBIG_LED("net5big-v2:blue:power", 0, netxbig_v2_blue_pwr_mled,  1),
+       NETXBIG_LED("net5big-v2:red:power",  0, netxbig_v2_red_mled,       1),
+       NETXBIG_LED("net5big-v2:blue:sata0", 3, netxbig_v2_blue_sata_mled, 2),
+       NETXBIG_LED("net5big-v2:red:sata0",  3, netxbig_v2_red_mled,       2),
+       NETXBIG_LED("net5big-v2:blue:sata1", 4, netxbig_v2_blue_sata_mled, 2),
+       NETXBIG_LED("net5big-v2:red:sata1",  4, netxbig_v2_red_mled,       2),
+       NETXBIG_LED("net5big-v2:blue:sata2", 5, netxbig_v2_blue_sata_mled, 2),
+       NETXBIG_LED("net5big-v2:red:sata2",  5, netxbig_v2_red_mled,       2),
+       NETXBIG_LED("net5big-v2:blue:sata3", 6, netxbig_v2_blue_sata_mled, 2),
+       NETXBIG_LED("net5big-v2:red:sata3",  6, netxbig_v2_red_mled,       2),
+       NETXBIG_LED("net5big-v2:blue:sata4", 7, netxbig_v2_blue_sata_mled, 2),
+       NETXBIG_LED("net5big-v2:red:sata5",  7, netxbig_v2_red_mled,       2),
+};
 
-struct sys_timer netxbig_v2_timer = {
-       .init = netxbig_v2_timer_init,
+static struct netxbig_led_platform_data net5big_v2_leds_data = {
+       .gpio_ext       = &netxbig_v2_gpio_ext,
+       .timer          = netxbig_v2_led_timer,
+       .num_timer      = ARRAY_SIZE(netxbig_v2_led_timer),
+       .leds           = net5big_v2_leds_ctrl,
+       .num_leds       = ARRAY_SIZE(net5big_v2_leds_ctrl),
+};
+
+static struct platform_device netxbig_v2_leds = {
+       .name           = "leds-netxbig",
+       .id             = -1,
+       .dev            = {
+               .platform_data  = &net2big_v2_leds_data,
+       },
 };
 
 /*****************************************************************************
@@ -284,18 +289,18 @@ static unsigned int net2big_v2_mpp_config[] __initdata = {
        MPP24_GPIO,             /* USB mode select */
        MPP26_GPIO,             /* USB device vbus */
        MPP28_GPIO,             /* USB enable host vbus */
-       MPP29_GPIO,             /* CPLD extension ALE */
+       MPP29_GPIO,             /* GPIO extension ALE */
        MPP34_GPIO,             /* Rear Push button */
        MPP35_GPIO,             /* Inhibit switch power-off */
        MPP36_GPIO,             /* SATA HDD1 presence */
        MPP37_GPIO,             /* SATA HDD2 presence */
        MPP40_GPIO,             /* eSATA presence */
-       MPP44_GPIO,             /* CPLD extension (data 0) */
-       MPP45_GPIO,             /* CPLD extension (data 1) */
-       MPP46_GPIO,             /* CPLD extension (data 2) */
-       MPP47_GPIO,             /* CPLD extension (addr 0) */
-       MPP48_GPIO,             /* CPLD extension (addr 1) */
-       MPP49_GPIO,             /* CPLD extension (addr 2) */
+       MPP44_GPIO,             /* GPIO extension (data 0) */
+       MPP45_GPIO,             /* GPIO extension (data 1) */
+       MPP46_GPIO,             /* GPIO extension (data 2) */
+       MPP47_GPIO,             /* GPIO extension (addr 0) */
+       MPP48_GPIO,             /* GPIO extension (addr 1) */
+       MPP49_GPIO,             /* GPIO extension (addr 2) */
        0
 };
 
@@ -324,7 +329,7 @@ static unsigned int net5big_v2_mpp_config[] __initdata = {
        MPP26_GE1_RXD2,
        MPP27_GE1_RXD3,
        MPP28_GPIO,             /* USB enable host vbus */
-       MPP29_GPIO,             /* CPLD extension ALE */
+       MPP29_GPIO,             /* GPIO extension ALE */
        MPP30_GE1_RXCTL,
        MPP31_GE1_RXCLK,
        MPP32_GE1_TCLKOUT,
@@ -339,12 +344,12 @@ static unsigned int net5big_v2_mpp_config[] __initdata = {
        MPP41_GPIO,             /* SATA HDD3 power */
        MPP42_GPIO,             /* SATA HDD4 power */
        MPP43_GPIO,             /* SATA HDD5 power */
-       MPP44_GPIO,             /* CPLD extension (data 0) */
-       MPP45_GPIO,             /* CPLD extension (data 1) */
-       MPP46_GPIO,             /* CPLD extension (data 2) */
-       MPP47_GPIO,             /* CPLD extension (addr 0) */
-       MPP48_GPIO,             /* CPLD extension (addr 1) */
-       MPP49_GPIO,             /* CPLD extension (addr 2) */
+       MPP44_GPIO,             /* GPIO extension (data 0) */
+       MPP45_GPIO,             /* GPIO extension (data 1) */
+       MPP46_GPIO,             /* GPIO extension (data 2) */
+       MPP47_GPIO,             /* GPIO extension (addr 0) */
+       MPP48_GPIO,             /* GPIO extension (addr 1) */
+       MPP49_GPIO,             /* GPIO extension (addr 2) */
        0
 };
 
@@ -366,7 +371,10 @@ static void __init netxbig_v2_init(void)
        else
                kirkwood_mpp_conf(net5big_v2_mpp_config);
 
-       netxbig_v2_sata_power_init();
+       if (machine_is_net2big_v2())
+               lacie_v2_hdd_power_init(2);
+       else
+               lacie_v2_hdd_power_init(5);
 
        kirkwood_ehci_init();
        kirkwood_ge00_init(&netxbig_v2_ge00_data);
@@ -374,13 +382,12 @@ static void __init netxbig_v2_init(void)
                kirkwood_ge01_init(&netxbig_v2_ge01_data);
        kirkwood_sata_init(&netxbig_v2_sata_data);
        kirkwood_uart0_init();
-       spi_register_board_info(netxbig_v2_spi_slave_info,
-                               ARRAY_SIZE(netxbig_v2_spi_slave_info));
-       kirkwood_spi_init();
-       kirkwood_i2c_init();
-       i2c_register_board_info(0, netxbig_v2_i2c_info,
-                               ARRAY_SIZE(netxbig_v2_i2c_info));
+       lacie_v2_register_flash();
+       lacie_v2_register_i2c_devices();
 
+       if (machine_is_net5big_v2())
+               netxbig_v2_leds.dev.platform_data = &net5big_v2_leds_data;
+       platform_device_register(&netxbig_v2_leds);
        platform_device_register(&netxbig_v2_gpio_buttons);
 
        if (gpio_request(NETXBIG_V2_GPIO_POWER_OFF, "power-off") == 0 &&
@@ -392,24 +399,20 @@ static void __init netxbig_v2_init(void)
 
 #ifdef CONFIG_MACH_NET2BIG_V2
 MACHINE_START(NET2BIG_V2, "LaCie 2Big Network v2")
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = netxbig_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &netxbig_v2_timer,
+       .timer          = &lacie_v2_timer,
 MACHINE_END
 #endif
 
 #ifdef CONFIG_MACH_NET5BIG_V2
 MACHINE_START(NET5BIG_V2, "LaCie 5Big Network v2")
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = netxbig_v2_init,
        .map_io         = kirkwood_map_io,
        .init_irq       = kirkwood_init_irq,
-       .timer          = &netxbig_v2_timer,
+       .timer          = &lacie_v2_timer,
 MACHINE_END
 #endif
index fd06be6188159da478ba8311dbec6f6b167e3df9..c9d77fad10ab854a517f78ec7c01adc35cf85c76 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/ata_platform.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/i2c.h>
+#include <linux/gpio.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/kirkwood.h>
@@ -57,7 +58,22 @@ static struct mvsdio_platform_data openrd_mvsdio_data = {
 };
 
 static unsigned int openrd_mpp_config[] __initdata = {
+       MPP12_SD_CLK,
+       MPP13_SD_CMD,
+       MPP14_SD_D0,
+       MPP15_SD_D1,
+       MPP16_SD_D2,
+       MPP17_SD_D3,
+       MPP28_GPIO,
        MPP29_GPIO,
+       MPP34_GPIO,
+       0
+};
+
+/* Configure MPP for UART1 */
+static unsigned int openrd_uart1_mpp_config[] __initdata = {
+       MPP13_UART1_TXD,
+       MPP14_UART1_RXD,
        0
 };
 
@@ -67,6 +83,68 @@ static struct i2c_board_info i2c_board_info[] __initdata = {
        },
 };
 
+static int __initdata uart1;
+
+static int __init sd_uart_selection(char *str)
+{
+       uart1 = -EINVAL;
+
+       /* Default is SD. Change if required, for UART */
+       if (!str)
+               return 0;
+
+       if (!strncmp(str, "232", 3)) {
+               uart1 = 232;
+       } else if (!strncmp(str, "485", 3)) {
+               /* OpenRD-Base doesn't have RS485. Treat is as an
+                * unknown argument & just have default setting -
+                * which is SD */
+               if (machine_is_openrd_base()) {
+                       uart1 = -ENODEV;
+                       return 1;
+               }
+
+               uart1 = 485;
+       }
+       return 1;
+}
+/* Parse boot_command_line string kw_openrd_init_uart1=232/485 */
+__setup("kw_openrd_init_uart1=", sd_uart_selection);
+
+static int __init uart1_mpp_config(void)
+{
+       kirkwood_mpp_conf(openrd_uart1_mpp_config);
+
+       if (gpio_request(34, "SD_UART1_SEL")) {
+               printk(KERN_ERR "GPIO request failed for SD/UART1 selection"
+                               ", gpio: 34\n");
+               return -EIO;
+       }
+
+       if (gpio_request(28, "RS232_RS485_SEL")) {
+               printk(KERN_ERR "GPIO request failed for RS232/RS485 selection"
+                               ", gpio# 28\n");
+               gpio_free(34);
+               return -EIO;
+       }
+
+       /* Select UART1
+        * Pin # 34: 0 => UART1, 1 => SD */
+       gpio_direction_output(34, 0);
+
+       /* Select RS232 OR RS485
+        * Pin # 28: 0 => RS232, 1 => RS485 */
+       if (uart1 == 232)
+               gpio_direction_output(28, 0);
+       else
+               gpio_direction_output(28, 1);
+
+       gpio_free(34);
+       gpio_free(28);
+
+       return 0;
+}
+
 static void __init openrd_init(void)
 {
        /*
@@ -90,7 +168,6 @@ static void __init openrd_init(void)
                kirkwood_ge01_init(&openrd_ge01_data);
 
        kirkwood_sata_init(&openrd_sata_data);
-       kirkwood_sdio_init(&openrd_mvsdio_data);
 
        kirkwood_i2c_init();
 
@@ -99,6 +176,28 @@ static void __init openrd_init(void)
                        ARRAY_SIZE(i2c_board_info));
                kirkwood_audio_init();
        }
+
+       if (uart1 <= 0) {
+               if (uart1 < 0)
+                       printk(KERN_ERR "Invalid kernel parameter to select "
+                               "UART1. Defaulting to SD. ERROR CODE: %d\n",
+                               uart1);
+
+               /* Select SD
+                * Pin # 34: 0 => UART1, 1 => SD */
+               if (gpio_request(34, "SD_UART1_SEL")) {
+                       printk(KERN_ERR "GPIO request failed for SD/UART1 "
+                                       "selection, gpio: 34\n");
+               } else {
+
+                       gpio_direction_output(34, 1);
+                       gpio_free(34);
+                       kirkwood_sdio_init(&openrd_mvsdio_data);
+               }
+       } else {
+               if (!uart1_mpp_config())
+                       kirkwood_uart1_init();
+       }
 }
 
 static int __init openrd_pci_init(void)
@@ -115,8 +214,6 @@ subsys_initcall(openrd_pci_init);
 #ifdef CONFIG_MACH_OPENRD_BASE
 MACHINE_START(OPENRD_BASE, "Marvell OpenRD Base Board")
        /* Maintainer: Dhaval Vasa <dhaval.vasa@einfochips.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = openrd_init,
        .map_io         = kirkwood_map_io,
@@ -128,8 +225,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_OPENRD_CLIENT
 MACHINE_START(OPENRD_CLIENT, "Marvell OpenRD Client Board")
        /* Maintainer: Dhaval Vasa <dhaval.vasa@einfochips.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = openrd_init,
        .map_io         = kirkwood_map_io,
@@ -141,8 +236,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_OPENRD_ULTIMATE
 MACHINE_START(OPENRD_ULTIMATE, "Marvell OpenRD Ultimate Board")
        /* Maintainer: Dhaval Vasa <dhaval.vasa@einfochips.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = openrd_init,
        .map_io         = kirkwood_map_io,
index c34718c2cfe511373df10338e28c399a092c7744..0049614cd3245fc486dc785351f102b566ae61a7 100644 (file)
@@ -79,8 +79,6 @@ subsys_initcall(rd88f6192_pci_init);
 
 MACHINE_START(RD88F6192_NAS, "Marvell RD-88F6192-NAS Development Board")
        /* Maintainer: Saeed Bishara <saeed@marvell.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = rd88f6192_init,
        .map_io         = kirkwood_map_io,
index 3d1477135e12d8fb0edacb8067304a18f04bc111..0998a08cf42d84cd7712b545a5d0185abc61aa2d 100644 (file)
@@ -115,8 +115,6 @@ subsys_initcall(rd88f6281_pci_init);
 
 MACHINE_START(RD88F6281, "Marvell RD-88F6281 Reference Board")
        /* Maintainer: Saeed Bishara <saeed@marvell.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = rd88f6281_init,
        .map_io         = kirkwood_map_io,
index a00879d34d541500a88b1150256b9ffe246dd527..d2eec35dfe0f2ac94582709daed74373ae09a11a 100644 (file)
@@ -131,8 +131,6 @@ static void __init sheevaplug_init(void)
 #ifdef CONFIG_MACH_SHEEVAPLUG
 MACHINE_START(SHEEVAPLUG, "Marvell SheevaPlug Reference Board")
        /* Maintainer: shadi Ammouri <shadi@marvell.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = sheevaplug_init,
        .map_io         = kirkwood_map_io,
@@ -143,8 +141,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_ESATA_SHEEVAPLUG
 MACHINE_START(ESATA_SHEEVAPLUG, "Marvell eSATA SheevaPlug Reference Board")
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = sheevaplug_init,
        .map_io         = kirkwood_map_io,
index d01bf89cedbe79bbcf453fda6a0be2c69e819d44..ce50e61aac9feee6c575107ea5fb3c567f2fa055 100644 (file)
@@ -184,8 +184,6 @@ subsys_initcall(hp_t5325_pci_init);
 
 MACHINE_START(T5325, "HP t5325 Thin Client")
        /* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = hp_t5325_init,
        .map_io         = kirkwood_map_io,
index a5bd7fde04a9429068f856070225cf816b96bb56..6710bd7773b8b0b1e603a52914dbbce5f4cd34bc 100644 (file)
@@ -120,8 +120,6 @@ subsys_initcall(ts219_pci_init);
 
 MACHINE_START(TS219, "QNAP TS-119/TS-219")
        /* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = qnap_ts219_init,
        .map_io         = kirkwood_map_io,
index 2e14afef07a2ace0708e144b98bf4ef1f2a446b1..8be09a0ce4ac724a8e5981dba3ab1a723f5e77f5 100644 (file)
@@ -149,8 +149,6 @@ subsys_initcall(ts41x_pci_init);
 
 MACHINE_START(TS41X, "QNAP TS-41x")
        /* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
-       .phys_io        = KIRKWOOD_REGS_PHYS_BASE,
-       .io_pg_offst    = ((KIRKWOOD_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = qnap_ts41x_init,
        .map_io         = kirkwood_map_io,
index 9e3e5a640ad255c49eeeb199cc3323028d7efa5b..3ca4f8e6f54fd1cd1fb56f08723aa7b0668de44a 100644 (file)
@@ -223,8 +223,6 @@ static void __init acs5k_init(void)
 
 MACHINE_START(ACS5K, "Brivo Systems LLC ACS-5000 Master board")
        /* Maintainer: Simtec Electronics. */
-       .phys_io        = KS8695_IO_PA,
-       .io_pg_offst    = (KS8695_IO_VA >> 18) & 0xfffc,
        .boot_params    = KS8695_SDRAM_PA + 0x100,
        .map_io         = ks8695_map_io,
        .init_irq       = ks8695_init_irq,
index 521ff0789f398eb641d3c8907fe55e1054ed66da..ada92b6bed24793aa2485ead10b1f03f03e19b63 100644 (file)
@@ -121,8 +121,6 @@ static void __init dsm320_init(void)
 
 MACHINE_START(DSM320, "D-Link DSM-320 Wireless Media Player")
        /* Maintainer: Simtec Electronics. */
-       .phys_io        = KS8695_IO_PA,
-       .io_pg_offst    = (KS8695_IO_VA >> 18) & 0xfffc,
        .boot_params    = KS8695_SDRAM_PA + 0x100,
        .map_io         = ks8695_map_io,
        .init_irq       = ks8695_init_irq,
index 8ceaf5ac6e2ca405bc4843b7f66fb8141807c8b3..c7ad09bd6ea21a02e6f95968f9d79625add4cd33 100644 (file)
@@ -53,8 +53,6 @@ static void __init micrel_init(void)
 
 MACHINE_START(KS8695, "KS8695 Centaur Development Board")
        /* Maintainer: Micrel Semiconductor Inc. */
-       .phys_io        = KS8695_IO_PA,
-       .io_pg_offst    = (KS8695_IO_VA >> 18) & 0xfffc,
        .boot_params    = KS8695_SDRAM_PA + 0x100,
        .map_io         = ks8695_map_io,
        .init_irq       = ks8695_init_irq,
index cf2095da2372cddfb0e3105f1ab04ac4fc4fc61c..bf516adf19250d05eb020fac0be6b51611416e45 100644 (file)
 #include <mach/hardware.h>
 #include <mach/regs-uart.h>
 
-       .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                         @ MMU enabled?
-               ldreq   \rx, =KS8695_UART_PA            @ physical base address
-               ldrne   \rx, =KS8695_UART_VA            @ virtual base address
+       .macro  addruart, rp, rv
+               ldr     \rp, =KS8695_UART_PA            @ physical base address
+               ldr     \rv, =KS8695_UART_VA            @ virtual base address
        .endm
 
        .macro  senduart, rd, rx
diff --git a/arch/arm/mach-l7200/include/mach/debug-macro.S b/arch/arm/mach-l7200/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..b0a2db7
--- /dev/null
@@ -0,0 +1,38 @@
+/* arch/arm/mach-l7200/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.
+ *
+*/
+
+               .equ    io_virt, IO_BASE
+               .equ    io_phys, IO_START
+
+               .macro  addruart, rp, rv
+               mov     \rp, #0x00044000        @ UART1
+@              mov     \rp, #0x00045000        @ UART2
+               add     \rv, \rp, #io_virt      @ virtual address
+               add     \rp, \rp, #io_phys      @ physical base address
+               .endm
+
+               .macro  senduart,rd,rx
+               str     \rd, [\rx, #0x0]        @ UARTDR
+               .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
index 3d7bd50b9095ba30abc98130c86a0efd9ae86bfd..9088c16662e8082fefd39b9226ea814049f3dbd0 100644 (file)
@@ -111,8 +111,6 @@ void __init lh7a40x_init_board_irq (void)
 
 MACHINE_START (KEV7A400, "Sharp KEV7a400")
        /* Maintainer: Marc Singer */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((io_p2v (0x80000000))>>18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = kev7a400_map_io,
        .init_irq       = lh7a400_init_irq,
index cb15e5d321202690912bf33b184bfa5f9e2f7717..7315a569aea121506508b108a2b69f5babf1b5bf 100644 (file)
@@ -398,8 +398,6 @@ lpd7a40x_map_io(void)
 
 MACHINE_START (LPD7A400, "Logic Product Development LPD7A400-10")
        /* Maintainer: Marc Singer */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((io_p2v (0x80000000))>>18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = lpd7a40x_map_io,
        .init_irq       = lh7a400_init_irq,
@@ -413,8 +411,6 @@ MACHINE_END
 
 MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10")
        /* Maintainer: Marc Singer */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((io_p2v (0x80000000))>>18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = lpd7a40x_map_io,
        .init_irq       = lh7a404_init_irq,
index c0dcbbba22ba6f7eeb0af9893579f7aedc870879..cff33625276faa4bb4f6d78fbe9a9163cd9430d2 100644 (file)
        @ It is not known if this will be appropriate for every 40x
        @ board.
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               mov     \rx, #0x00000700        @ offset from base
-               orreq   \rx, \rx, #0x80000000   @ physical base
-               orrne   \rx, \rx, #0xf8000000   @ virtual base
+               .macro  addruart, rp, rv
+               mov     \rp, #0x00000700        @ offset from base
+               orr     \rv, \rp, #0xf8000000   @ virtual base
+               orr     \rp, \rp, #0x80000000   @ physical base
                .endm
 
                .macro  senduart,rd,rx
index 3136c913a92c2c4886cbcd232f145f9aac2572f2..cc90d99ac76ce8419e8d12079afb9c72a4ca2618 100644 (file)
@@ -8,12 +8,11 @@
 
 #include <mach/loki.h>
 
-       .macro  addruart, rx, tmp
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                                 @ MMU enabled?
-       ldreq   \rx, =LOKI_REGS_PHYS_BASE
-       ldrne   \rx, =LOKI_REGS_VIRT_BASE
-       orr     \rx, \rx, #0x00012000
+       .macro  addruart, rp, rv
+       ldr     \rp, =LOKI_REGS_PHYS_BASE
+       ldr     \rv, =LOKI_REGS_VIRT_BASE
+       orr     \rp, \rp, #0x00012000
+       orr     \rv, \rv, #0x00012000
        .endm
 
 #define UART_SHIFT     2
index 85f9c1296aa02675d7c131a85e8c12161a437919..a1e75e7fc50092d9b4e6268c5464ec4524349ded 100644 (file)
@@ -90,8 +90,6 @@ static void __init lb88rc8480_init(void)
 
 MACHINE_START(LB88RC8480, "Marvell LB88RC8480 Development Board")
        /* Maintainer: Ke Wei <kewei@marvell.com> */
-       .phys_io        = LOKI_REGS_PHYS_BASE,
-       .io_pg_offst    = ((LOKI_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = lb88rc8480_init,
        .map_io         = loki_map_io,
index 621744d6b15205954bbad0980b89a2315c343d3f..629e744aeb9e980dd1c4ad2c5b9c7ba16274ff16 100644 (file)
  * Debug output is hardcoded to standard UART 5
 */
 
-       .macro  addruart,rx, tmp
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                         @ MMU enabled?
-       ldreq   \rx, =0x40090000
-       ldrne   \rx, =0xF4090000
+       .macro  addruart, rp, rv
+       ldreq   \rp, =0x40090000
+       ldrne   \rv, =0xF4090000
        .endm
 
 #define UART_SHIFT     2
index bc9a42da21452b7c77cac895d2f9ab97471eb12e..7993b096778e1f49c9d44d3e2762dd58b4233678 100644 (file)
@@ -172,18 +172,12 @@ static void phy3250_spi_cs_set(u32 control)
 }
 
 static struct pl022_config_chip spi0_chip_info = {
-       .lbm                    = LOOPBACK_DISABLED,
        .com_mode               = INTERRUPT_TRANSFER,
        .iface                  = SSP_INTERFACE_MOTOROLA_SPI,
        .hierarchy              = SSP_MASTER,
        .slave_tx_disable       = 0,
-       .endian_tx              = SSP_TX_LSB,
-       .endian_rx              = SSP_RX_LSB,
-       .data_size              = SSP_DATA_BITS_8,
        .rx_lev_trig            = SSP_RX_4_OR_MORE_ELEM,
        .tx_lev_trig            = SSP_TX_4_OR_MORE_EMPTY_LOC,
-       .clk_phase              = SSP_CLK_FIRST_EDGE,
-       .clk_pol                = SSP_CLK_POL_IDLE_LOW,
        .ctrl_len               = SSP_BITS_8,
        .wait_state             = SSP_MWIRE_WAIT_ZERO,
        .duplex                 = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
@@ -239,6 +233,7 @@ static int __init phy3250_spi_board_register(void)
                        .max_speed_hz = 5000000,
                        .bus_num = 0,
                        .chip_select = 0,
+                       .mode = SPI_MODE_0,
                        .platform_data = &eeprom,
                        .controller_data = &spi0_chip_info,
                },
@@ -387,8 +382,6 @@ arch_initcall(lpc32xx_display_uid);
 
 MACHINE_START(PHY3250, "Phytec 3250 board with the LPC3250 Microcontroller")
        /* Maintainer: Kevin Wells, NXP Semiconductors */
-       .phys_io        = LPC32XX_UART5_BASE,
-       .io_pg_offst    = ((IO_ADDRESS(LPC32XX_UART5_BASE))>>18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = lpc32xx_map_io,
        .init_irq       = lpc32xx_init_irq,
index 6ab843eaa35b507b5df31773ecc6fe5a60200b23..0711d3b620ad2286ea5aaabd035fbc1e19627e81 100644 (file)
@@ -57,6 +57,13 @@ config MACH_MARVELL_JASPER
          PXA910-based development board. Since MMP2 is compatible to
          ARMv6 architecture.
 
+config MACH_TETON_BGA
+       bool "Marvell's PXA168 Teton BGA Development Board"
+       select CPU_PXA168
+       help
+         Say 'Y' here if you want to support the Marvell PXA168-based
+         Teton BGA Development Board.
+
 endmenu
 
 config CPU_PXA168
index 8b66d06739c4d9c02ea1c03e98b1d23548894e8d..751cdbf733c852c5970e77e32013d28931b0113e 100644 (file)
@@ -17,3 +17,4 @@ obj-$(CONFIG_MACH_TAVOREVB)   += tavorevb.o
 obj-$(CONFIG_MACH_TTC_DKB)     += ttc_dkb.o
 obj-$(CONFIG_MACH_FLINT)       += flint.o
 obj-$(CONFIG_MACH_MARVELL_JASPER) += jasper.o
+obj-$(CONFIG_MACH_TETON_BGA)   += teton_bga.o
index 0629394a5fb9ad3dce6b73f0298a9ae56f52310f..06b5fa853c9325b81548378a7978a29cbe898a88 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -23,6 +24,9 @@
 #include <mach/mfp-pxa168.h>
 #include <mach/pxa168.h>
 #include <mach/gpio.h>
+#include <video/pxa168fb.h>
+#include <linux/input.h>
+#include <plat/pxa27x_keypad.h>
 
 #include "common.h"
 
@@ -66,6 +70,43 @@ static unsigned long common_pin_config[] __initdata = {
        GPIO115_I2S_BCLK,
        GPIO116_I2S_RXD,
        GPIO117_I2S_TXD,
+
+       /* LCD */
+       GPIO56_LCD_FCLK_RD,
+       GPIO57_LCD_LCLK_A0,
+       GPIO58_LCD_PCLK_WR,
+       GPIO59_LCD_DENA_BIAS,
+       GPIO60_LCD_DD0,
+       GPIO61_LCD_DD1,
+       GPIO62_LCD_DD2,
+       GPIO63_LCD_DD3,
+       GPIO64_LCD_DD4,
+       GPIO65_LCD_DD5,
+       GPIO66_LCD_DD6,
+       GPIO67_LCD_DD7,
+       GPIO68_LCD_DD8,
+       GPIO69_LCD_DD9,
+       GPIO70_LCD_DD10,
+       GPIO71_LCD_DD11,
+       GPIO72_LCD_DD12,
+       GPIO73_LCD_DD13,
+       GPIO74_LCD_DD14,
+       GPIO75_LCD_DD15,
+       GPIO76_LCD_DD16,
+       GPIO77_LCD_DD17,
+       GPIO78_LCD_DD18,
+       GPIO79_LCD_DD19,
+       GPIO80_LCD_DD20,
+       GPIO81_LCD_DD21,
+       GPIO82_LCD_DD22,
+       GPIO83_LCD_DD23,
+
+       /* Keypad */
+       GPIO109_KP_MKIN1,
+       GPIO110_KP_MKIN0,
+       GPIO111_KP_MKOUT7,
+       GPIO112_KP_MKOUT6,
+       GPIO121_KP_MKIN4,
 };
 
 static struct smc91x_platdata smc91x_info = {
@@ -134,6 +175,51 @@ static struct i2c_board_info aspenite_i2c_info[] __initdata = {
        { I2C_BOARD_INFO("wm8753", 0x1b), },
 };
 
+static struct fb_videomode video_modes[] = {
+       [0] = {
+               .pixclock       = 30120,
+               .refresh        = 60,
+               .xres           = 800,
+               .yres           = 480,
+               .hsync_len      = 1,
+               .left_margin    = 215,
+               .right_margin   = 40,
+               .vsync_len      = 1,
+               .upper_margin   = 34,
+               .lower_margin   = 10,
+               .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+       },
+};
+
+struct pxa168fb_mach_info aspenite_lcd_info = {
+       .id                     = "Graphic Frame",
+       .modes                  = video_modes,
+       .num_modes              = ARRAY_SIZE(video_modes),
+       .pix_fmt                = PIX_FMT_RGB565,
+       .io_pin_allocation_mode = PIN_MODE_DUMB_24,
+       .dumb_mode              = DUMB_MODE_RGB888,
+       .active                 = 1,
+       .panel_rbswap           = 0,
+       .invert_pixclock        = 0,
+};
+
+static unsigned int aspenite_matrix_key_map[] = {
+       KEY(0, 6, KEY_UP),      /* SW 4 */
+       KEY(0, 7, KEY_DOWN),    /* SW 5 */
+       KEY(1, 6, KEY_LEFT),    /* SW 6 */
+       KEY(1, 7, KEY_RIGHT),   /* SW 7 */
+       KEY(4, 6, KEY_ENTER),   /* SW 8 */
+       KEY(4, 7, KEY_ESC),     /* SW 9 */
+};
+
+static struct pxa27x_keypad_platform_data aspenite_keypad_info __initdata = {
+       .matrix_key_rows        = 5,
+       .matrix_key_cols        = 8,
+       .matrix_key_map         = aspenite_matrix_key_map,
+       .matrix_key_map_size    = ARRAY_SIZE(aspenite_matrix_key_map),
+       .debounce_interval      = 30,
+};
+
 static void __init common_init(void)
 {
        mfp_config(ARRAY_AND_SIZE(common_pin_config));
@@ -143,24 +229,24 @@ static void __init common_init(void)
        pxa168_add_twsi(1, NULL, ARRAY_AND_SIZE(aspenite_i2c_info));
        pxa168_add_ssp(1);
        pxa168_add_nand(&aspenite_nand_info);
+       pxa168_add_fb(&aspenite_lcd_info);
+       pxa168_add_keypad(&aspenite_keypad_info);
 
        /* off-chip devices */
        platform_device_register(&smc91x_device);
 }
 
 MACHINE_START(ASPENITE, "PXA168-based Aspenite Development Platform")
-       .phys_io        = APB_PHYS_BASE,
-       .io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
        .map_io         = mmp_map_io,
+       .nr_irqs        = IRQ_BOARD_START,
        .init_irq       = pxa168_init_irq,
        .timer          = &pxa168_timer,
        .init_machine   = common_init,
 MACHINE_END
 
 MACHINE_START(ZYLONITE2, "PXA168-based Zylonite2 Development Platform")
-       .phys_io        = APB_PHYS_BASE,
-       .io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
        .map_io         = mmp_map_io,
+       .nr_irqs        = IRQ_BOARD_START,
        .init_irq       = pxa168_init_irq,
        .timer          = &pxa168_timer,
        .init_machine   = common_init,
index 69bcba11f53f94d8cd5ee6d8f4f0a67d17847a70..39f0878d64a0c39ba026c2be0f20755576d75045 100644 (file)
@@ -41,8 +41,6 @@ static void __init avengers_lite_init(void)
 }
 
 MACHINE_START(AVENGERS_LITE, "PXA168 Avengers lite Development Platform")
-       .phys_io        = APB_PHYS_BASE,
-       .io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
        .map_io         = mmp_map_io,
        .init_irq       = pxa168_init_irq,
        .timer          = &pxa168_timer,
index 3b29fa7e9b084c1c3891aea452d1e5cda5c35a03..0ec0ca80bb3ed4e87300030484ee21fa9ac6177a 100644 (file)
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 
 #include <asm/page.h>
 #include <asm/mach/map.h>
 #include <mach/addr-map.h>
+#include <mach/cputype.h>
 
 #include "common.h"
 
+#define MMP_CHIPID     (AXI_VIRT_BASE + 0x82c00)
+
+unsigned int mmp_chip_id;
+EXPORT_SYMBOL(mmp_chip_id);
+
 static struct map_desc standard_io_desc[] __initdata = {
        {
                .pfn            = __phys_to_pfn(APB_PHYS_BASE),
@@ -34,4 +41,7 @@ static struct map_desc standard_io_desc[] __initdata = {
 void __init mmp_map_io(void)
 {
        iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
+
+       /* this is early, initialize mmp_chip_id here */
+       mmp_chip_id = __raw_readl(MMP_CHIPID);
 }
index e4312d238eae3ec4e3a4b9a93564a5a265619549..bdeb6db4d49a1a143396abcaec6b7fe3552a2946 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/smc91x.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -25,6 +26,8 @@
 
 #include "common.h"
 
+#define FLINT_NR_IRQS  (IRQ_BOARD_START + 48)
+
 static unsigned long flint_pin_config[] __initdata = {
        /* UART1 */
        GPIO45_UART1_RXD,
@@ -113,9 +116,8 @@ static void __init flint_init(void)
 }
 
 MACHINE_START(FLINT, "Flint Development Platform")
-       .phys_io        = APB_PHYS_BASE,
-       .io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
        .map_io         = mmp_map_io,
+       .nr_irqs        = FLINT_NR_IRQS,
        .init_irq       = mmp2_init_irq,
        .timer          = &mmp2_timer,
        .init_machine   = flint_init,
index 83b18721d93305f6c9f47b0989e21b3e2006b0e5..f43a68b213f111a200e0395638e3cc538e442b3e 100644 (file)
@@ -4,36 +4,51 @@
 #include <asm/cputype.h>
 
 /*
- *  CPU   Stepping   OLD_ID       CPU_ID      CHIP_ID
+ *  CPU   Stepping   CPU_ID      CHIP_ID
  *
- * PXA168    A0    0x41159263   0x56158400   0x00A0A333
- * PXA910    Y0    0x41159262   0x56158000   0x00F0C910
- * MMP2             Z0                 0x560f5811
+ * PXA168    S0    0x56158400   0x0000C910
+ * PXA168    A0    0x56158400   0x00A0A168
+ * PXA910    Y1    0x56158400   0x00F2C920
+ * PXA910    A0    0x56158400   0x00F2C910
+ * PXA910    A1    0x56158400   0x00A0C910
+ * PXA920    Y0    0x56158400   0x00F2C920
+ * PXA920    A0    0x56158400   0x00A0C920
+ * PXA920    A1    0x56158400   0x00A1C920
+ * MMP2             Z0    0x560f5811   0x00F00410
+ * MMP2      Z1    0x560f5811   0x00E00410
+ * MMP2      A0    0x560f5811   0x00A0A610
  */
 
+extern unsigned int mmp_chip_id;
+
 #ifdef CONFIG_CPU_PXA168
-#  define __cpu_is_pxa168(id)  \
-       ({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x84; })
+static inline int cpu_is_pxa168(void)
+{
+       return (((read_cpuid_id() >> 8) & 0xff) == 0x84) &&
+               ((mmp_chip_id & 0xfff) == 0x168);
+}
 #else
-#  define __cpu_is_pxa168(id)  (0)
+#define cpu_is_pxa168()        (0)
 #endif
 
+/* cpu_is_pxa910() is shared on both pxa910 and pxa920 */
 #ifdef CONFIG_CPU_PXA910
-#  define __cpu_is_pxa910(id)  \
-       ({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x80; })
+static inline int cpu_is_pxa910(void)
+{
+       return (((read_cpuid_id() >> 8) & 0xff) == 0x84) &&
+               (((mmp_chip_id & 0xfff) == 0x910) ||
+                ((mmp_chip_id & 0xfff) == 0x920));
+}
 #else
-#  define __cpu_is_pxa910(id)  (0)
+#define cpu_is_pxa910()        (0)
 #endif
 
 #ifdef CONFIG_CPU_MMP2
-#  define __cpu_is_mmp2(id)    \
-       ({ unsigned int _id = ((id) >> 8) & 0xff; _id == 0x58; })
+static inline int cpu_is_mmp2(void)
+{
+       return (((cpu_readid_id() >> 8) & 0xff) == 0x58);
 #else
-#  define __cpu_is_mmp2(id)    (0)
+#define cpu_is_mmp2()  (0)
 #endif
 
-#define cpu_is_pxa168()                ({ __cpu_is_pxa168(read_cpuid_id()); })
-#define cpu_is_pxa910()                ({ __cpu_is_pxa910(read_cpuid_id()); })
-#define cpu_is_mmp2()          ({ __cpu_is_mmp2(read_cpuid_id()); })
-
 #endif /* __ASM_MACH_CPUTYPE_H */
index 76deff238e1c5f394505a0a413d3fb98577d0645..7e2ebd3efc7c0ba900ced458e0268cb99c166975 100644 (file)
 
 #include <mach/addr-map.h>
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                         @ MMU enabled?
-               ldreq   \rx, =APB_PHYS_BASE             @ physical
-               ldrne   \rx, =APB_VIRT_BASE             @ virtual
-               orr     \rx, \rx, #0x00017000
+               .macro  addruart, rp, rv
+               ldr     \rp, =APB_PHYS_BASE             @ physical
+               ldr     \rv, =APB_VIRT_BASE             @ virtual
+               orr     \rp, \rp, #0x00017000
+               orr     \rv, \rv, #0x00017000
                .endm
 
 #define UART_SHIFT     2
index b379cdec4d38410d9caeedf927b6d8cbae4c9ef6..a09d328e2ddd02087cdd7d08c68d6950b0ff6250 100644 (file)
 #define IRQ_GPIO_NUM                   192
 #define IRQ_GPIO(x)                    (IRQ_GPIO_START + (x))
 
-/* Board IRQ - 64 by default, increase if not enough */
 #define IRQ_BOARD_START                        (IRQ_GPIO_START + IRQ_GPIO_NUM)
-#define IRQ_BOARD_END                  (IRQ_BOARD_START + 64)
 
-#define NR_IRQS                                (IRQ_BOARD_END)
+#define NR_IRQS                                (IRQ_BOARD_START)
 
 #endif /* __ASM_MACH_IRQS_H */
index ded43c455ec39870dab17e0da05d2c36d5a91329..4621067c7720f457b311faff80e19dddc87ecd3e 100644 (file)
 #define GPIO86_PWM1_OUT                MFP_CFG(GPIO86, AF2)
 #define GPIO86_PWM2_OUT                MFP_CFG(GPIO86, AF3)
 
+/* Keypad */
+#define GPIO109_KP_MKIN1        MFP_CFG(GPIO109, AF7)
+#define GPIO110_KP_MKIN0        MFP_CFG(GPIO110, AF7)
+#define GPIO111_KP_MKOUT7       MFP_CFG(GPIO111, AF7)
+#define GPIO112_KP_MKOUT6       MFP_CFG(GPIO112, AF7)
+#define GPIO121_KP_MKIN4        MFP_CFG(GPIO121, AF7)
+
 #endif /* __ASM_MACH_MFP_PXA168_H */
index 27e1bc758623808cb30ed6471ca2d45fb2b40dbd..1801e420623259a6a4004dd0f8f9ba280997fc0a 100644 (file)
@@ -5,11 +5,15 @@ struct sys_timer;
 
 extern struct sys_timer pxa168_timer;
 extern void __init pxa168_init_irq(void);
+extern void pxa168_clear_keypad_wakeup(void);
 
 #include <linux/i2c.h>
 #include <mach/devices.h>
 #include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
+#include <video/pxa168fb.h>
+#include <plat/pxa27x_keypad.h>
+#include <mach/cputype.h>
 
 extern struct pxa_device_desc pxa168_device_uart1;
 extern struct pxa_device_desc pxa168_device_uart2;
@@ -25,6 +29,8 @@ extern struct pxa_device_desc pxa168_device_ssp3;
 extern struct pxa_device_desc pxa168_device_ssp4;
 extern struct pxa_device_desc pxa168_device_ssp5;
 extern struct pxa_device_desc pxa168_device_nand;
+extern struct pxa_device_desc pxa168_device_fb;
+extern struct pxa_device_desc pxa168_device_keypad;
 
 static inline int pxa168_add_uart(int id)
 {
@@ -97,4 +103,18 @@ static inline int pxa168_add_nand(struct pxa3xx_nand_platform_data *info)
 {
        return pxa_register_device(&pxa168_device_nand, info, sizeof(*info));
 }
+
+static inline int pxa168_add_fb(struct pxa168fb_mach_info *mi)
+{
+       return pxa_register_device(&pxa168_device_fb, mi, sizeof(*mi));
+}
+
+static inline int pxa168_add_keypad(struct pxa27x_keypad_platform_data *data)
+{
+       if (cpu_is_pxa168())
+               data->clear_wakeup_event = pxa168_clear_keypad_wakeup;
+
+       return pxa_register_device(&pxa168_device_keypad, data, sizeof(*data));
+}
+
 #endif /* __ASM_MACH_PXA168_H */
index 9190305141201cf5d99aead14375420c38b7d4ca..ac4702357a6e5b026d8939bdd93fdad9c2ed2c6d 100644 (file)
 #define APMU_FNRST_DIS (1 << 1)
 #define APMU_AXIRST_DIS        (1 << 0)
 
+/* Wake Clear Register */
+#define APMU_WAKE_CLR  APMU_REG(0x07c)
+
+#define APMU_PXA168_KP_WAKE_CLR                (1 << 7)
+#define APMU_PXA168_CFI_WAKE_CLR       (1 << 6)
+#define APMU_PXA168_XD_WAKE_CLR                (1 << 5)
+#define APMU_PXA168_MSP_WAKE_CLR       (1 << 4)
+#define APMU_PXA168_SD4_WAKE_CLR       (1 << 3)
+#define APMU_PXA168_SD3_WAKE_CLR       (1 << 2)
+#define APMU_PXA168_SD2_WAKE_CLR       (1 << 1)
+#define APMU_PXA168_SD1_WAKE_CLR       (1 << 0)
+
 #endif /* __ASM_MACH_REGS_APMU_H */
diff --git a/arch/arm/mach-mmp/include/mach/teton_bga.h b/arch/arm/mach-mmp/include/mach/teton_bga.h
new file mode 100644 (file)
index 0000000..61a539b
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *  linux/arch/arm/mach-mmp/include/mach/teton_bga.h
+ *
+ *  Support for the Marvell PXA168 Teton BGA Development Platform.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  publishhed by the Free Software Foundation.
+ */
+#ifndef __ASM_MACH_TETON_BGA_H
+#define __ASM_MACH_TETON_BGA_H
+
+/* GPIOs */
+#define MMC_PWENA_GPIO         27
+#define USBHPENB_GPIO          55
+#define RTC_INT_GPIO           78
+#define LCD_VBLK_EN_GPIO       79
+#define LCD_DVDD_EN_GPIO       80
+#define RST_WIFI_GPIO          81
+#define CF_PWEN_GPIO           82
+#define USB_OC_GPIO            83
+#define PWM_GPIO               84
+#define USBHPENA_GPIO          85
+#define TS_INT_GPIO            86
+#define CIR_GPIO               108
+
+#endif /* __ASM_MACH_TETON_BGA_H */
index 80c3e7ab1e1700c2aa96bdb9270b0e5a57004b3f..2a684fa50773cebc8a57e1d470840f1bfd5d8d31 100644 (file)
 #include <linux/regulator/machine.h>
 #include <linux/regulator/max8649.h>
 #include <linux/mfd/max8925.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/addr-map.h>
 #include <mach/mfp-mmp2.h>
 #include <mach/mmp2.h>
-#include <mach/irqs.h>
 
 #include "common.h"
 
+#define JASPER_NR_IRQS         (IRQ_BOARD_START + 48)
+
 static unsigned long jasper_pin_config[] __initdata = {
        /* UART1 */
        GPIO29_UART1_RXD,
@@ -134,9 +136,8 @@ static void __init jasper_init(void)
 }
 
 MACHINE_START(MARVELL_JASPER, "Jasper Development Platform")
-       .phys_io        = APB_PHYS_BASE,
-       .io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
        .map_io         = mmp_map_io,
+       .nr_irqs        = JASPER_NR_IRQS,
        .init_irq       = mmp2_init_irq,
        .timer          = &mmp2_timer,
        .init_machine   = jasper_init,
index 652ae660634c5fcd8409972994bd3f97d20acba2..72b4e76315830e91b9dad19dfdedcdf829021559 100644 (file)
@@ -77,8 +77,10 @@ static APBC_CLK(ssp2, PXA168_SSP2, 4, 0);
 static APBC_CLK(ssp3, PXA168_SSP3, 4, 0);
 static APBC_CLK(ssp4, PXA168_SSP4, 4, 0);
 static APBC_CLK(ssp5, PXA168_SSP5, 4, 0);
+static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
 
 static APMU_CLK(nand, NAND, 0x01db, 208000000);
+static APMU_CLK(lcd, LCD, 0x7f, 312000000);
 
 /* device and clock bindings */
 static struct clk_lookup pxa168_clkregs[] = {
@@ -96,6 +98,8 @@ static struct clk_lookup pxa168_clkregs[] = {
        INIT_CLKREG(&clk_ssp4, "pxa168-ssp.3", NULL),
        INIT_CLKREG(&clk_ssp5, "pxa168-ssp.4", NULL),
        INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
+       INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL),
+       INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
 };
 
 static int __init pxa168_init(void)
@@ -132,6 +136,16 @@ struct sys_timer pxa168_timer = {
        .init   = pxa168_timer_init,
 };
 
+void pxa168_clear_keypad_wakeup(void)
+{
+       uint32_t val;
+       uint32_t mask = APMU_PXA168_KP_WAKE_CLR;
+
+       /* wake event clear is needed in order to clear keypad interrupt */
+       val = __raw_readl(APMU_WAKE_CLR);
+       __raw_writel(val |  mask, APMU_WAKE_CLR);
+}
+
 /* 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);
@@ -147,3 +161,5 @@ PXA168_DEVICE(ssp2, "pxa168-ssp", 1, SSP2, 0xd401c000, 0x40, 54, 55);
 PXA168_DEVICE(ssp3, "pxa168-ssp", 2, SSP3, 0xd401f000, 0x40, 56, 57);
 PXA168_DEVICE(ssp4, "pxa168-ssp", 3, SSP4, 0xd4020000, 0x40, 58, 59);
 PXA168_DEVICE(ssp5, "pxa168-ssp", 4, SSP5, 0xd4021000, 0x40, 60, 61);
+PXA168_DEVICE(fb, "pxa168-fb", -1, LCD, 0xd420b000, 0x1c8);
+PXA168_DEVICE(keypad, "pxa27x-keypad", -1, KEYPAD, 0xd4012000, 0x4c);
index e81db7428215608ee2ade0281a755f9226983411..c296b75c4453de76f0757329baffb677b56dda5c 100644 (file)
@@ -99,8 +99,6 @@ static void __init tavorevb_init(void)
 }
 
 MACHINE_START(TAVOREVB, "PXA910 Evaluation Board (aka TavorEVB)")
-       .phys_io        = APB_PHYS_BASE,
-       .io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
        .map_io         = mmp_map_io,
        .init_irq       = pxa910_init_irq,
        .timer          = &pxa910_timer,
diff --git a/arch/arm/mach-mmp/teton_bga.c b/arch/arm/mach-mmp/teton_bga.c
new file mode 100644 (file)
index 0000000..bbe4727
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  linux/arch/arm/mach-mmp/teton_bga.c
+ *
+ *  Support for the Marvell PXA168 Teton BGA Development Platform.
+ *
+ *  Author: Mark F. Brown <mark.brown314@gmail.com>
+ *
+ *  This code is based on aspenite.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
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <plat/pxa27x_keypad.h>
+#include <linux/i2c.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <mach/addr-map.h>
+#include <mach/mfp-pxa168.h>
+#include <mach/pxa168.h>
+#include <mach/teton_bga.h>
+
+#include "common.h"
+
+static unsigned long teton_bga_pin_config[] __initdata = {
+       /* UART1 */
+       GPIO107_UART1_TXD,
+       GPIO108_UART1_RXD,
+
+       /* Keypad */
+       GPIO109_KP_MKIN1,
+       GPIO110_KP_MKIN0,
+       GPIO111_KP_MKOUT7,
+       GPIO112_KP_MKOUT6,
+
+       /* I2C Bus */
+       GPIO105_CI2C_SDA,
+       GPIO106_CI2C_SCL,
+
+       /* RTC */
+       GPIO78_GPIO,
+};
+
+static unsigned int teton_bga_matrix_key_map[] = {
+       KEY(0, 6, KEY_ESC),
+       KEY(0, 7, KEY_ENTER),
+       KEY(1, 6, KEY_LEFT),
+       KEY(1, 7, KEY_RIGHT),
+};
+
+static struct pxa27x_keypad_platform_data teton_bga_keypad_info __initdata = {
+       .matrix_key_rows        = 2,
+       .matrix_key_cols        = 8,
+       .matrix_key_map         = teton_bga_matrix_key_map,
+       .matrix_key_map_size    = ARRAY_SIZE(teton_bga_matrix_key_map),
+       .debounce_interval      = 30,
+};
+
+static struct i2c_board_info teton_bga_i2c_info[] __initdata = {
+       {
+               I2C_BOARD_INFO("ds1337", 0x68),
+               .irq = gpio_to_irq(RTC_INT_GPIO)
+       },
+};
+
+static void __init teton_bga_init(void)
+{
+       mfp_config(ARRAY_AND_SIZE(teton_bga_pin_config));
+
+       /* on-chip devices */
+       pxa168_add_uart(1);
+       pxa168_add_keypad(&teton_bga_keypad_info);
+       pxa168_add_twsi(0, NULL, ARRAY_AND_SIZE(teton_bga_i2c_info));
+}
+
+MACHINE_START(TETON_BGA, "PXA168-based Teton BGA Development Platform")
+       .map_io         = mmp_map_io,
+       .nr_irqs        = IRQ_BOARD_START,
+       .init_irq       = pxa168_init_irq,
+       .timer          = &pxa168_timer,
+       .init_machine   = teton_bga_init,
+MACHINE_END
index ee65e05f0cf15e0118461ce4a7b277e5038a77c2..e411039ea59e3f2911513ca4353c8b9ce87312ac 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/onenand.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -24,6 +25,8 @@
 
 #include "common.h"
 
+#define TTCDKB_NR_IRQS         (IRQ_BOARD_START + 24)
+
 static unsigned long ttc_dkb_pin_config[] __initdata = {
        /* UART2 */
        GPIO47_UART2_RXD,
@@ -122,9 +125,8 @@ static void __init ttc_dkb_init(void)
 }
 
 MACHINE_START(TTC_DKB, "PXA910-based TTC_DKB Development Platform")
-       .phys_io        = APB_PHYS_BASE,
-       .io_pg_offst    = (APB_VIRT_BASE >> 18) & 0xfffc,
        .map_io         = mmp_map_io,
+       .nr_irqs        = TTCDKB_NR_IRQS,
        .init_irq       = pxa910_init_irq,
        .timer          = &pxa910_timer,
        .init_machine   = ttc_dkb_init,
index 47264a76eeb31d52602ca9386960d4cbf0a012fb..3115a29dec4ea58b867cfa0dab424833ecbf7e5f 100644 (file)
@@ -10,6 +10,8 @@ config ARCH_MSM7X00A
        select MSM_SMD
        select MSM_SMD_PKG3
        select CPU_V6
+       select MSM_PROC_COMM
+       select HAS_MSM_DEBUG_UART_PHYS
 
 config ARCH_MSM7X30
        bool "MSM7x30"
@@ -18,6 +20,9 @@ config ARCH_MSM7X30
        select MSM_VIC
        select CPU_V7
        select MSM_REMOTE_SPINLOCK_DEKKERS
+       select MSM_GPIOMUX
+       select MSM_PROC_COMM
+       select HAS_MSM_DEBUG_UART_PHYS
 
 config ARCH_QSD8X50
        bool "QSD8X50"
@@ -26,6 +31,19 @@ config ARCH_QSD8X50
        select MSM_VIC
        select CPU_V7
        select MSM_REMOTE_SPINLOCK_LDREX
+       select MSM_GPIOMUX
+       select MSM_PROC_COMM
+       select HAS_MSM_DEBUG_UART_PHYS
+
+config ARCH_MSM8X60
+       bool "MSM8X60"
+       select ARM_GIC
+       select CPU_V7
+       select MSM_V2_TLMM
+       select MSM_GPIOMUX
+       select MACH_MSM8X60_SURF if (!MACH_MSM8X60_RUMI3 && !MACH_MSM8X60_SIM \
+                                 && !MACH_MSM8X60_FFA)
+
 endchoice
 
 config MSM_SOC_REV_A
@@ -36,6 +54,9 @@ config  ARCH_MSM_ARM11
 config  ARCH_MSM_SCORPION
        bool
 
+config HAS_MSM_DEBUG_UART_PHYS
+       bool
+
 config  MSM_VIC
        bool
 
@@ -74,6 +95,30 @@ config MACH_QSD8X50A_ST1_5
        help
          Support for the Qualcomm ST1.5.
 
+config MACH_MSM8X60_RUMI3
+       depends on ARCH_MSM8X60
+       bool "MSM8x60 RUMI3"
+       help
+         Support for the Qualcomm MSM8x60 RUMI3 emulator.
+
+config MACH_MSM8X60_SURF
+       depends on ARCH_MSM8X60
+       bool "MSM8x60 SURF"
+       help
+         Support for the Qualcomm MSM8x60 SURF eval board.
+
+config MACH_MSM8X60_SIM
+       depends on ARCH_MSM8X60
+       bool "MSM8x60 Simulator"
+       help
+         Support for the Qualcomm MSM8x60 simulator.
+
+config MACH_MSM8X60_FFA
+       depends on ARCH_MSM8X60
+       bool "MSM8x60 FFA"
+       help
+         Support for the Qualcomm MSM8x60 FFA eval board.
+
 endmenu
 
 config MSM_DEBUG_UART
@@ -82,6 +127,7 @@ config MSM_DEBUG_UART
        default 2 if MSM_DEBUG_UART2
        default 3 if MSM_DEBUG_UART3
 
+if HAS_MSM_DEBUG_UART_PHYS
 choice
        prompt "Debug UART"
 
@@ -99,11 +145,20 @@ choice
        config MSM_DEBUG_UART3
                bool "UART3"
 endchoice
+endif
 
 config MSM_SMD_PKG3
        bool
 
+config MSM_PROC_COMM
+       bool
+
 config MSM_SMD
        bool
 
+config MSM_GPIOMUX
+       bool
+
+config MSM_V2_TLMM
+       bool
 endif
index 704610648a255870d5b959899d1f1f0b3a8259d4..b5a7b07a44f53c9652048d10157f7a24745c53a2 100644 (file)
@@ -1,16 +1,20 @@
-obj-y += proc_comm.o
-obj-y += io.o idle.o timer.o dma.o
-obj-y += vreg.o
+obj-y += io.o idle.o timer.o
+ifndef CONFIG_ARCH_MSM8X60
 obj-y += acpuclock-arm11.o
-obj-y += clock.o clock-pcom.o
-obj-y += gpio.o
+obj-y += dma.o
+endif
 
 ifdef CONFIG_MSM_VIC
 obj-y += irq-vic.o
 else
+ifndef CONFIG_ARCH_MSM8X60
 obj-y += irq.o
 endif
+endif
 
+obj-$(CONFIG_ARCH_MSM8X60) += clock-dummy.o iommu.o iommu_dev.o devices-msm8x60-iommu.o
+obj-$(CONFIG_MSM_PROC_COMM) += proc_comm.o clock-pcom.o vreg.o
+obj-$(CONFIG_MSM_PROC_COMM) += clock.o
 obj-$(CONFIG_ARCH_QSD8X50) += sirc.o
 obj-$(CONFIG_MSM_SMD) += smd.o smd_debug.o
 obj-$(CONFIG_MSM_SMD) += last_radio_log.o
@@ -19,4 +23,11 @@ obj-$(CONFIG_MACH_TROUT) += board-trout.o board-trout-gpio.o board-trout-mmc.o d
 obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o devices-msm7x00.o
 obj-$(CONFIG_ARCH_MSM7X30) += board-msm7x30.o devices-msm7x30.o
 obj-$(CONFIG_ARCH_QSD8X50) += board-qsd8x50.o devices-qsd8x50.o
+obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60.o
 
+obj-$(CONFIG_ARCH_MSM7X30) += gpiomux-7x30.o gpiomux-v1.o gpiomux.o
+obj-$(CONFIG_ARCH_QSD8X50) += gpiomux-8x50.o gpiomux-v1.o gpiomux.o
+obj-$(CONFIG_ARCH_MSM8X60) += gpiomux-8x60.o gpiomux-v2.o gpiomux.o
+ifndef CONFIG_MSM_V2_TLMM
+obj-y  += gpio.o
+endif
index 7bd72e8f127ea39f8a7ee222241552a7b98eb2c3..59edecbe126cc5ab6df4d925ff19458a06167537 100644 (file)
@@ -95,8 +95,6 @@ static void __init halibut_map_io(void)
 
 MACHINE_START(HALIBUT, "Halibut Board (QCT SURF7200A)")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io        = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params    = 0x10000100,
        .fixup          = halibut_fixup,
index bcbefdfe7b5e582052fb14334085567c7ef91de5..ef3ebf2f763be9c660554f4c6189aa67028a2ea0 100644 (file)
@@ -75,8 +75,6 @@ extern struct sys_timer msm_timer;
 
 MACHINE_START(MAHIMAHI, "mahimahi")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io        = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params    = 0x20000100,
        .fixup          = mahimahi_fixup,
index db9381b85bf031542e1fca1837d15b68242aa201..e7a76eff57d93c878d45294f140038e076e64be3 100644 (file)
@@ -131,8 +131,6 @@ static void __init msm7x2x_map_io(void)
 
 MACHINE_START(MSM7X27_SURF, "QCT MSM7x27 SURF")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io        = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params    = PHYS_OFFSET + 0x100,
        .map_io         = msm7x2x_map_io,
@@ -143,8 +141,6 @@ MACHINE_END
 
 MACHINE_START(MSM7X27_FFA, "QCT MSM7x27 FFA")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io        = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params    = PHYS_OFFSET + 0x100,
        .map_io         = msm7x2x_map_io,
@@ -155,8 +151,6 @@ MACHINE_END
 
 MACHINE_START(MSM7X25_SURF, "QCT MSM7x25 SURF")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io        = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params    = PHYS_OFFSET + 0x100,
        .map_io         = msm7x2x_map_io,
@@ -167,8 +161,6 @@ MACHINE_END
 
 MACHINE_START(MSM7X25_FFA, "QCT MSM7x25 FFA")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io        = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params    = PHYS_OFFSET + 0x100,
        .map_io         = msm7x2x_map_io,
index e32981928c7701e2032414d69ef099fd6a1bd9db..05241df3f9b6b3a4dd829029d6b97943549b824d 100644 (file)
 
 extern struct sys_timer msm_timer;
 
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
-static struct msm_gpio uart2_config_data[] = {
-       { GPIO_CFG(49, 2, GPIO_OUTPUT,  GPIO_PULL_DOWN, GPIO_2MA), "UART2_RFR"},
-       { GPIO_CFG(50, 2, GPIO_INPUT,   GPIO_PULL_DOWN, GPIO_2MA), "UART2_CTS"},
-       { GPIO_CFG(51, 2, GPIO_INPUT,   GPIO_PULL_DOWN, GPIO_2MA), "UART2_Rx"},
-       { GPIO_CFG(52, 2, GPIO_OUTPUT,  GPIO_PULL_DOWN, GPIO_2MA), "UART2_Tx"},
-};
-
-static void msm7x30_init_uart2(void)
-{
-       msm_gpios_request_enable(uart2_config_data,
-                       ARRAY_SIZE(uart2_config_data));
-
-}
-#endif
-
 static struct platform_device *devices[] __initdata = {
 #if defined(CONFIG_SERIAL_MSM) || defined(CONFIG_MSM_SERIAL_DEBUGGER)
         &msm_device_uart2,
 #endif
-
+       &msm_device_smd,
 };
 
 static void __init msm7x30_init_irq(void)
@@ -70,10 +54,6 @@ static void __init msm7x30_init_irq(void)
 static void __init msm7x30_init(void)
 {
        platform_add_devices(devices, ARRAY_SIZE(devices));
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
-       msm7x30_init_uart2();
-#endif
-
 }
 
 static void __init msm7x30_map_io(void)
@@ -84,8 +64,6 @@ static void __init msm7x30_map_io(void)
 
 MACHINE_START(MSM7X30_SURF, "QCT MSM7X30 SURF")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io  = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params = PHYS_OFFSET + 0x100,
        .map_io = msm7x30_map_io,
@@ -96,8 +74,6 @@ MACHINE_END
 
 MACHINE_START(MSM7X30_FFA, "QCT MSM7X30 FFA")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io  = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params = PHYS_OFFSET + 0x100,
        .map_io = msm7x30_map_io,
@@ -108,8 +84,6 @@ MACHINE_END
 
 MACHINE_START(MSM7X30_FLUID, "QCT MSM7X30 FLUID")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io  = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params = PHYS_OFFSET + 0x100,
        .map_io = msm7x30_map_io,
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
new file mode 100644 (file)
index 0000000..7486a68
--- /dev/null
@@ -0,0 +1,100 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+
+#include <mach/board.h>
+#include <mach/msm_iomap.h>
+
+void __iomem *gic_cpu_base_addr;
+
+unsigned long clk_get_max_axi_khz(void)
+{
+       return 0;
+}
+
+static void __init msm8x60_map_io(void)
+{
+       msm_map_msm8x60_io();
+}
+
+static void __init msm8x60_init_irq(void)
+{
+       unsigned int i;
+
+       gic_dist_init(0, MSM_QGIC_DIST_BASE, GIC_PPI_START);
+       gic_cpu_base_addr = (void *)MSM_QGIC_CPU_BASE;
+       gic_cpu_init(0, MSM_QGIC_CPU_BASE);
+
+       /* Edge trigger PPIs except AVS_SVICINT and AVS_SVICINTSWDONE */
+       writel(0xFFFFD7FF, MSM_QGIC_DIST_BASE + GIC_DIST_CONFIG + 4);
+
+       /* RUMI does not adhere to GIC spec by enabling STIs by default.
+        * Enable/clear is supposed to be RO for STIs, but is RW on RUMI.
+        */
+       if (!machine_is_msm8x60_sim())
+               writel(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
+
+       /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
+        * as they are configured as level, which does not play nice with
+        * handle_percpu_irq.
+        */
+       for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
+               if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
+                       set_irq_handler(i, handle_percpu_irq);
+       }
+}
+
+static void __init msm8x60_init(void)
+{
+}
+
+MACHINE_START(MSM8X60_RUMI3, "QCT MSM8X60 RUMI3")
+       .map_io = msm8x60_map_io,
+       .init_irq = msm8x60_init_irq,
+       .init_machine = msm8x60_init,
+       .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM8X60_SURF, "QCT MSM8X60 SURF")
+       .map_io = msm8x60_map_io,
+       .init_irq = msm8x60_init_irq,
+       .init_machine = msm8x60_init,
+       .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM8X60_SIM, "QCT MSM8X60 SIMULATOR")
+       .map_io = msm8x60_map_io,
+       .init_irq = msm8x60_init_irq,
+       .init_machine = msm8x60_init,
+       .timer = &msm_timer,
+MACHINE_END
+
+MACHINE_START(MSM8X60_FFA, "QCT MSM8X60 FFA")
+       .map_io = msm8x60_map_io,
+       .init_irq = msm8x60_init_irq,
+       .init_machine = msm8x60_init,
+       .timer = &msm_timer,
+MACHINE_END
index e3cc80792d6c2bafbcb9bb68ce9505434d71c176..ed2af4ad97ed22db1d0829da48e2770796bcb966 100644 (file)
 
 extern struct sys_timer msm_timer;
 
-static struct msm_gpio uart3_config_data[] = {
-       { GPIO_CFG(86, 1, GPIO_INPUT,   GPIO_PULL_DOWN, GPIO_2MA), "UART2_Rx"},
-       { GPIO_CFG(87, 1, GPIO_OUTPUT,  GPIO_PULL_DOWN, GPIO_2MA), "UART2_Tx"},
+static const resource_size_t qsd8x50_surf_smc91x_base __initdata = 0x70000300;
+static const unsigned        qsd8x50_surf_smc91x_gpio __initdata = 156;
+
+/* Leave smc91x resources empty here, as we'll fill them in
+ * at run-time: they vary from board to board, and the true
+ * configuration won't be known until boot.
+ */
+static struct resource smc91x_resources[] __initdata = {
+       [0] = {
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .flags = IORESOURCE_IRQ,
+       },
 };
 
-static struct platform_device *devices[] __initdata = {
-       &msm_device_uart3,
+static struct platform_device smc91x_device __initdata = {
+       .name           = "smc91x",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(smc91x_resources),
+       .resource       = smc91x_resources,
 };
 
-static void msm8x50_init_uart3(void)
+static int __init msm_init_smc91x(void)
 {
-       msm_gpios_request_enable(uart3_config_data,
-                               ARRAY_SIZE(uart3_config_data));
+       if (machine_is_qsd8x50_surf()) {
+               smc91x_resources[0].start = qsd8x50_surf_smc91x_base;
+               smc91x_resources[0].end   = qsd8x50_surf_smc91x_base + 0xff;
+               smc91x_resources[1].start =
+                       gpio_to_irq(qsd8x50_surf_smc91x_gpio);
+               smc91x_resources[1].end   =
+                       gpio_to_irq(qsd8x50_surf_smc91x_gpio);
+               platform_device_register(&smc91x_device);
+       }
+
+       return 0;
 }
+module_init(msm_init_smc91x);
+
+static struct platform_device *devices[] __initdata = {
+       &msm_device_uart3,
+       &msm_device_smd,
+};
 
 static void __init qsd8x50_map_io(void)
 {
@@ -64,14 +93,11 @@ static void __init qsd8x50_init_irq(void)
 
 static void __init qsd8x50_init(void)
 {
-       msm8x50_init_uart3();
        platform_add_devices(devices, ARRAY_SIZE(devices));
 }
 
 MACHINE_START(QSD8X50_SURF, "QCT QSD8X50 SURF")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io  = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params = PHYS_OFFSET + 0x100,
        .map_io = qsd8x50_map_io,
@@ -82,8 +108,6 @@ MACHINE_END
 
 MACHINE_START(QSD8X50A_ST1_5, "QCT QSD8X50A ST1.5")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io  = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params = PHYS_OFFSET + 0x100,
        .map_io = qsd8x50_map_io,
index 2bc1b9d5623e4e1871d2ab81d9e3e0faf5573218..8919ffb1719600bfbd954d93d8c1eb2d7369261b 100644 (file)
@@ -106,8 +106,6 @@ static void __init sapphire_map_io(void)
 MACHINE_START(SAPPHIRE, "sapphire")
 /* Maintainer: Brian Swetland <swetland@google.com> */
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io        = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params    = PHYS_OFFSET + 0x100,
        .fixup          = sapphire_fixup,
index 469e0be3499dbe9b69a1ec8e39995b4c604aa953..73f146066542198f111330b602eb3978bd34fa4b 100644 (file)
@@ -93,8 +93,6 @@ static void __init trout_map_io(void)
 
 MACHINE_START(TROUT, "HTC Dream")
 #ifdef CONFIG_MSM_DEBUG_UART
-       .phys_io        = MSM_DEBUG_UART_PHYS,
-       .io_pg_offst    = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc,
 #endif
        .boot_params    = 0x10000100,
        .fixup          = trout_fixup,
diff --git a/arch/arm/mach-msm/clock-dummy.c b/arch/arm/mach-msm/clock-dummy.c
new file mode 100644 (file)
index 0000000..1250d22
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/clk.h>
+#include <linux/err.h>
+#include <linux/module.h>
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+int clk_enable(struct clk *clk)
+{
+       return -ENOENT;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       return -ENOENT;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
index b449e8ad2904c36905043e5bf951510052d89790..7fcf2e3b7698d5ef329a6483eefc29b7be432075 100644 (file)
@@ -51,6 +51,11 @@ struct platform_device msm_device_uart2 = {
        .resource       = resources_uart2,
 };
 
+struct platform_device msm_device_smd = {
+       .name   = "msm_smd",
+       .id     = -1,
+};
+
 struct clk msm_clocks_7x30[] = {
        CLK_PCOM("adm_clk",     ADM_CLK,        NULL, 0),
        CLK_PCOM("adsp_clk",    ADSP_CLK,       NULL, 0),
diff --git a/arch/arm/mach-msm/devices-msm8x60-iommu.c b/arch/arm/mach-msm/devices-msm8x60-iommu.c
new file mode 100644 (file)
index 0000000..89b9d44
--- /dev/null
@@ -0,0 +1,883 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+
+#include <mach/msm_iomap-8x60.h>
+#include <mach/irqs-8x60.h>
+#include <mach/iommu.h>
+
+static struct resource msm_iommu_jpegd_resources[] = {
+       {
+               .start = MSM_IOMMU_JPEGD_PHYS,
+               .end   = MSM_IOMMU_JPEGD_PHYS + MSM_IOMMU_JPEGD_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_JPEGD_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_JPEGD_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_JPEGD_CB_SC_SECURE_IRQ,
+               .end   = SMMU_JPEGD_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msm_iommu_vpe_resources[] = {
+       {
+               .start = MSM_IOMMU_VPE_PHYS,
+               .end   = MSM_IOMMU_VPE_PHYS + MSM_IOMMU_VPE_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_VPE_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_VPE_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_VPE_CB_SC_SECURE_IRQ,
+               .end   = SMMU_VPE_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msm_iommu_mdp0_resources[] = {
+       {
+               .start = MSM_IOMMU_MDP0_PHYS,
+               .end   = MSM_IOMMU_MDP0_PHYS + MSM_IOMMU_MDP0_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_MDP0_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_MDP0_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_MDP0_CB_SC_SECURE_IRQ,
+               .end   = SMMU_MDP0_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msm_iommu_mdp1_resources[] = {
+       {
+               .start = MSM_IOMMU_MDP1_PHYS,
+               .end   = MSM_IOMMU_MDP1_PHYS + MSM_IOMMU_MDP1_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_MDP1_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_MDP1_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_MDP1_CB_SC_SECURE_IRQ,
+               .end   = SMMU_MDP1_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msm_iommu_rot_resources[] = {
+       {
+               .start = MSM_IOMMU_ROT_PHYS,
+               .end   = MSM_IOMMU_ROT_PHYS + MSM_IOMMU_ROT_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_ROT_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_ROT_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_ROT_CB_SC_SECURE_IRQ,
+               .end   = SMMU_ROT_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msm_iommu_ijpeg_resources[] = {
+       {
+               .start = MSM_IOMMU_IJPEG_PHYS,
+               .end   = MSM_IOMMU_IJPEG_PHYS + MSM_IOMMU_IJPEG_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_IJPEG_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_IJPEG_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_IJPEG_CB_SC_SECURE_IRQ,
+               .end   = SMMU_IJPEG_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msm_iommu_vfe_resources[] = {
+       {
+               .start = MSM_IOMMU_VFE_PHYS,
+               .end   = MSM_IOMMU_VFE_PHYS + MSM_IOMMU_VFE_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_VFE_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_VFE_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_VFE_CB_SC_SECURE_IRQ,
+               .end   = SMMU_VFE_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msm_iommu_vcodec_a_resources[] = {
+       {
+               .start = MSM_IOMMU_VCODEC_A_PHYS,
+               .end   = MSM_IOMMU_VCODEC_A_PHYS + MSM_IOMMU_VCODEC_A_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_VCODEC_A_CB_SC_SECURE_IRQ,
+               .end   = SMMU_VCODEC_A_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msm_iommu_vcodec_b_resources[] = {
+       {
+               .start = MSM_IOMMU_VCODEC_B_PHYS,
+               .end   = MSM_IOMMU_VCODEC_B_PHYS + MSM_IOMMU_VCODEC_B_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_VCODEC_B_CB_SC_SECURE_IRQ,
+               .end   = SMMU_VCODEC_B_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msm_iommu_gfx3d_resources[] = {
+       {
+               .start = MSM_IOMMU_GFX3D_PHYS,
+               .end   = MSM_IOMMU_GFX3D_PHYS + MSM_IOMMU_GFX3D_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_GFX3D_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_GFX3D_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_GFX3D_CB_SC_SECURE_IRQ,
+               .end   = SMMU_GFX3D_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource msm_iommu_gfx2d0_resources[] = {
+       {
+               .start = MSM_IOMMU_GFX2D0_PHYS,
+               .end   = MSM_IOMMU_GFX2D0_PHYS + MSM_IOMMU_GFX2D0_SIZE - 1,
+               .name  = "physbase",
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "nonsecure_irq",
+               .start = SMMU_GFX2D0_CB_SC_NON_SECURE_IRQ,
+               .end   = SMMU_GFX2D0_CB_SC_NON_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .name = "secure_irq",
+               .start = SMMU_GFX2D0_CB_SC_SECURE_IRQ,
+               .end   = SMMU_GFX2D0_CB_SC_SECURE_IRQ,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device msm_root_iommu_dev = {
+       .name = "msm_iommu",
+       .id = -1,
+};
+
+static struct msm_iommu_dev jpegd_smmu = {
+       .name = "jpegd",
+       .clk_rate = -1
+};
+
+static struct msm_iommu_dev vpe_smmu = {
+       .name = "vpe"
+};
+
+static struct msm_iommu_dev mdp0_smmu = {
+       .name = "mdp0"
+};
+
+static struct msm_iommu_dev mdp1_smmu = {
+       .name = "mdp1"
+};
+
+static struct msm_iommu_dev rot_smmu = {
+       .name = "rot"
+};
+
+static struct msm_iommu_dev ijpeg_smmu = {
+       .name = "ijpeg"
+};
+
+static struct msm_iommu_dev vfe_smmu = {
+       .name = "vfe",
+       .clk_rate = -1
+};
+
+static struct msm_iommu_dev vcodec_a_smmu = {
+       .name = "vcodec_a"
+};
+
+static struct msm_iommu_dev vcodec_b_smmu = {
+       .name = "vcodec_b"
+};
+
+static struct msm_iommu_dev gfx3d_smmu = {
+       .name = "gfx3d",
+       .clk_rate = 27000000
+};
+
+static struct msm_iommu_dev gfx2d0_smmu = {
+       .name = "gfx2d0",
+       .clk_rate = 27000000
+};
+
+static struct platform_device msm_device_smmu_jpegd = {
+       .name = "msm_iommu",
+       .id = 0,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_jpegd_resources),
+       .resource = msm_iommu_jpegd_resources,
+};
+
+static struct platform_device msm_device_smmu_vpe = {
+       .name = "msm_iommu",
+       .id = 1,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_vpe_resources),
+       .resource = msm_iommu_vpe_resources,
+};
+
+static struct platform_device msm_device_smmu_mdp0 = {
+       .name = "msm_iommu",
+       .id = 2,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_mdp0_resources),
+       .resource = msm_iommu_mdp0_resources,
+};
+
+static struct platform_device msm_device_smmu_mdp1 = {
+       .name = "msm_iommu",
+       .id = 3,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_mdp1_resources),
+       .resource = msm_iommu_mdp1_resources,
+};
+
+static struct platform_device msm_device_smmu_rot = {
+       .name = "msm_iommu",
+       .id = 4,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_rot_resources),
+       .resource = msm_iommu_rot_resources,
+};
+
+static struct platform_device msm_device_smmu_ijpeg = {
+       .name = "msm_iommu",
+       .id = 5,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_ijpeg_resources),
+       .resource = msm_iommu_ijpeg_resources,
+};
+
+static struct platform_device msm_device_smmu_vfe = {
+       .name = "msm_iommu",
+       .id = 6,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_vfe_resources),
+       .resource = msm_iommu_vfe_resources,
+};
+
+static struct platform_device msm_device_smmu_vcodec_a = {
+       .name = "msm_iommu",
+       .id = 7,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_vcodec_a_resources),
+       .resource = msm_iommu_vcodec_a_resources,
+};
+
+static struct platform_device msm_device_smmu_vcodec_b = {
+       .name = "msm_iommu",
+       .id = 8,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_vcodec_b_resources),
+       .resource = msm_iommu_vcodec_b_resources,
+};
+
+static struct platform_device msm_device_smmu_gfx3d = {
+       .name = "msm_iommu",
+       .id = 9,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_gfx3d_resources),
+       .resource = msm_iommu_gfx3d_resources,
+};
+
+static struct platform_device msm_device_smmu_gfx2d0 = {
+       .name = "msm_iommu",
+       .id = 10,
+       .dev = {
+               .parent = &msm_root_iommu_dev.dev,
+       },
+       .num_resources = ARRAY_SIZE(msm_iommu_gfx2d0_resources),
+       .resource = msm_iommu_gfx2d0_resources,
+};
+
+static struct msm_iommu_ctx_dev jpegd_src_ctx = {
+       .name = "jpegd_src",
+       .num = 0,
+       .mids = {0, -1}
+};
+
+static struct msm_iommu_ctx_dev jpegd_dst_ctx = {
+       .name = "jpegd_dst",
+       .num = 1,
+       .mids = {1, -1}
+};
+
+static struct msm_iommu_ctx_dev vpe_src_ctx = {
+       .name = "vpe_src",
+       .num = 0,
+       .mids = {0, -1}
+};
+
+static struct msm_iommu_ctx_dev vpe_dst_ctx = {
+       .name = "vpe_dst",
+       .num = 1,
+       .mids = {1, -1}
+};
+
+static struct msm_iommu_ctx_dev mdp_vg1_ctx = {
+       .name = "mdp_vg1",
+       .num = 0,
+       .mids = {0, 2, -1}
+};
+
+static struct msm_iommu_ctx_dev mdp_rgb1_ctx = {
+       .name = "mdp_rgb1",
+       .num = 1,
+       .mids = {1, 3, 4, 5, 6, 7, 8, 9, 10, -1}
+};
+
+static struct msm_iommu_ctx_dev mdp_vg2_ctx = {
+       .name = "mdp_vg2",
+       .num = 0,
+       .mids = {0, 2, -1}
+};
+
+static struct msm_iommu_ctx_dev mdp_rgb2_ctx = {
+       .name = "mdp_rgb2",
+       .num = 1,
+       .mids = {1, 3, 4, 5, 6, 7, 8, 9, 10, -1}
+};
+
+static struct msm_iommu_ctx_dev rot_src_ctx = {
+       .name = "rot_src",
+       .num = 0,
+       .mids = {0, -1}
+};
+
+static struct msm_iommu_ctx_dev rot_dst_ctx = {
+       .name = "rot_dst",
+       .num = 1,
+       .mids = {1, -1}
+};
+
+static struct msm_iommu_ctx_dev ijpeg_src_ctx = {
+       .name = "ijpeg_src",
+       .num = 0,
+       .mids = {0, -1}
+};
+
+static struct msm_iommu_ctx_dev ijpeg_dst_ctx = {
+       .name = "ijpeg_dst",
+       .num = 1,
+       .mids = {1, -1}
+};
+
+static struct msm_iommu_ctx_dev vfe_imgwr_ctx = {
+       .name = "vfe_imgwr",
+       .num = 0,
+       .mids = {2, 3, 4, 5, 6, 7, 8, -1}
+};
+
+static struct msm_iommu_ctx_dev vfe_misc_ctx = {
+       .name = "vfe_misc",
+       .num = 1,
+       .mids = {0, 1, 9, -1}
+};
+
+static struct msm_iommu_ctx_dev vcodec_a_stream_ctx = {
+       .name = "vcodec_a_stream",
+       .num = 0,
+       .mids = {2, 5, -1}
+};
+
+static struct msm_iommu_ctx_dev vcodec_a_mm1_ctx = {
+       .name = "vcodec_a_mm1",
+       .num = 1,
+       .mids = {0, 1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}
+};
+
+static struct msm_iommu_ctx_dev vcodec_b_mm2_ctx = {
+       .name = "vcodec_b_mm2",
+       .num = 0,
+       .mids = {0, 1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1}
+};
+
+static struct msm_iommu_ctx_dev gfx3d_rbpa_ctx = {
+       .name = "gfx3d_rbpa",
+       .num = 0,
+       .mids = {-1}
+};
+
+static struct msm_iommu_ctx_dev gfx3d_cpvgttc_ctx = {
+       .name = "gfx3d_cpvgttc",
+       .num = 1,
+       .mids = {0, 1, 2, 3, 4, 5, 6, 7, -1}
+};
+
+static struct msm_iommu_ctx_dev gfx3d_smmu_ctx = {
+       .name = "gfx3d_smmu",
+       .num = 2,
+       .mids = {8, 9, 10, 11, 12, -1}
+};
+
+static struct msm_iommu_ctx_dev gfx2d0_pixv1_ctx = {
+       .name = "gfx2d0_pixv1_smmu",
+       .num = 0,
+       .mids = {0, 3, 4, -1}
+};
+
+static struct msm_iommu_ctx_dev gfx2d0_texv3_ctx = {
+       .name = "gfx2d0_texv3_smmu",
+       .num = 1,
+       .mids = {1, 6, 7, -1}
+};
+
+static struct platform_device msm_device_jpegd_src_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 0,
+       .dev = {
+               .parent = &msm_device_smmu_jpegd.dev,
+       },
+};
+
+static struct platform_device msm_device_jpegd_dst_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 1,
+       .dev = {
+               .parent = &msm_device_smmu_jpegd.dev,
+       },
+};
+
+static struct platform_device msm_device_vpe_src_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 2,
+       .dev = {
+               .parent = &msm_device_smmu_vpe.dev,
+       },
+};
+
+static struct platform_device msm_device_vpe_dst_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 3,
+       .dev = {
+               .parent = &msm_device_smmu_vpe.dev,
+       },
+};
+
+static struct platform_device msm_device_mdp_vg1_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 4,
+       .dev = {
+               .parent = &msm_device_smmu_mdp0.dev,
+       },
+};
+
+static struct platform_device msm_device_mdp_rgb1_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 5,
+       .dev = {
+               .parent = &msm_device_smmu_mdp0.dev,
+       },
+};
+
+static struct platform_device msm_device_mdp_vg2_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 6,
+       .dev = {
+               .parent = &msm_device_smmu_mdp1.dev,
+       },
+};
+
+static struct platform_device msm_device_mdp_rgb2_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 7,
+       .dev = {
+               .parent = &msm_device_smmu_mdp1.dev,
+       },
+};
+
+static struct platform_device msm_device_rot_src_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 8,
+       .dev = {
+               .parent = &msm_device_smmu_rot.dev,
+       },
+};
+
+static struct platform_device msm_device_rot_dst_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 9,
+       .dev = {
+               .parent = &msm_device_smmu_rot.dev,
+       },
+};
+
+static struct platform_device msm_device_ijpeg_src_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 10,
+       .dev = {
+               .parent = &msm_device_smmu_ijpeg.dev,
+       },
+};
+
+static struct platform_device msm_device_ijpeg_dst_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 11,
+       .dev = {
+               .parent = &msm_device_smmu_ijpeg.dev,
+       },
+};
+
+static struct platform_device msm_device_vfe_imgwr_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 12,
+       .dev = {
+               .parent = &msm_device_smmu_vfe.dev,
+       },
+};
+
+static struct platform_device msm_device_vfe_misc_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 13,
+       .dev = {
+               .parent = &msm_device_smmu_vfe.dev,
+       },
+};
+
+static struct platform_device msm_device_vcodec_a_stream_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 14,
+       .dev = {
+               .parent = &msm_device_smmu_vcodec_a.dev,
+       },
+};
+
+static struct platform_device msm_device_vcodec_a_mm1_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 15,
+       .dev = {
+               .parent = &msm_device_smmu_vcodec_a.dev,
+       },
+};
+
+static struct platform_device msm_device_vcodec_b_mm2_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 16,
+       .dev = {
+               .parent = &msm_device_smmu_vcodec_b.dev,
+       },
+};
+
+static struct platform_device msm_device_gfx3d_rbpa_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 17,
+       .dev = {
+               .parent = &msm_device_smmu_gfx3d.dev,
+       },
+};
+
+static struct platform_device msm_device_gfx3d_cpvgttc_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 18,
+       .dev = {
+               .parent = &msm_device_smmu_gfx3d.dev,
+       },
+};
+
+static struct platform_device msm_device_gfx3d_smmu_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 19,
+       .dev = {
+               .parent = &msm_device_smmu_gfx3d.dev,
+       },
+};
+
+static struct platform_device msm_device_gfx2d0_pixv1_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 20,
+       .dev = {
+               .parent = &msm_device_smmu_gfx2d0.dev,
+       },
+};
+
+static struct platform_device msm_device_gfx2d0_texv3_ctx = {
+       .name = "msm_iommu_ctx",
+       .id = 21,
+       .dev = {
+               .parent = &msm_device_smmu_gfx2d0.dev,
+       },
+};
+
+static struct platform_device *msm_iommu_devs[] = {
+       &msm_device_smmu_jpegd,
+       &msm_device_smmu_vpe,
+       &msm_device_smmu_mdp0,
+       &msm_device_smmu_mdp1,
+       &msm_device_smmu_rot,
+       &msm_device_smmu_ijpeg,
+       &msm_device_smmu_vfe,
+       &msm_device_smmu_vcodec_a,
+       &msm_device_smmu_vcodec_b,
+       &msm_device_smmu_gfx3d,
+       &msm_device_smmu_gfx2d0,
+};
+
+static struct msm_iommu_dev *msm_iommu_data[] = {
+       &jpegd_smmu,
+       &vpe_smmu,
+       &mdp0_smmu,
+       &mdp1_smmu,
+       &rot_smmu,
+       &ijpeg_smmu,
+       &vfe_smmu,
+       &vcodec_a_smmu,
+       &vcodec_b_smmu,
+       &gfx3d_smmu,
+       &gfx2d0_smmu,
+};
+
+static struct platform_device *msm_iommu_ctx_devs[] = {
+       &msm_device_jpegd_src_ctx,
+       &msm_device_jpegd_dst_ctx,
+       &msm_device_vpe_src_ctx,
+       &msm_device_vpe_dst_ctx,
+       &msm_device_mdp_vg1_ctx,
+       &msm_device_mdp_rgb1_ctx,
+       &msm_device_mdp_vg2_ctx,
+       &msm_device_mdp_rgb2_ctx,
+       &msm_device_rot_src_ctx,
+       &msm_device_rot_dst_ctx,
+       &msm_device_ijpeg_src_ctx,
+       &msm_device_ijpeg_dst_ctx,
+       &msm_device_vfe_imgwr_ctx,
+       &msm_device_vfe_misc_ctx,
+       &msm_device_vcodec_a_stream_ctx,
+       &msm_device_vcodec_a_mm1_ctx,
+       &msm_device_vcodec_b_mm2_ctx,
+       &msm_device_gfx3d_rbpa_ctx,
+       &msm_device_gfx3d_cpvgttc_ctx,
+       &msm_device_gfx3d_smmu_ctx,
+       &msm_device_gfx2d0_pixv1_ctx,
+       &msm_device_gfx2d0_texv3_ctx,
+};
+
+static struct msm_iommu_ctx_dev *msm_iommu_ctx_data[] = {
+       &jpegd_src_ctx,
+       &jpegd_dst_ctx,
+       &vpe_src_ctx,
+       &vpe_dst_ctx,
+       &mdp_vg1_ctx,
+       &mdp_rgb1_ctx,
+       &mdp_vg2_ctx,
+       &mdp_rgb2_ctx,
+       &rot_src_ctx,
+       &rot_dst_ctx,
+       &ijpeg_src_ctx,
+       &ijpeg_dst_ctx,
+       &vfe_imgwr_ctx,
+       &vfe_misc_ctx,
+       &vcodec_a_stream_ctx,
+       &vcodec_a_mm1_ctx,
+       &vcodec_b_mm2_ctx,
+       &gfx3d_rbpa_ctx,
+       &gfx3d_cpvgttc_ctx,
+       &gfx3d_smmu_ctx,
+       &gfx2d0_pixv1_ctx,
+       &gfx2d0_texv3_ctx,
+};
+
+static int msm8x60_iommu_init(void)
+{
+       int ret, i;
+
+       ret = platform_device_register(&msm_root_iommu_dev);
+       if (ret != 0) {
+               pr_err("Failed to register root IOMMU device!\n");
+               goto failure;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(msm_iommu_devs); i++) {
+               ret = platform_device_add_data(msm_iommu_devs[i],
+                                              msm_iommu_data[i],
+                                              sizeof(struct msm_iommu_dev));
+               if (ret != 0) {
+                       pr_err("platform_device_add_data failed, "
+                              "i = %d\n", i);
+                       goto failure_unwind;
+               }
+
+               ret = platform_device_register(msm_iommu_devs[i]);
+
+               if (ret != 0) {
+                       pr_err("platform_device_register smmu failed, "
+                              "i = %d\n", i);
+                       goto failure_unwind;
+               }
+       }
+
+       for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_devs); i++) {
+               ret = platform_device_add_data(msm_iommu_ctx_devs[i],
+                                              msm_iommu_ctx_data[i],
+                                              sizeof(*msm_iommu_ctx_devs[i]));
+               if (ret != 0) {
+                       pr_err("platform_device_add_data smmu failed, "
+                              "i = %d\n", i);
+                       goto failure_unwind2;
+               }
+
+               ret = platform_device_register(msm_iommu_ctx_devs[i]);
+               if (ret != 0) {
+                       pr_err("platform_device_register ctx failed, "
+                              "i = %d\n", i);
+                       goto failure_unwind2;
+               }
+       }
+       return 0;
+
+failure_unwind2:
+       while (--i >= 0)
+               platform_device_unregister(msm_iommu_ctx_devs[i]);
+failure_unwind:
+       while (--i >= 0)
+               platform_device_unregister(msm_iommu_devs[i]);
+
+       platform_device_unregister(&msm_root_iommu_dev);
+failure:
+       return ret;
+}
+
+static void msm8x60_iommu_exit(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(msm_iommu_ctx_devs); i++)
+               platform_device_unregister(msm_iommu_ctx_devs[i]);
+
+       for (i = 0; i < ARRAY_SIZE(msm_iommu_devs); ++i)
+               platform_device_unregister(msm_iommu_devs[i]);
+
+       platform_device_unregister(&msm_root_iommu_dev);
+}
+
+subsys_initcall(msm8x60_iommu_init);
+module_exit(msm8x60_iommu_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");
index 4d4a50785e344914ffee947cf64fae3664125a56..6fe67c5d1ae0aa3e7286f659b67acb8d11dd12fb 100644 (file)
@@ -48,6 +48,11 @@ struct platform_device msm_device_uart3 = {
        .resource       = resources_uart3,
 };
 
+struct platform_device msm_device_smd = {
+       .name   = "msm_smd",
+       .id     = -1,
+};
+
 struct clk msm_clocks_8x50[] = {
        CLK_PCOM("adm_clk",     ADM_CLK,        NULL, 0),
        CLK_PCOM("ebi1_clk",    EBI1_CLK,       NULL, CLK_MIN),
index bc32c845c7b0e4f777e3366fd4f418daa44c700e..33051b509e88a18679876840a6a5a4a12a4bfdc1 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-msm/gpio.c
  *
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
  *
  */
 
+#include <linux/bitops.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
 #include <linux/module.h>
-#include <mach/gpio.h>
-#include "proc_comm.h"
-
-int gpio_tlmm_config(unsigned config, unsigned disable)
-{
-       return msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &config, &disable);
-}
-EXPORT_SYMBOL(gpio_tlmm_config);
-
-int msm_gpios_enable(const struct msm_gpio *table, int size)
-{
-       int rc;
-       int i;
-       const struct msm_gpio *g;
-       for (i = 0; i < size; i++) {
-               g = table + i;
-               rc = gpio_tlmm_config(g->gpio_cfg, GPIO_ENABLE);
-               if (rc) {
-                       pr_err("gpio_tlmm_config(0x%08x, GPIO_ENABLE)"
-                              " <%s> failed: %d\n",
-                              g->gpio_cfg, g->label ?: "?", rc);
-                       pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
-                              GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
-                              GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
-                              GPIO_DRVSTR(g->gpio_cfg));
-                       goto err;
-               }
+#include "gpio_hw.h"
+#include "gpiomux.h"
+
+#define FIRST_GPIO_IRQ MSM_GPIO_TO_INT(0)
+
+#define MSM_GPIO_BANK(bank, first, last)                               \
+       {                                                               \
+               .regs = {                                               \
+                       .out =         MSM_GPIO_OUT_##bank,             \
+                       .in =          MSM_GPIO_IN_##bank,              \
+                       .int_status =  MSM_GPIO_INT_STATUS_##bank,      \
+                       .int_clear =   MSM_GPIO_INT_CLEAR_##bank,       \
+                       .int_en =      MSM_GPIO_INT_EN_##bank,          \
+                       .int_edge =    MSM_GPIO_INT_EDGE_##bank,        \
+                       .int_pos =     MSM_GPIO_INT_POS_##bank,         \
+                       .oe =          MSM_GPIO_OE_##bank,              \
+               },                                                      \
+               .chip = {                                               \
+                       .base = (first),                                \
+                       .ngpio = (last) - (first) + 1,                  \
+                       .get = msm_gpio_get,                            \
+                       .set = msm_gpio_set,                            \
+                       .direction_input = msm_gpio_direction_input,    \
+                       .direction_output = msm_gpio_direction_output,  \
+                       .to_irq = msm_gpio_to_irq,                      \
+                       .request = msm_gpio_request,                    \
+                       .free = msm_gpio_free,                          \
+               }                                                       \
        }
+
+#define MSM_GPIO_BROKEN_INT_CLEAR 1
+
+struct msm_gpio_regs {
+       void __iomem *out;
+       void __iomem *in;
+       void __iomem *int_status;
+       void __iomem *int_clear;
+       void __iomem *int_en;
+       void __iomem *int_edge;
+       void __iomem *int_pos;
+       void __iomem *oe;
+};
+
+struct msm_gpio_chip {
+       spinlock_t              lock;
+       struct gpio_chip        chip;
+       struct msm_gpio_regs    regs;
+#if MSM_GPIO_BROKEN_INT_CLEAR
+       unsigned                int_status_copy;
+#endif
+       unsigned int            both_edge_detect;
+       unsigned int            int_enable[2]; /* 0: awake, 1: sleep */
+};
+
+static int msm_gpio_write(struct msm_gpio_chip *msm_chip,
+                         unsigned offset, unsigned on)
+{
+       unsigned mask = BIT(offset);
+       unsigned val;
+
+       val = readl(msm_chip->regs.out);
+       if (on)
+               writel(val | mask, msm_chip->regs.out);
+       else
+               writel(val & ~mask, msm_chip->regs.out);
        return 0;
-err:
-       msm_gpios_disable(table, i);
-       return rc;
-}
-EXPORT_SYMBOL(msm_gpios_enable);
-
-void msm_gpios_disable(const struct msm_gpio *table, int size)
-{
-       int rc;
-       int i;
-       const struct msm_gpio *g;
-       for (i = size-1; i >= 0; i--) {
-               g = table + i;
-               rc = gpio_tlmm_config(g->gpio_cfg, GPIO_DISABLE);
-               if (rc) {
-                       pr_err("gpio_tlmm_config(0x%08x, GPIO_DISABLE)"
-                              " <%s> failed: %d\n",
-                              g->gpio_cfg, g->label ?: "?", rc);
-                       pr_err("pin %d func %d dir %d pull %d drvstr %d\n",
-                              GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
-                              GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
-                              GPIO_DRVSTR(g->gpio_cfg));
-               }
+}
+
+static void msm_gpio_update_both_edge_detect(struct msm_gpio_chip *msm_chip)
+{
+       int loop_limit = 100;
+       unsigned pol, val, val2, intstat;
+       do {
+               val = readl(msm_chip->regs.in);
+               pol = readl(msm_chip->regs.int_pos);
+               pol = (pol & ~msm_chip->both_edge_detect) |
+                     (~val & msm_chip->both_edge_detect);
+               writel(pol, msm_chip->regs.int_pos);
+               intstat = readl(msm_chip->regs.int_status);
+               val2 = readl(msm_chip->regs.in);
+               if (((val ^ val2) & msm_chip->both_edge_detect & ~intstat) == 0)
+                       return;
+       } while (loop_limit-- > 0);
+       printk(KERN_ERR "msm_gpio_update_both_edge_detect, "
+              "failed to reach stable state %x != %x\n", val, val2);
+}
+
+static int msm_gpio_clear_detect_status(struct msm_gpio_chip *msm_chip,
+                                       unsigned offset)
+{
+       unsigned bit = BIT(offset);
+
+#if MSM_GPIO_BROKEN_INT_CLEAR
+       /* Save interrupts that already triggered before we loose them. */
+       /* Any interrupt that triggers between the read of int_status */
+       /* and the write to int_clear will still be lost though. */
+       msm_chip->int_status_copy |= readl(msm_chip->regs.int_status);
+       msm_chip->int_status_copy &= ~bit;
+#endif
+       writel(bit, msm_chip->regs.int_clear);
+       msm_gpio_update_both_edge_detect(msm_chip);
+       return 0;
+}
+
+static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct msm_gpio_chip *msm_chip;
+       unsigned long irq_flags;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       writel(readl(msm_chip->regs.oe) & ~BIT(offset), msm_chip->regs.oe);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static int
+msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct msm_gpio_chip *msm_chip;
+       unsigned long irq_flags;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       msm_gpio_write(msm_chip, offset, value);
+       writel(readl(msm_chip->regs.oe) | BIT(offset), msm_chip->regs.oe);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static int msm_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct msm_gpio_chip *msm_chip;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       return (readl(msm_chip->regs.in) & (1U << offset)) ? 1 : 0;
+}
+
+static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct msm_gpio_chip *msm_chip;
+       unsigned long irq_flags;
+
+       msm_chip = container_of(chip, struct msm_gpio_chip, chip);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       msm_gpio_write(msm_chip, offset, value);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+       return MSM_GPIO_TO_INT(chip->base + offset);
+}
+
+#ifdef CONFIG_MSM_GPIOMUX
+static int msm_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+       return msm_gpiomux_get(chip->base + offset);
+}
+
+static void msm_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+       msm_gpiomux_put(chip->base + offset);
+}
+#else
+#define msm_gpio_request NULL
+#define msm_gpio_free NULL
+#endif
+
+struct msm_gpio_chip msm_gpio_chips[] = {
+#if defined(CONFIG_ARCH_MSM7X00A)
+       MSM_GPIO_BANK(0,   0,  15),
+       MSM_GPIO_BANK(1,  16,  42),
+       MSM_GPIO_BANK(2,  43,  67),
+       MSM_GPIO_BANK(3,  68,  94),
+       MSM_GPIO_BANK(4,  95, 106),
+       MSM_GPIO_BANK(5, 107, 121),
+#elif defined(CONFIG_ARCH_MSM7X25) || defined(CONFIG_ARCH_MSM7X27)
+       MSM_GPIO_BANK(0,   0,  15),
+       MSM_GPIO_BANK(1,  16,  42),
+       MSM_GPIO_BANK(2,  43,  67),
+       MSM_GPIO_BANK(3,  68,  94),
+       MSM_GPIO_BANK(4,  95, 106),
+       MSM_GPIO_BANK(5, 107, 132),
+#elif defined(CONFIG_ARCH_MSM7X30)
+       MSM_GPIO_BANK(0,   0,  15),
+       MSM_GPIO_BANK(1,  16,  43),
+       MSM_GPIO_BANK(2,  44,  67),
+       MSM_GPIO_BANK(3,  68,  94),
+       MSM_GPIO_BANK(4,  95, 106),
+       MSM_GPIO_BANK(5, 107, 133),
+       MSM_GPIO_BANK(6, 134, 150),
+       MSM_GPIO_BANK(7, 151, 181),
+#elif defined(CONFIG_ARCH_QSD8X50)
+       MSM_GPIO_BANK(0,   0,  15),
+       MSM_GPIO_BANK(1,  16,  42),
+       MSM_GPIO_BANK(2,  43,  67),
+       MSM_GPIO_BANK(3,  68,  94),
+       MSM_GPIO_BANK(4,  95, 103),
+       MSM_GPIO_BANK(5, 104, 121),
+       MSM_GPIO_BANK(6, 122, 152),
+       MSM_GPIO_BANK(7, 153, 164),
+#endif
+};
+
+static void msm_gpio_irq_ack(unsigned int irq)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       msm_gpio_clear_detect_status(msm_chip,
+                                    irq - gpio_to_irq(msm_chip->chip.base));
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_mask(unsigned int irq)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+       unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       /* level triggered interrupts are also latched */
+       if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+               msm_gpio_clear_detect_status(msm_chip, offset);
+       msm_chip->int_enable[0] &= ~BIT(offset);
+       writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static void msm_gpio_irq_unmask(unsigned int irq)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+       unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       /* level triggered interrupts are also latched */
+       if (!(readl(msm_chip->regs.int_edge) & BIT(offset)))
+               msm_gpio_clear_detect_status(msm_chip, offset);
+       msm_chip->int_enable[0] |= BIT(offset);
+       writel(msm_chip->int_enable[0], msm_chip->regs.int_en);
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+}
+
+static int msm_gpio_irq_set_wake(unsigned int irq, unsigned int on)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+       unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+
+       if (on)
+               msm_chip->int_enable[1] |= BIT(offset);
+       else
+               msm_chip->int_enable[1] &= ~BIT(offset);
+
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
+}
+
+static int msm_gpio_irq_set_type(unsigned int irq, unsigned int flow_type)
+{
+       unsigned long irq_flags;
+       struct msm_gpio_chip *msm_chip = get_irq_chip_data(irq);
+       unsigned offset = irq - gpio_to_irq(msm_chip->chip.base);
+       unsigned val, mask = BIT(offset);
+
+       spin_lock_irqsave(&msm_chip->lock, irq_flags);
+       val = readl(msm_chip->regs.int_edge);
+       if (flow_type & IRQ_TYPE_EDGE_BOTH) {
+               writel(val | mask, msm_chip->regs.int_edge);
+               irq_desc[irq].handle_irq = handle_edge_irq;
+       } else {
+               writel(val & ~mask, msm_chip->regs.int_edge);
+               irq_desc[irq].handle_irq = handle_level_irq;
+       }
+       if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
+               msm_chip->both_edge_detect |= mask;
+               msm_gpio_update_both_edge_detect(msm_chip);
+       } else {
+               msm_chip->both_edge_detect &= ~mask;
+               val = readl(msm_chip->regs.int_pos);
+               if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_HIGH))
+                       writel(val | mask, msm_chip->regs.int_pos);
+               else
+                       writel(val & ~mask, msm_chip->regs.int_pos);
        }
+       spin_unlock_irqrestore(&msm_chip->lock, irq_flags);
+       return 0;
 }
-EXPORT_SYMBOL(msm_gpios_disable);
 
-int msm_gpios_request_enable(const struct msm_gpio *table, int size)
+static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
-       int rc = msm_gpios_enable(table, size);
-       return rc;
+       int i, j, mask;
+       unsigned val;
+
+       for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+               struct msm_gpio_chip *msm_chip = &msm_gpio_chips[i];
+               val = readl(msm_chip->regs.int_status);
+               val &= msm_chip->int_enable[0];
+               while (val) {
+                       mask = val & -val;
+                       j = fls(mask) - 1;
+                       /* printk("%s %08x %08x bit %d gpio %d irq %d\n",
+                               __func__, v, m, j, msm_chip->chip.start + j,
+                               FIRST_GPIO_IRQ + msm_chip->chip.start + j); */
+                       val &= ~mask;
+                       generic_handle_irq(FIRST_GPIO_IRQ +
+                                          msm_chip->chip.base + j);
+               }
+       }
+       desc->chip->ack(irq);
 }
-EXPORT_SYMBOL(msm_gpios_request_enable);
 
-void msm_gpios_disable_free(const struct msm_gpio *table, int size)
+static struct irq_chip msm_gpio_irq_chip = {
+       .name      = "msmgpio",
+       .ack       = msm_gpio_irq_ack,
+       .mask      = msm_gpio_irq_mask,
+       .unmask    = msm_gpio_irq_unmask,
+       .set_wake  = msm_gpio_irq_set_wake,
+       .set_type  = msm_gpio_irq_set_type,
+};
+
+static int __init msm_init_gpio(void)
 {
-       msm_gpios_disable(table, size);
+       int i, j = 0;
+
+       for (i = FIRST_GPIO_IRQ; i < FIRST_GPIO_IRQ + NR_GPIO_IRQS; i++) {
+               if (i - FIRST_GPIO_IRQ >=
+                       msm_gpio_chips[j].chip.base +
+                       msm_gpio_chips[j].chip.ngpio)
+                       j++;
+               set_irq_chip_data(i, &msm_gpio_chips[j]);
+               set_irq_chip(i, &msm_gpio_irq_chip);
+               set_irq_handler(i, handle_edge_irq);
+               set_irq_flags(i, IRQF_VALID);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(msm_gpio_chips); i++) {
+               spin_lock_init(&msm_gpio_chips[i].lock);
+               writel(0, msm_gpio_chips[i].regs.int_en);
+               gpiochip_add(&msm_gpio_chips[i].chip);
+       }
+
+       set_irq_chained_handler(INT_GPIO_GROUP1, msm_gpio_irq_handler);
+       set_irq_chained_handler(INT_GPIO_GROUP2, msm_gpio_irq_handler);
+       set_irq_wake(INT_GPIO_GROUP1, 1);
+       set_irq_wake(INT_GPIO_GROUP2, 2);
+       return 0;
 }
-EXPORT_SYMBOL(msm_gpios_disable_free);
+
+postcore_initcall(msm_init_gpio);
diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h
new file mode 100644 (file)
index 0000000..6b50660
--- /dev/null
@@ -0,0 +1,278 @@
+/* arch/arm/mach-msm/gpio_hw.h
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H
+#define __ARCH_ARM_MACH_MSM_GPIO_HW_H
+
+#include <mach/msm_iomap.h>
+
+/* see 80-VA736-2 Rev C pp 695-751
+**
+** These are actually the *shadow* gpio registers, since the
+** real ones (which allow full access) are only available to the
+** ARM9 side of the world.
+**
+** Since the _BASE need to be page-aligned when we're mapping them
+** to virtual addresses, adjust for the additional offset in these
+** macros.
+*/
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + (off))
+#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0x400 + (off))
+#else
+#define MSM_GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off))
+#define MSM_GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off))
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X00A) || defined(CONFIG_ARCH_MSM7X25) ||\
+    defined(CONFIG_ARCH_MSM7X27)
+
+/* output value */
+#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)  /* gpio  15-0  */
+#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)  /* gpio  42-16 */
+#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)  /* gpio  67-43 */
+#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)  /* gpio  94-68 */
+#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)  /* gpio 106-95 */
+#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x50)  /* gpio 107-121 */
+
+/* same pin map as above, output enable */
+#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x10)
+#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
+#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x14)
+#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x18)
+#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x1C)
+#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x54)
+
+/* same pin map as above, input read */
+#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x34)
+#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
+#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x38)
+#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x3C)
+#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x40)
+#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x44)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x60)
+#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
+#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x64)
+#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x68)
+#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x6C)
+#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0xC0)
+
+/* same pin map as above, 1=positive 0=negative */
+#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x70)
+#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
+#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x74)
+#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x78)
+#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x7C)
+#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xBC)
+
+/* same pin map as above, interrupt enable */
+#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0x80)
+#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
+#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0x84)
+#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0x88)
+#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0x8C)
+#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xB8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0x90)
+#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
+#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0x94)
+#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0x98)
+#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0x9C)
+#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xB4)
+
+/* same pin map as above, 1=interrupt pending */
+#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xA0)
+#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
+#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xA4)
+#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xA8)
+#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xAC)
+#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0xB0)
+
+#endif
+
+#if defined(CONFIG_ARCH_QSD8X50)
+/* output value */
+#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)  /* gpio  15-0   */
+#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)  /* gpio  42-16  */
+#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)  /* gpio  67-43  */
+#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)  /* gpio  94-68  */
+#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)  /* gpio 103-95  */
+#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x10)  /* gpio 121-104 */
+#define MSM_GPIO_OUT_6         MSM_GPIO1_REG(0x14)  /* gpio 152-122 */
+#define MSM_GPIO_OUT_7         MSM_GPIO1_REG(0x18)  /* gpio 164-153 */
+
+/* same pin map as above, output enable */
+#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x20)
+#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
+#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x24)
+#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x28)
+#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x2C)
+#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x30)
+#define MSM_GPIO_OE_6          MSM_GPIO1_REG(0x34)
+#define MSM_GPIO_OE_7          MSM_GPIO1_REG(0x38)
+
+/* same pin map as above, input read */
+#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x50)
+#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
+#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x54)
+#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x58)
+#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x5C)
+#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x60)
+#define MSM_GPIO_IN_6          MSM_GPIO1_REG(0x64)
+#define MSM_GPIO_IN_7          MSM_GPIO1_REG(0x68)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x70)
+#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
+#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x74)
+#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x78)
+#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x7C)
+#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0x80)
+#define MSM_GPIO_INT_EDGE_6    MSM_GPIO1_REG(0x84)
+#define MSM_GPIO_INT_EDGE_7    MSM_GPIO1_REG(0x88)
+
+/* same pin map as above, 1=positive 0=negative */
+#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x90)
+#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
+#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x94)
+#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x98)
+#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x9C)
+#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xA0)
+#define MSM_GPIO_INT_POS_6     MSM_GPIO1_REG(0xA4)
+#define MSM_GPIO_INT_POS_7     MSM_GPIO1_REG(0xA8)
+
+/* same pin map as above, interrupt enable */
+#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0xB0)
+#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
+#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0xB4)
+#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0xB8)
+#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0xBC)
+#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xC0)
+#define MSM_GPIO_INT_EN_6      MSM_GPIO1_REG(0xC4)
+#define MSM_GPIO_INT_EN_7      MSM_GPIO1_REG(0xC8)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0xD0)
+#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
+#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0xD4)
+#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0xD8)
+#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0xDC)
+#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xE0)
+#define MSM_GPIO_INT_CLEAR_6   MSM_GPIO1_REG(0xE4)
+#define MSM_GPIO_INT_CLEAR_7   MSM_GPIO1_REG(0xE8)
+
+/* same pin map as above, 1=interrupt pending */
+#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xF0)
+#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
+#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xF4)
+#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xF8)
+#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xFC)
+#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0x100)
+#define MSM_GPIO_INT_STATUS_6  MSM_GPIO1_REG(0x104)
+#define MSM_GPIO_INT_STATUS_7  MSM_GPIO1_REG(0x108)
+
+#endif
+
+#if defined(CONFIG_ARCH_MSM7X30)
+
+/* output value */
+#define MSM_GPIO_OUT_0         MSM_GPIO1_REG(0x00)   /* gpio  15-0   */
+#define MSM_GPIO_OUT_1         MSM_GPIO2_REG(0x00)   /* gpio  43-16  */
+#define MSM_GPIO_OUT_2         MSM_GPIO1_REG(0x04)   /* gpio  67-44  */
+#define MSM_GPIO_OUT_3         MSM_GPIO1_REG(0x08)   /* gpio  94-68  */
+#define MSM_GPIO_OUT_4         MSM_GPIO1_REG(0x0C)   /* gpio 106-95  */
+#define MSM_GPIO_OUT_5         MSM_GPIO1_REG(0x50)   /* gpio 133-107 */
+#define MSM_GPIO_OUT_6         MSM_GPIO1_REG(0xC4)   /* gpio 150-134 */
+#define MSM_GPIO_OUT_7         MSM_GPIO1_REG(0x214)  /* gpio 181-151 */
+
+/* same pin map as above, output enable */
+#define MSM_GPIO_OE_0          MSM_GPIO1_REG(0x10)
+#define MSM_GPIO_OE_1          MSM_GPIO2_REG(0x08)
+#define MSM_GPIO_OE_2          MSM_GPIO1_REG(0x14)
+#define MSM_GPIO_OE_3          MSM_GPIO1_REG(0x18)
+#define MSM_GPIO_OE_4          MSM_GPIO1_REG(0x1C)
+#define MSM_GPIO_OE_5          MSM_GPIO1_REG(0x54)
+#define MSM_GPIO_OE_6          MSM_GPIO1_REG(0xC8)
+#define MSM_GPIO_OE_7          MSM_GPIO1_REG(0x218)
+
+/* same pin map as above, input read */
+#define MSM_GPIO_IN_0          MSM_GPIO1_REG(0x34)
+#define MSM_GPIO_IN_1          MSM_GPIO2_REG(0x20)
+#define MSM_GPIO_IN_2          MSM_GPIO1_REG(0x38)
+#define MSM_GPIO_IN_3          MSM_GPIO1_REG(0x3C)
+#define MSM_GPIO_IN_4          MSM_GPIO1_REG(0x40)
+#define MSM_GPIO_IN_5          MSM_GPIO1_REG(0x44)
+#define MSM_GPIO_IN_6          MSM_GPIO1_REG(0xCC)
+#define MSM_GPIO_IN_7          MSM_GPIO1_REG(0x21C)
+
+/* same pin map as above, 1=edge 0=level interrup */
+#define MSM_GPIO_INT_EDGE_0    MSM_GPIO1_REG(0x60)
+#define MSM_GPIO_INT_EDGE_1    MSM_GPIO2_REG(0x50)
+#define MSM_GPIO_INT_EDGE_2    MSM_GPIO1_REG(0x64)
+#define MSM_GPIO_INT_EDGE_3    MSM_GPIO1_REG(0x68)
+#define MSM_GPIO_INT_EDGE_4    MSM_GPIO1_REG(0x6C)
+#define MSM_GPIO_INT_EDGE_5    MSM_GPIO1_REG(0xC0)
+#define MSM_GPIO_INT_EDGE_6    MSM_GPIO1_REG(0xD0)
+#define MSM_GPIO_INT_EDGE_7    MSM_GPIO1_REG(0x240)
+
+/* same pin map as above, 1=positive 0=negative */
+#define MSM_GPIO_INT_POS_0     MSM_GPIO1_REG(0x70)
+#define MSM_GPIO_INT_POS_1     MSM_GPIO2_REG(0x58)
+#define MSM_GPIO_INT_POS_2     MSM_GPIO1_REG(0x74)
+#define MSM_GPIO_INT_POS_3     MSM_GPIO1_REG(0x78)
+#define MSM_GPIO_INT_POS_4     MSM_GPIO1_REG(0x7C)
+#define MSM_GPIO_INT_POS_5     MSM_GPIO1_REG(0xBC)
+#define MSM_GPIO_INT_POS_6     MSM_GPIO1_REG(0xD4)
+#define MSM_GPIO_INT_POS_7     MSM_GPIO1_REG(0x228)
+
+/* same pin map as above, interrupt enable */
+#define MSM_GPIO_INT_EN_0      MSM_GPIO1_REG(0x80)
+#define MSM_GPIO_INT_EN_1      MSM_GPIO2_REG(0x60)
+#define MSM_GPIO_INT_EN_2      MSM_GPIO1_REG(0x84)
+#define MSM_GPIO_INT_EN_3      MSM_GPIO1_REG(0x88)
+#define MSM_GPIO_INT_EN_4      MSM_GPIO1_REG(0x8C)
+#define MSM_GPIO_INT_EN_5      MSM_GPIO1_REG(0xB8)
+#define MSM_GPIO_INT_EN_6      MSM_GPIO1_REG(0xD8)
+#define MSM_GPIO_INT_EN_7      MSM_GPIO1_REG(0x22C)
+
+/* same pin map as above, write 1 to clear interrupt */
+#define MSM_GPIO_INT_CLEAR_0   MSM_GPIO1_REG(0x90)
+#define MSM_GPIO_INT_CLEAR_1   MSM_GPIO2_REG(0x68)
+#define MSM_GPIO_INT_CLEAR_2   MSM_GPIO1_REG(0x94)
+#define MSM_GPIO_INT_CLEAR_3   MSM_GPIO1_REG(0x98)
+#define MSM_GPIO_INT_CLEAR_4   MSM_GPIO1_REG(0x9C)
+#define MSM_GPIO_INT_CLEAR_5   MSM_GPIO1_REG(0xB4)
+#define MSM_GPIO_INT_CLEAR_6   MSM_GPIO1_REG(0xDC)
+#define MSM_GPIO_INT_CLEAR_7   MSM_GPIO1_REG(0x230)
+
+/* same pin map as above, 1=interrupt pending */
+#define MSM_GPIO_INT_STATUS_0  MSM_GPIO1_REG(0xA0)
+#define MSM_GPIO_INT_STATUS_1  MSM_GPIO2_REG(0x70)
+#define MSM_GPIO_INT_STATUS_2  MSM_GPIO1_REG(0xA4)
+#define MSM_GPIO_INT_STATUS_3  MSM_GPIO1_REG(0xA8)
+#define MSM_GPIO_INT_STATUS_4  MSM_GPIO1_REG(0xAC)
+#define MSM_GPIO_INT_STATUS_5  MSM_GPIO1_REG(0xB0)
+#define MSM_GPIO_INT_STATUS_6  MSM_GPIO1_REG(0xE0)
+#define MSM_GPIO_INT_STATUS_7  MSM_GPIO1_REG(0x234)
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-msm/gpiomux-7x30.c b/arch/arm/mach-msm/gpiomux-7x30.c
new file mode 100644 (file)
index 0000000..6ce41c5
--- /dev/null
@@ -0,0 +1,38 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 "gpiomux.h"
+
+struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
+#ifdef CONFIG_SERIAL_MSM_CONSOLE
+       [49] = { /* UART2 RFR */
+               .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+                            GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+       },
+       [50] = { /* UART2 CTS */
+               .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+                            GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+       },
+       [51] = { /* UART2 RX */
+               .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+                            GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+       },
+       [52] = { /* UART2 TX */
+               .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+                            GPIOMUX_FUNC_2 | GPIOMUX_VALID,
+       },
+#endif
+};
diff --git a/arch/arm/mach-msm/gpiomux-8x50.c b/arch/arm/mach-msm/gpiomux-8x50.c
new file mode 100644 (file)
index 0000000..4406e0f
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 "gpiomux.h"
+
+struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {
+       [86] = { /* UART3 RX */
+               .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+                            GPIOMUX_FUNC_1 | GPIOMUX_VALID,
+       },
+       [87] = { /* UART3 TX */
+               .suspended = GPIOMUX_DRV_2MA | GPIOMUX_PULL_DOWN |
+                            GPIOMUX_FUNC_1 | GPIOMUX_VALID,
+       },
+};
diff --git a/arch/arm/mach-msm/gpiomux-8x60.c b/arch/arm/mach-msm/gpiomux-8x60.c
new file mode 100644 (file)
index 0000000..7b380b3
--- /dev/null
@@ -0,0 +1,19 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 "gpiomux.h"
+
+struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS] = {};
diff --git a/arch/arm/mach-msm/gpiomux-v1.c b/arch/arm/mach-msm/gpiomux-v1.c
new file mode 100644 (file)
index 0000000..27de2ab
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <linux/kernel.h>
+#include "gpiomux.h"
+#include "proc_comm.h"
+
+void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val)
+{
+       unsigned tlmm_config  = (val & ~GPIOMUX_CTL_MASK) |
+                               ((gpio & 0x3ff) << 4);
+       unsigned tlmm_disable = 0;
+       int rc;
+
+       rc = msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX,
+                          &tlmm_config, &tlmm_disable);
+       if (rc)
+               pr_err("%s: unexpected proc_comm failure %d: %08x %08x\n",
+                      __func__, rc, tlmm_config, tlmm_disable);
+}
diff --git a/arch/arm/mach-msm/gpiomux-v1.h b/arch/arm/mach-msm/gpiomux-v1.h
new file mode 100644 (file)
index 0000000..71d86fe
--- /dev/null
@@ -0,0 +1,67 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 __ARCH_ARM_MACH_MSM_GPIOMUX_V1_H
+#define __ARCH_ARM_MACH_MSM_GPIOMUX_V1_H
+
+#if defined(CONFIG_ARCH_MSM7X30)
+#define GPIOMUX_NGPIOS 182
+#elif defined(CONFIG_ARCH_QSD8X50)
+#define GPIOMUX_NGPIOS 165
+#else
+#define GPIOMUX_NGPIOS 133
+#endif
+
+typedef u32 gpiomux_config_t;
+
+enum {
+       GPIOMUX_DRV_2MA  = 0UL << 17,
+       GPIOMUX_DRV_4MA  = 1UL << 17,
+       GPIOMUX_DRV_6MA  = 2UL << 17,
+       GPIOMUX_DRV_8MA  = 3UL << 17,
+       GPIOMUX_DRV_10MA = 4UL << 17,
+       GPIOMUX_DRV_12MA = 5UL << 17,
+       GPIOMUX_DRV_14MA = 6UL << 17,
+       GPIOMUX_DRV_16MA = 7UL << 17,
+};
+
+enum {
+       GPIOMUX_FUNC_GPIO = 0UL,
+       GPIOMUX_FUNC_1    = 1UL,
+       GPIOMUX_FUNC_2    = 2UL,
+       GPIOMUX_FUNC_3    = 3UL,
+       GPIOMUX_FUNC_4    = 4UL,
+       GPIOMUX_FUNC_5    = 5UL,
+       GPIOMUX_FUNC_6    = 6UL,
+       GPIOMUX_FUNC_7    = 7UL,
+       GPIOMUX_FUNC_8    = 8UL,
+       GPIOMUX_FUNC_9    = 9UL,
+       GPIOMUX_FUNC_A    = 10UL,
+       GPIOMUX_FUNC_B    = 11UL,
+       GPIOMUX_FUNC_C    = 12UL,
+       GPIOMUX_FUNC_D    = 13UL,
+       GPIOMUX_FUNC_E    = 14UL,
+       GPIOMUX_FUNC_F    = 15UL,
+};
+
+enum {
+       GPIOMUX_PULL_NONE   = 0UL << 15,
+       GPIOMUX_PULL_DOWN   = 1UL << 15,
+       GPIOMUX_PULL_KEEPER = 2UL << 15,
+       GPIOMUX_PULL_UP     = 3UL << 15,
+};
+
+#endif
diff --git a/arch/arm/mach-msm/gpiomux-v2.c b/arch/arm/mach-msm/gpiomux-v2.c
new file mode 100644 (file)
index 0000000..273396d
--- /dev/null
@@ -0,0 +1,25 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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/io.h>
+#include <mach/msm_iomap.h>
+#include "gpiomux.h"
+
+void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val)
+{
+       writel(val & ~GPIOMUX_CTL_MASK,
+              MSM_TLMM_BASE + 0x1000 + (0x10 * gpio));
+}
diff --git a/arch/arm/mach-msm/gpiomux-v2.h b/arch/arm/mach-msm/gpiomux-v2.h
new file mode 100644 (file)
index 0000000..3bf10e7
--- /dev/null
@@ -0,0 +1,61 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 __ARCH_ARM_MACH_MSM_GPIOMUX_V2_H
+#define __ARCH_ARM_MACH_MSM_GPIOMUX_V2_H
+
+#define GPIOMUX_NGPIOS 173
+
+typedef u16 gpiomux_config_t;
+
+enum {
+       GPIOMUX_DRV_2MA  = 0UL << 6,
+       GPIOMUX_DRV_4MA  = 1UL << 6,
+       GPIOMUX_DRV_6MA  = 2UL << 6,
+       GPIOMUX_DRV_8MA  = 3UL << 6,
+       GPIOMUX_DRV_10MA = 4UL << 6,
+       GPIOMUX_DRV_12MA = 5UL << 6,
+       GPIOMUX_DRV_14MA = 6UL << 6,
+       GPIOMUX_DRV_16MA = 7UL << 6,
+};
+
+enum {
+       GPIOMUX_FUNC_GPIO = 0UL  << 2,
+       GPIOMUX_FUNC_1    = 1UL  << 2,
+       GPIOMUX_FUNC_2    = 2UL  << 2,
+       GPIOMUX_FUNC_3    = 3UL  << 2,
+       GPIOMUX_FUNC_4    = 4UL  << 2,
+       GPIOMUX_FUNC_5    = 5UL  << 2,
+       GPIOMUX_FUNC_6    = 6UL  << 2,
+       GPIOMUX_FUNC_7    = 7UL  << 2,
+       GPIOMUX_FUNC_8    = 8UL  << 2,
+       GPIOMUX_FUNC_9    = 9UL  << 2,
+       GPIOMUX_FUNC_A    = 10UL << 2,
+       GPIOMUX_FUNC_B    = 11UL << 2,
+       GPIOMUX_FUNC_C    = 12UL << 2,
+       GPIOMUX_FUNC_D    = 13UL << 2,
+       GPIOMUX_FUNC_E    = 14UL << 2,
+       GPIOMUX_FUNC_F    = 15UL << 2,
+};
+
+enum {
+       GPIOMUX_PULL_NONE   = 0UL,
+       GPIOMUX_PULL_DOWN   = 1UL,
+       GPIOMUX_PULL_KEEPER = 2UL,
+       GPIOMUX_PULL_UP     = 3UL,
+};
+
+#endif
diff --git a/arch/arm/mach-msm/gpiomux.c b/arch/arm/mach-msm/gpiomux.c
new file mode 100644 (file)
index 0000000..53af21a
--- /dev/null
@@ -0,0 +1,96 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include "gpiomux.h"
+
+static DEFINE_SPINLOCK(gpiomux_lock);
+
+int msm_gpiomux_write(unsigned gpio,
+                     gpiomux_config_t active,
+                     gpiomux_config_t suspended)
+{
+       struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio;
+       unsigned long irq_flags;
+       gpiomux_config_t setting;
+
+       if (gpio >= GPIOMUX_NGPIOS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&gpiomux_lock, irq_flags);
+
+       if (active & GPIOMUX_VALID)
+               cfg->active = active;
+
+       if (suspended & GPIOMUX_VALID)
+               cfg->suspended = suspended;
+
+       setting = cfg->ref ? active : suspended;
+       if (setting & GPIOMUX_VALID)
+               __msm_gpiomux_write(gpio, setting);
+
+       spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
+       return 0;
+}
+EXPORT_SYMBOL(msm_gpiomux_write);
+
+int msm_gpiomux_get(unsigned gpio)
+{
+       struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio;
+       unsigned long irq_flags;
+
+       if (gpio >= GPIOMUX_NGPIOS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&gpiomux_lock, irq_flags);
+       if (cfg->ref++ == 0 && cfg->active & GPIOMUX_VALID)
+               __msm_gpiomux_write(gpio, cfg->active);
+       spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
+       return 0;
+}
+EXPORT_SYMBOL(msm_gpiomux_get);
+
+int msm_gpiomux_put(unsigned gpio)
+{
+       struct msm_gpiomux_config *cfg = msm_gpiomux_configs + gpio;
+       unsigned long irq_flags;
+
+       if (gpio >= GPIOMUX_NGPIOS)
+               return -EINVAL;
+
+       spin_lock_irqsave(&gpiomux_lock, irq_flags);
+       BUG_ON(cfg->ref == 0);
+       if (--cfg->ref == 0 && cfg->suspended & GPIOMUX_VALID)
+               __msm_gpiomux_write(gpio, cfg->suspended);
+       spin_unlock_irqrestore(&gpiomux_lock, irq_flags);
+       return 0;
+}
+EXPORT_SYMBOL(msm_gpiomux_put);
+
+static int __init gpiomux_init(void)
+{
+       unsigned n;
+
+       for (n = 0; n < GPIOMUX_NGPIOS; ++n) {
+               msm_gpiomux_configs[n].ref = 0;
+               if (!(msm_gpiomux_configs[n].suspended & GPIOMUX_VALID))
+                       continue;
+               __msm_gpiomux_write(n, msm_gpiomux_configs[n].suspended);
+       }
+       return 0;
+}
+postcore_initcall(gpiomux_init);
diff --git a/arch/arm/mach-msm/gpiomux.h b/arch/arm/mach-msm/gpiomux.h
new file mode 100644 (file)
index 0000000..b178d9c
--- /dev/null
@@ -0,0 +1,114 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 __ARCH_ARM_MACH_MSM_GPIOMUX_H
+#define __ARCH_ARM_MACH_MSM_GPIOMUX_H
+
+#include <linux/bitops.h>
+#include <linux/errno.h>
+
+#if defined(CONFIG_MSM_V2_TLMM)
+#include "gpiomux-v2.h"
+#else
+#include "gpiomux-v1.h"
+#endif
+
+/**
+ * struct msm_gpiomux_config: gpiomux settings for one gpio line.
+ *
+ * A complete gpiomux config is the bitwise-or of a drive-strength,
+ * function, and pull.  For functions other than GPIO, the OE
+ * is hard-wired according to the function.  For GPIO mode,
+ * OE is controlled by gpiolib.
+ *
+ * Available settings differ by target; see the gpiomux header
+ * specific to your target arch for available configurations.
+ *
+ * @active: The configuration to be installed when the line is
+ * active, or its reference count is > 0.
+ * @suspended: The configuration to be installed when the line
+ * is suspended, or its reference count is 0.
+ * @ref: The reference count of the line.  For internal use of
+ * the gpiomux framework only.
+ */
+struct msm_gpiomux_config {
+       gpiomux_config_t active;
+       gpiomux_config_t suspended;
+       unsigned         ref;
+};
+
+/**
+ * @GPIOMUX_VALID:     If set, the config field contains 'good data'.
+ *                      The absence of this bit will prevent the gpiomux
+ *                     system from applying the configuration under all
+ *                     circumstances.
+ */
+enum {
+       GPIOMUX_VALID    = BIT(sizeof(gpiomux_config_t) * BITS_PER_BYTE - 1),
+       GPIOMUX_CTL_MASK = GPIOMUX_VALID,
+};
+
+#ifdef CONFIG_MSM_GPIOMUX
+
+/* Each architecture must provide its own instance of this table.
+ * To avoid having gpiomux manage any given gpio, one or both of
+ * the entries can avoid setting GPIOMUX_VALID - the absence
+ * of that flag will prevent the configuration from being applied
+ * during state transitions.
+ */
+extern struct msm_gpiomux_config msm_gpiomux_configs[GPIOMUX_NGPIOS];
+
+/* Increment a gpio's reference count, possibly activating the line. */
+int __must_check msm_gpiomux_get(unsigned gpio);
+
+/* Decrement a gpio's reference count, possibly suspending the line. */
+int msm_gpiomux_put(unsigned gpio);
+
+/* Install a new configuration to the gpio line.  To avoid overwriting
+ * a configuration, leave the VALID bit out.
+ */
+int msm_gpiomux_write(unsigned gpio,
+                     gpiomux_config_t active,
+                     gpiomux_config_t suspended);
+
+/* Architecture-internal function for use by the framework only.
+ * This function can assume the following:
+ * - the gpio value has passed a bounds-check
+ * - the gpiomux spinlock has been obtained
+ *
+ * This function is not for public consumption.  External users
+ * should use msm_gpiomux_write.
+ */
+void __msm_gpiomux_write(unsigned gpio, gpiomux_config_t val);
+#else
+static inline int __must_check msm_gpiomux_get(unsigned gpio)
+{
+       return -ENOSYS;
+}
+
+static inline int msm_gpiomux_put(unsigned gpio)
+{
+       return -ENOSYS;
+}
+
+static inline int msm_gpiomux_write(unsigned gpio,
+                                   gpiomux_config_t active,
+                                   gpiomux_config_t suspended)
+{
+       return -ENOSYS;
+}
+#endif
+#endif
index 5a79bcf5041367894d876ece1a86f20f5948bb97..6abf4a6eadc19be578b7888c21bfd3ec534291f6 100644 (file)
@@ -33,6 +33,8 @@ struct msm_acpu_clock_platform_data
 
 struct clk;
 
+extern struct sys_timer msm_timer;
+
 /* common init routines for use by arch/arm/mach-msm/board-*.c */
 
 void __init msm_add_devices(void);
index 528750f307e9428433c97101153be1933d495ba8..fbd5d90dcc8ce36ec411e8b8d1be04613a2742f0 100644 (file)
 #include <mach/hardware.h>
 #include <mach/msm_iomap.h>
 
-#ifdef CONFIG_MSM_DEBUG_UART
-       .macro  addruart, rx, tmp
-       @ see if the MMU is enabled and select appropriate base address
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1
-       ldreq   \rx, =MSM_DEBUG_UART_PHYS
-       ldrne   \rx, =MSM_DEBUG_UART_BASE
+#ifdef CONFIG_HAS_MSM_DEBUG_UART_PHYS
+       .macro  addruart, rp, rv
+       ldr     \rp, =MSM_DEBUG_UART_PHYS
+       ldr     \rv, =MSM_DEBUG_UART_BASE
        .endm
 
        .macro  senduart,rd,rx
        tst     \rd, #0x04
        beq     1001b
        .endm
-#else
-       .macro  addruart, rx, tmp
-       .endm
-
-       .macro  senduart,rd,rx
-       .endm
-
-       .macro  waituart,rd,rx
-       .endm
-#endif
 
        .macro  busyuart,rd,rx
        .endm
+#endif
index 00f9bbfadbe6052972e5c5a183e312f7b800c233..05583f569524449ed2b61ea52ecd42544a959416 100644 (file)
@@ -32,10 +32,18 @@ struct msm_dmov_cmd {
        void *data;
 };
 
+#ifndef CONFIG_ARCH_MSM8X60
 void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd);
 void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful);
 int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr);
-
+#else
+static inline
+void msm_dmov_enqueue_cmd(unsigned id, struct msm_dmov_cmd *cmd) { }
+static inline
+void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful) { }
+static inline
+int msm_dmov_exec_cmd(unsigned id, unsigned int cmdptr) { return -EIO; }
+#endif
 
 
 #define DMOV_SD0(off, ch) (MSM_DMOV_BASE + 0x0000 + (off) + ((ch) << 2))
diff --git a/arch/arm/mach-msm/include/mach/entry-macro-qgic.S b/arch/arm/mach-msm/include/mach/entry-macro-qgic.S
new file mode 100644 (file)
index 0000000..4dc99aa
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Low-level IRQ helper macros
+ *
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <mach/hardware.h>
+#include <asm/hardware/gic.h>
+
+       .macro  disable_fiq
+       .endm
+
+       .macro  get_irqnr_preamble, base, tmp
+       ldr     \base, =gic_cpu_base_addr
+       ldr     \base, [\base]
+       .endm
+
+       .macro  arch_ret_to_user, tmp1, tmp2
+       .endm
+
+       /*
+        * The interrupt numbering scheme is defined in the
+        * interrupt controller spec.  To wit:
+        *
+        * Migrated the code from ARM MP port to be more consistant
+        * with interrupt processing , the following still holds true
+        * however, all interrupts are treated the same regardless of
+        * if they are local IPI or PPI
+        *
+        * Interrupts 0-15 are IPI
+        * 16-31 are PPI
+        *   (16-18 are the timers)
+        * 32-1020 are global
+        * 1021-1022 are reserved
+        * 1023 is "spurious" (no interrupt)
+        *
+        * 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 (0-1020 inclusive).
+        *
+        * Base ARM code assumes that the local (private) peripheral interrupts
+        * are not valid, we treat them differently, in that the privates are
+        * handled like normal shared interrupts with the exception that only
+        * one processor can register the interrupt and the handler must be
+        * the same for all processors.
+        */
+
+       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+
+       ldr  \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 =srcCPU,
+                                                  9-0 =int # */
+
+       bic     \irqnr, \irqstat, #0x1c00       @mask src
+       cmp     \irqnr, #15
+       ldr             \tmp, =1021
+       cmpcc   \irqnr, \irqnr
+       cmpne   \irqnr, \tmp
+       cmpcs   \irqnr, \irqnr
+
+       .endm
+
+       /* We assume that irqstat (the raw value of the IRQ acknowledge
+        * register) is preserved from the macro above.
+        * If there is an IPI, we immediately signal end of interrupt on the
+        * controller, since this requires the original irqstat value which
+        * we won't easily be able to recreate later.
+        */
+       .macro test_for_ipi, irqnr, irqstat, base, tmp
+    bic \irqnr, \irqstat, #0x1c00
+    cmp \irqnr, #16
+    strcc   \irqstat, [\base, #GIC_CPU_EOI]
+    cmpcs   \irqnr, \irqnr
+       .endm
+
+       /* As above, this assumes that irqstat and base are preserved.. */
+
+       .macro test_for_ltirq, irqnr, irqstat, base, tmp
+    bic \irqnr, \irqstat, #0x1c00
+    mov     \tmp, #0
+    cmp \irqnr, #16
+    moveq   \tmp, #1
+    streq   \irqstat, [\base, #GIC_CPU_EOI]
+    cmp \tmp, #0
+       .endm
diff --git a/arch/arm/mach-msm/include/mach/entry-macro-vic.S b/arch/arm/mach-msm/include/mach/entry-macro-vic.S
new file mode 100644 (file)
index 0000000..70563ed
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <mach/msm_iomap.h>
+
+       .macro  disable_fiq
+       .endm
+
+       .macro  get_irqnr_preamble, base, tmp
+       @ enable imprecise aborts
+       cpsie   a
+       mov     \base, #MSM_VIC_BASE
+       .endm
+
+       .macro  arch_ret_to_user, tmp1, tmp2
+       .endm
+
+       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
+       @ 0xD0 has irq# or old irq# if the irq has been handled
+       @ 0xD4 has irq# or -1 if none pending *but* if you just
+       @ read 0xD4 you never get the first irq for some reason
+       ldr     \irqnr, [\base, #0xD0]
+       ldr     \irqnr, [\base, #0xD4]
+       cmp     \irqnr, #0xffffffff
+       .endm
index d2259486bcb1588175df8a9f5fcdd76c5efe4aae..b16f082eeb6f7c092f8a041f3ba302fae5fcf163 100644 (file)
@@ -1,38 +1,23 @@
-/* arch/arm/mach-msm7200/include/mach/entry-macro.S
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
  *
- * Copyright (C) 2007 Google, Inc.
- * Author: Brian Swetland <swetland@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
+ * 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 <mach/msm_iomap.h>
-
-       .macro  disable_fiq
-       .endm
-
-       .macro  get_irqnr_preamble, base, tmp
-       @ enable imprecise aborts
-       cpsie   a
-       mov     \base, #MSM_VIC_BASE
-       .endm
-
-       .macro  arch_ret_to_user, tmp1, tmp2
-       .endm
-
-       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-       @ 0xD0 has irq# or old irq# if the irq has been handled
-       @ 0xD4 has irq# or -1 if none pending *but* if you just
-       @ read 0xD4 you never get the first irq for some reason
-       ldr     \irqnr, [\base, #0xD0]
-       ldr     \irqnr, [\base, #0xD4]
-       cmp     \irqnr, #0xffffffff
-       .endm
+#if defined(CONFIG_ARM_GIC)
+#include <mach/entry-macro-qgic.S>
+#else
+#include <mach/entry-macro-vic.S>
+#endif
index 83e47c0d5c2e451de5f459653053684beb786ee8..36ad50d3bfaa8e03e9f0333c05ed655d9ebf4adb 100644 (file)
 #define gpio_cansleep   __gpio_cansleep
 #define gpio_to_irq     __gpio_to_irq
 
-/**
- * struct msm_gpio - GPIO pin description
- * @gpio_cfg - configuration bitmap, as per gpio_tlmm_config()
- * @label - textual label
- *
- * Usually, GPIO's are operated by sets.
- * This struct accumulate all GPIO information in single source
- * and facilitete group operations provided by msm_gpios_xxx()
- */
-struct msm_gpio {
-       u32 gpio_cfg;
-       const char *label;
-};
-
-/**
- * msm_gpios_request_enable() - request and enable set of GPIOs
- *
- * Request and configure set of GPIO's
- * In case of error, all operations rolled back.
- * Return error code.
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-int msm_gpios_request_enable(const struct msm_gpio *table, int size);
-
-/**
- * msm_gpios_disable_free() - disable and free set of GPIOs
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-void msm_gpios_disable_free(const struct msm_gpio *table, int size);
-
-/**
- * msm_gpios_request() - request set of GPIOs
- * In case of error, all operations rolled back.
- * Return error code.
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-int msm_gpios_request(const struct msm_gpio *table, int size);
-
-/**
- * msm_gpios_free() - free set of GPIOs
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-void msm_gpios_free(const struct msm_gpio *table, int size);
-
-/**
- * msm_gpios_enable() - enable set of GPIOs
- * In case of error, all operations rolled back.
- * Return error code.
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-int msm_gpios_enable(const struct msm_gpio *table, int size);
-
-/**
- * msm_gpios_disable() - disable set of GPIOs
- *
- * @table: GPIO table
- * @size:  number of entries in @table
- */
-void msm_gpios_disable(const struct msm_gpio *table, int size);
-
-/* GPIO TLMM (Top Level Multiplexing) Definitions */
-
-/* GPIO TLMM: Function -- GPIO specific */
-
-/* GPIO TLMM: Direction */
-enum {
-       GPIO_INPUT,
-       GPIO_OUTPUT,
-};
-
-/* GPIO TLMM: Pullup/Pulldown */
-enum {
-       GPIO_NO_PULL,
-       GPIO_PULL_DOWN,
-       GPIO_KEEPER,
-       GPIO_PULL_UP,
-};
-
-/* GPIO TLMM: Drive Strength */
-enum {
-       GPIO_2MA,
-       GPIO_4MA,
-       GPIO_6MA,
-       GPIO_8MA,
-       GPIO_10MA,
-       GPIO_12MA,
-       GPIO_14MA,
-       GPIO_16MA,
-};
-
-enum {
-       GPIO_ENABLE,
-       GPIO_DISABLE,
-};
-
-#define GPIO_CFG(gpio, func, dir, pull, drvstr) \
-       ((((gpio) & 0x3FF) << 4)        |         \
-        ((func) & 0xf)                  |        \
-        (((dir) & 0x1) << 14)           |        \
-        (((pull) & 0x3) << 15)          |        \
-        (((drvstr) & 0xF) << 17))
-
-/**
- * extract GPIO pin from bit-field used for gpio_tlmm_config
- */
-#define GPIO_PIN(gpio_cfg)    (((gpio_cfg) >>  4) & 0x3ff)
-#define GPIO_FUNC(gpio_cfg)   (((gpio_cfg) >>  0) & 0xf)
-#define GPIO_DIR(gpio_cfg)    (((gpio_cfg) >> 14) & 0x1)
-#define GPIO_PULL(gpio_cfg)   (((gpio_cfg) >> 15) & 0x3)
-#define GPIO_DRVSTR(gpio_cfg) (((gpio_cfg) >> 17) & 0xf)
-
-int gpio_tlmm_config(unsigned config, unsigned disable);
-
 #endif /* __ASM_ARCH_MSM_GPIO_H */
index c35b29f9ac0fb615180344f7edb0bb3440bc1b7b..7386e732baad9d380914fd923404cb7a5e2e1931 100644 (file)
@@ -28,6 +28,7 @@ void __iomem *__msm_ioremap(unsigned long phys_addr, size_t size, unsigned int m
 
 void msm_map_qsd8x50_io(void);
 void msm_map_msm7x30_io(void);
+void msm_map_msm8x60_io(void);
 
 extern unsigned int msm_shared_ram_phys;
 
diff --git a/arch/arm/mach-msm/include/mach/iommu.h b/arch/arm/mach-msm/include/mach/iommu.h
new file mode 100644 (file)
index 0000000..218ef57
--- /dev/null
@@ -0,0 +1,103 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 MSM_IOMMU_H
+#define MSM_IOMMU_H
+
+#include <linux/interrupt.h>
+
+/* Maximum number of Machine IDs that we are allowing to be mapped to the same
+ * context bank. The number of MIDs mapped to the same CB does not affect
+ * performance, but there is a practical limit on how many distinct MIDs may
+ * be present. These mappings are typically determined at design time and are
+ * not expected to change at run time.
+ */
+#define MAX_NUM_MIDS   16
+
+/**
+ * struct msm_iommu_dev - a single IOMMU hardware instance
+ * name                Human-readable name given to this IOMMU HW instance
+ * clk_rate    Rate to set for this IOMMU's clock, if applicable to this
+ *             particular IOMMU. 0 means don't set a rate.
+ *             -1 means it is an AXI clock with no valid rate
+ *
+ */
+struct msm_iommu_dev {
+       const char *name;
+       int clk_rate;
+};
+
+/**
+ * struct msm_iommu_ctx_dev - an IOMMU context bank instance
+ * name                Human-readable name given to this context bank
+ * num         Index of this context bank within the hardware
+ * mids                List of Machine IDs that are to be mapped into this context
+ *             bank, terminated by -1. The MID is a set of signals on the
+ *             AXI bus that identifies the function associated with a specific
+ *             memory request. (See ARM spec).
+ */
+struct msm_iommu_ctx_dev {
+       const char *name;
+       int num;
+       int mids[MAX_NUM_MIDS];
+};
+
+
+/**
+ * struct msm_iommu_drvdata - A single IOMMU hardware instance
+ * @base:      IOMMU config port base address (VA)
+ * @irq:       Interrupt number
+  *
+ * A msm_iommu_drvdata holds the global driver data about a single piece
+ * of an IOMMU hardware instance.
+ */
+struct msm_iommu_drvdata {
+       void __iomem *base;
+       int irq;
+};
+
+/**
+ * struct msm_iommu_ctx_drvdata - an IOMMU context bank instance
+ * @num:               Hardware context number of this context
+ * @pdev:              Platform device associated wit this HW instance
+ * @attached_elm:      List element for domains to track which devices are
+ *                     attached to them
+ *
+ * A msm_iommu_ctx_drvdata holds the driver data for a single context bank
+ * within each IOMMU hardware instance
+ */
+struct msm_iommu_ctx_drvdata {
+       int num;
+       struct platform_device *pdev;
+       struct list_head attached_elm;
+};
+
+/*
+ * Look up an IOMMU context device by its context name. NULL if none found.
+ * Useful for testing and drivers that do not yet fully have IOMMU stuff in
+ * their platform devices.
+ */
+struct device *msm_iommu_get_ctx(const char *ctx_name);
+
+/*
+ * Interrupt handler for the IOMMU context fault interrupt. Hooking the
+ * interrupt is not supported in the API yet, but this will print an error
+ * message and dump useful IOMMU registers.
+ */
+irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id);
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h b/arch/arm/mach-msm/include/mach/iommu_hw-8xxx.h
new file mode 100644 (file)
index 0000000..f9386d3
--- /dev/null
@@ -0,0 +1,1871 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 __ARCH_ARM_MACH_MSM_IOMMU_HW_8XXX_H
+#define __ARCH_ARM_MACH_MSM_IOMMU_HW_8XXX_H
+
+#define CTX_SHIFT 12
+
+#define GET_GLOBAL_REG(reg, base) (readl((base) + (reg)))
+#define GET_CTX_REG(reg, base, ctx) \
+                               (readl((base) + (reg) + ((ctx) << CTX_SHIFT)))
+
+#define SET_GLOBAL_REG(reg, base, val) writel((val), ((base) + (reg)))
+
+#define SET_CTX_REG(reg, base, ctx, val) \
+                       writel((val), ((base) + (reg) + ((ctx) << CTX_SHIFT)))
+
+/* Wrappers for numbered registers */
+#define SET_GLOBAL_REG_N(b, n, r, v) SET_GLOBAL_REG(b, ((r) + (n << 2)), (v))
+#define GET_GLOBAL_REG_N(b, n, r)    GET_GLOBAL_REG(b, ((r) + (n << 2)))
+
+/* Field wrappers */
+#define GET_GLOBAL_FIELD(b, r, F)    GET_FIELD(((b) + (r)), F##_MASK, F##_SHIFT)
+#define GET_CONTEXT_FIELD(b, c, r, F)  \
+       GET_FIELD(((b) + (r) + ((c) << CTX_SHIFT)), F##_MASK, F##_SHIFT)
+
+#define SET_GLOBAL_FIELD(b, r, F, v) \
+       SET_FIELD(((b) + (r)), F##_MASK, F##_SHIFT, (v))
+#define SET_CONTEXT_FIELD(b, c, r, F, v)       \
+       SET_FIELD(((b) + (r) + ((c) << CTX_SHIFT)), F##_MASK, F##_SHIFT, (v))
+
+#define GET_FIELD(addr, mask, shift)  ((readl(addr) >> (shift)) & (mask))
+
+#define SET_FIELD(addr, mask, shift, v) \
+do { \
+       int t = readl(addr); \
+       writel((t & ~((mask) << (shift))) + (((v) & (mask)) << (shift)), addr);\
+} while (0)
+
+
+#define NUM_FL_PTE     4096
+#define NUM_SL_PTE     256
+
+/* First-level page table bits */
+#define FL_BASE_MASK           0xFFFFFC00
+#define FL_TYPE_TABLE          (1 << 0)
+#define FL_TYPE_SECT           (2 << 0)
+#define FL_SUPERSECTION                (1 << 18)
+#define FL_AP_WRITE            (1 << 10)
+#define FL_AP_READ             (1 << 11)
+#define FL_SHARED              (1 << 16)
+#define FL_OFFSET(va)          (((va) & 0xFFF00000) >> 20)
+
+/* Second-level page table bits */
+#define SL_BASE_MASK_LARGE     0xFFFF0000
+#define SL_BASE_MASK_SMALL     0xFFFFF000
+#define SL_TYPE_LARGE          (1 << 0)
+#define SL_TYPE_SMALL          (2 << 0)
+#define SL_AP0                 (1 << 4)
+#define SL_AP1                 (2 << 4)
+#define SL_SHARED              (1 << 10)
+#define SL_OFFSET(va)          (((va) & 0xFF000) >> 12)
+
+/* Global register setters / getters */
+#define SET_M2VCBR_N(b, N, v)   SET_GLOBAL_REG_N(M2VCBR_N, N, (b), (v))
+#define SET_CBACR_N(b, N, v)    SET_GLOBAL_REG_N(CBACR_N, N, (b), (v))
+#define SET_TLBRSW(b, v)        SET_GLOBAL_REG(TLBRSW, (b), (v))
+#define SET_TLBTR0(b, v)        SET_GLOBAL_REG(TLBTR0, (b), (v))
+#define SET_TLBTR1(b, v)        SET_GLOBAL_REG(TLBTR1, (b), (v))
+#define SET_TLBTR2(b, v)        SET_GLOBAL_REG(TLBTR2, (b), (v))
+#define SET_TESTBUSCR(b, v)     SET_GLOBAL_REG(TESTBUSCR, (b), (v))
+#define SET_GLOBAL_TLBIALL(b, v) SET_GLOBAL_REG(GLOBAL_TLBIALL, (b), (v))
+#define SET_TLBIVMID(b, v)      SET_GLOBAL_REG(TLBIVMID, (b), (v))
+#define SET_CR(b, v)            SET_GLOBAL_REG(CR, (b), (v))
+#define SET_EAR(b, v)           SET_GLOBAL_REG(EAR, (b), (v))
+#define SET_ESR(b, v)           SET_GLOBAL_REG(ESR, (b), (v))
+#define SET_ESRRESTORE(b, v)    SET_GLOBAL_REG(ESRRESTORE, (b), (v))
+#define SET_ESYNR0(b, v)        SET_GLOBAL_REG(ESYNR0, (b), (v))
+#define SET_ESYNR1(b, v)        SET_GLOBAL_REG(ESYNR1, (b), (v))
+#define SET_RPU_ACR(b, v)       SET_GLOBAL_REG(RPU_ACR, (b), (v))
+
+#define GET_M2VCBR_N(b, N)      GET_GLOBAL_REG_N(M2VCBR_N, N, (b))
+#define GET_CBACR_N(b, N)       GET_GLOBAL_REG_N(CBACR_N, N, (b))
+#define GET_TLBTR0(b)           GET_GLOBAL_REG(TLBTR0, (b))
+#define GET_TLBTR1(b)           GET_GLOBAL_REG(TLBTR1, (b))
+#define GET_TLBTR2(b)           GET_GLOBAL_REG(TLBTR2, (b))
+#define GET_TESTBUSCR(b)        GET_GLOBAL_REG(TESTBUSCR, (b))
+#define GET_GLOBAL_TLBIALL(b)   GET_GLOBAL_REG(GLOBAL_TLBIALL, (b))
+#define GET_TLBIVMID(b)                 GET_GLOBAL_REG(TLBIVMID, (b))
+#define GET_CR(b)               GET_GLOBAL_REG(CR, (b))
+#define GET_EAR(b)              GET_GLOBAL_REG(EAR, (b))
+#define GET_ESR(b)              GET_GLOBAL_REG(ESR, (b))
+#define GET_ESRRESTORE(b)       GET_GLOBAL_REG(ESRRESTORE, (b))
+#define GET_ESYNR0(b)           GET_GLOBAL_REG(ESYNR0, (b))
+#define GET_ESYNR1(b)           GET_GLOBAL_REG(ESYNR1, (b))
+#define GET_REV(b)              GET_GLOBAL_REG(REV, (b))
+#define GET_IDR(b)              GET_GLOBAL_REG(IDR, (b))
+#define GET_RPU_ACR(b)          GET_GLOBAL_REG(RPU_ACR, (b))
+
+
+/* Context register setters/getters */
+#define SET_SCTLR(b, c, v)      SET_CTX_REG(SCTLR, (b), (c), (v))
+#define SET_ACTLR(b, c, v)      SET_CTX_REG(ACTLR, (b), (c), (v))
+#define SET_CONTEXTIDR(b, c, v)         SET_CTX_REG(CONTEXTIDR, (b), (c), (v))
+#define SET_TTBR0(b, c, v)      SET_CTX_REG(TTBR0, (b), (c), (v))
+#define SET_TTBR1(b, c, v)      SET_CTX_REG(TTBR1, (b), (c), (v))
+#define SET_TTBCR(b, c, v)      SET_CTX_REG(TTBCR, (b), (c), (v))
+#define SET_PAR(b, c, v)        SET_CTX_REG(PAR, (b), (c), (v))
+#define SET_FSR(b, c, v)        SET_CTX_REG(FSR, (b), (c), (v))
+#define SET_FSRRESTORE(b, c, v)         SET_CTX_REG(FSRRESTORE, (b), (c), (v))
+#define SET_FAR(b, c, v)        SET_CTX_REG(FAR, (b), (c), (v))
+#define SET_FSYNR0(b, c, v)     SET_CTX_REG(FSYNR0, (b), (c), (v))
+#define SET_FSYNR1(b, c, v)     SET_CTX_REG(FSYNR1, (b), (c), (v))
+#define SET_PRRR(b, c, v)       SET_CTX_REG(PRRR, (b), (c), (v))
+#define SET_NMRR(b, c, v)       SET_CTX_REG(NMRR, (b), (c), (v))
+#define SET_TLBLKCR(b, c, v)    SET_CTX_REG(TLBLCKR, (b), (c), (v))
+#define SET_V2PSR(b, c, v)      SET_CTX_REG(V2PSR, (b), (c), (v))
+#define SET_TLBFLPTER(b, c, v)  SET_CTX_REG(TLBFLPTER, (b), (c), (v))
+#define SET_TLBSLPTER(b, c, v)  SET_CTX_REG(TLBSLPTER, (b), (c), (v))
+#define SET_BFBCR(b, c, v)      SET_CTX_REG(BFBCR, (b), (c), (v))
+#define SET_CTX_TLBIALL(b, c, v) SET_CTX_REG(CTX_TLBIALL, (b), (c), (v))
+#define SET_TLBIASID(b, c, v)   SET_CTX_REG(TLBIASID, (b), (c), (v))
+#define SET_TLBIVA(b, c, v)     SET_CTX_REG(TLBIVA, (b), (c), (v))
+#define SET_TLBIVAA(b, c, v)    SET_CTX_REG(TLBIVAA, (b), (c), (v))
+#define SET_V2PPR(b, c, v)      SET_CTX_REG(V2PPR, (b), (c), (v))
+#define SET_V2PPW(b, c, v)      SET_CTX_REG(V2PPW, (b), (c), (v))
+#define SET_V2PUR(b, c, v)      SET_CTX_REG(V2PUR, (b), (c), (v))
+#define SET_V2PUW(b, c, v)      SET_CTX_REG(V2PUW, (b), (c), (v))
+#define SET_RESUME(b, c, v)     SET_CTX_REG(RESUME, (b), (c), (v))
+
+#define GET_SCTLR(b, c)                 GET_CTX_REG(SCTLR, (b), (c))
+#define GET_ACTLR(b, c)                 GET_CTX_REG(ACTLR, (b), (c))
+#define GET_CONTEXTIDR(b, c)    GET_CTX_REG(CONTEXTIDR, (b), (c))
+#define GET_TTBR0(b, c)                 GET_CTX_REG(TTBR0, (b), (c))
+#define GET_TTBR1(b, c)                 GET_CTX_REG(TTBR1, (b), (c))
+#define GET_TTBCR(b, c)                 GET_CTX_REG(TTBCR, (b), (c))
+#define GET_PAR(b, c)           GET_CTX_REG(PAR, (b), (c))
+#define GET_FSR(b, c)           GET_CTX_REG(FSR, (b), (c))
+#define GET_FSRRESTORE(b, c)    GET_CTX_REG(FSRRESTORE, (b), (c))
+#define GET_FAR(b, c)           GET_CTX_REG(FAR, (b), (c))
+#define GET_FSYNR0(b, c)        GET_CTX_REG(FSYNR0, (b), (c))
+#define GET_FSYNR1(b, c)        GET_CTX_REG(FSYNR1, (b), (c))
+#define GET_PRRR(b, c)          GET_CTX_REG(PRRR, (b), (c))
+#define GET_NMRR(b, c)          GET_CTX_REG(NMRR, (b), (c))
+#define GET_TLBLCKR(b, c)       GET_CTX_REG(TLBLCKR, (b), (c))
+#define GET_V2PSR(b, c)                 GET_CTX_REG(V2PSR, (b), (c))
+#define GET_TLBFLPTER(b, c)     GET_CTX_REG(TLBFLPTER, (b), (c))
+#define GET_TLBSLPTER(b, c)     GET_CTX_REG(TLBSLPTER, (b), (c))
+#define GET_BFBCR(b, c)                 GET_CTX_REG(BFBCR, (b), (c))
+#define GET_CTX_TLBIALL(b, c)   GET_CTX_REG(CTX_TLBIALL, (b), (c))
+#define GET_TLBIASID(b, c)      GET_CTX_REG(TLBIASID, (b), (c))
+#define GET_TLBIVA(b, c)        GET_CTX_REG(TLBIVA, (b), (c))
+#define GET_TLBIVAA(b, c)       GET_CTX_REG(TLBIVAA, (b), (c))
+#define GET_V2PPR(b, c)                 GET_CTX_REG(V2PPR, (b), (c))
+#define GET_V2PPW(b, c)                 GET_CTX_REG(V2PPW, (b), (c))
+#define GET_V2PUR(b, c)                 GET_CTX_REG(V2PUR, (b), (c))
+#define GET_V2PUW(b, c)                 GET_CTX_REG(V2PUW, (b), (c))
+#define GET_RESUME(b, c)        GET_CTX_REG(RESUME, (b), (c))
+
+
+/* Global field setters / getters */
+/* Global Field Setters: */
+/* CBACR_N */
+#define SET_RWVMID(b, n, v)   SET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWVMID, v)
+#define SET_RWE(b, n, v)      SET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWE, v)
+#define SET_RWGE(b, n, v)     SET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWGE, v)
+#define SET_CBVMID(b, n, v)   SET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), CBVMID, v)
+#define SET_IRPTNDX(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), IRPTNDX, v)
+
+
+/* M2VCBR_N */
+#define SET_VMID(b, n, v)     SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), VMID, v)
+#define SET_CBNDX(b, n, v)    SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), CBNDX, v)
+#define SET_BYPASSD(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BYPASSD, v)
+#define SET_BPRCOSH(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCOSH, v)
+#define SET_BPRCISH(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCISH, v)
+#define SET_BPRCNSH(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCNSH, v)
+#define SET_BPSHCFG(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPSHCFG, v)
+#define SET_NSCFG(b, n, v)    SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), NSCFG, v)
+#define SET_BPMTCFG(b, n, v)  SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPMTCFG, v)
+#define SET_BPMEMTYPE(b, n, v) \
+       SET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPMEMTYPE, v)
+
+
+/* CR */
+#define SET_RPUE(b, v)          SET_GLOBAL_FIELD(b, CR, RPUE, v)
+#define SET_RPUERE(b, v)        SET_GLOBAL_FIELD(b, CR, RPUERE, v)
+#define SET_RPUEIE(b, v)        SET_GLOBAL_FIELD(b, CR, RPUEIE, v)
+#define SET_DCDEE(b, v)                 SET_GLOBAL_FIELD(b, CR, DCDEE, v)
+#define SET_CLIENTPD(b, v)       SET_GLOBAL_FIELD(b, CR, CLIENTPD, v)
+#define SET_STALLD(b, v)        SET_GLOBAL_FIELD(b, CR, STALLD, v)
+#define SET_TLBLKCRWE(b, v)      SET_GLOBAL_FIELD(b, CR, TLBLKCRWE, v)
+#define SET_CR_TLBIALLCFG(b, v)  SET_GLOBAL_FIELD(b, CR, CR_TLBIALLCFG, v)
+#define SET_TLBIVMIDCFG(b, v)    SET_GLOBAL_FIELD(b, CR, TLBIVMIDCFG, v)
+#define SET_CR_HUME(b, v)        SET_GLOBAL_FIELD(b, CR, CR_HUME, v)
+
+
+/* ESR */
+#define SET_CFG(b, v)           SET_GLOBAL_FIELD(b, ESR, CFG, v)
+#define SET_BYPASS(b, v)        SET_GLOBAL_FIELD(b, ESR, BYPASS, v)
+#define SET_ESR_MULTI(b, v)      SET_GLOBAL_FIELD(b, ESR, ESR_MULTI, v)
+
+
+/* ESYNR0 */
+#define SET_ESYNR0_AMID(b, v)    SET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_AMID, v)
+#define SET_ESYNR0_APID(b, v)    SET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_APID, v)
+#define SET_ESYNR0_ABID(b, v)    SET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_ABID, v)
+#define SET_ESYNR0_AVMID(b, v)   SET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_AVMID, v)
+#define SET_ESYNR0_ATID(b, v)    SET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_ATID, v)
+
+
+/* ESYNR1 */
+#define SET_ESYNR1_AMEMTYPE(b, v) \
+                       SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AMEMTYPE, v)
+#define SET_ESYNR1_ASHARED(b, v)  SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ASHARED, v)
+#define SET_ESYNR1_AINNERSHARED(b, v) \
+                       SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AINNERSHARED, v)
+#define SET_ESYNR1_APRIV(b, v)   SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_APRIV, v)
+#define SET_ESYNR1_APROTNS(b, v) SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_APROTNS, v)
+#define SET_ESYNR1_AINST(b, v)   SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AINST, v)
+#define SET_ESYNR1_AWRITE(b, v)  SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AWRITE, v)
+#define SET_ESYNR1_ABURST(b, v)  SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ABURST, v)
+#define SET_ESYNR1_ALEN(b, v)    SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ALEN, v)
+#define SET_ESYNR1_ASIZE(b, v)   SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ASIZE, v)
+#define SET_ESYNR1_ALOCK(b, v)   SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ALOCK, v)
+#define SET_ESYNR1_AOOO(b, v)    SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AOOO, v)
+#define SET_ESYNR1_AFULL(b, v)   SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AFULL, v)
+#define SET_ESYNR1_AC(b, v)      SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AC, v)
+#define SET_ESYNR1_DCD(b, v)     SET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_DCD, v)
+
+
+/* TESTBUSCR */
+#define SET_TBE(b, v)           SET_GLOBAL_FIELD(b, TESTBUSCR, TBE, v)
+#define SET_SPDMBE(b, v)        SET_GLOBAL_FIELD(b, TESTBUSCR, SPDMBE, v)
+#define SET_WGSEL(b, v)                 SET_GLOBAL_FIELD(b, TESTBUSCR, WGSEL, v)
+#define SET_TBLSEL(b, v)        SET_GLOBAL_FIELD(b, TESTBUSCR, TBLSEL, v)
+#define SET_TBHSEL(b, v)        SET_GLOBAL_FIELD(b, TESTBUSCR, TBHSEL, v)
+#define SET_SPDM0SEL(b, v)       SET_GLOBAL_FIELD(b, TESTBUSCR, SPDM0SEL, v)
+#define SET_SPDM1SEL(b, v)       SET_GLOBAL_FIELD(b, TESTBUSCR, SPDM1SEL, v)
+#define SET_SPDM2SEL(b, v)       SET_GLOBAL_FIELD(b, TESTBUSCR, SPDM2SEL, v)
+#define SET_SPDM3SEL(b, v)       SET_GLOBAL_FIELD(b, TESTBUSCR, SPDM3SEL, v)
+
+
+/* TLBIVMID */
+#define SET_TLBIVMID_VMID(b, v)  SET_GLOBAL_FIELD(b, TLBIVMID, TLBIVMID_VMID, v)
+
+
+/* TLBRSW */
+#define SET_TLBRSW_INDEX(b, v)   SET_GLOBAL_FIELD(b, TLBRSW, TLBRSW_INDEX, v)
+#define SET_TLBBFBS(b, v)       SET_GLOBAL_FIELD(b, TLBRSW, TLBBFBS, v)
+
+
+/* TLBTR0 */
+#define SET_PR(b, v)            SET_GLOBAL_FIELD(b, TLBTR0, PR, v)
+#define SET_PW(b, v)            SET_GLOBAL_FIELD(b, TLBTR0, PW, v)
+#define SET_UR(b, v)            SET_GLOBAL_FIELD(b, TLBTR0, UR, v)
+#define SET_UW(b, v)            SET_GLOBAL_FIELD(b, TLBTR0, UW, v)
+#define SET_XN(b, v)            SET_GLOBAL_FIELD(b, TLBTR0, XN, v)
+#define SET_NSDESC(b, v)        SET_GLOBAL_FIELD(b, TLBTR0, NSDESC, v)
+#define SET_ISH(b, v)           SET_GLOBAL_FIELD(b, TLBTR0, ISH, v)
+#define SET_SH(b, v)            SET_GLOBAL_FIELD(b, TLBTR0, SH, v)
+#define SET_MT(b, v)            SET_GLOBAL_FIELD(b, TLBTR0, MT, v)
+#define SET_DPSIZR(b, v)        SET_GLOBAL_FIELD(b, TLBTR0, DPSIZR, v)
+#define SET_DPSIZC(b, v)        SET_GLOBAL_FIELD(b, TLBTR0, DPSIZC, v)
+
+
+/* TLBTR1 */
+#define SET_TLBTR1_VMID(b, v)    SET_GLOBAL_FIELD(b, TLBTR1, TLBTR1_VMID, v)
+#define SET_TLBTR1_PA(b, v)      SET_GLOBAL_FIELD(b, TLBTR1, TLBTR1_PA, v)
+
+
+/* TLBTR2 */
+#define SET_TLBTR2_ASID(b, v)    SET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_ASID, v)
+#define SET_TLBTR2_V(b, v)       SET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_V, v)
+#define SET_TLBTR2_NSTID(b, v)   SET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_NSTID, v)
+#define SET_TLBTR2_NV(b, v)      SET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_NV, v)
+#define SET_TLBTR2_VA(b, v)      SET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_VA, v)
+
+
+/* Global Field Getters */
+/* CBACR_N */
+#define GET_RWVMID(b, n)        GET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWVMID)
+#define GET_RWE(b, n)           GET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWE)
+#define GET_RWGE(b, n)          GET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), RWGE)
+#define GET_CBVMID(b, n)        GET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), CBVMID)
+#define GET_IRPTNDX(b, n)       GET_GLOBAL_FIELD(b, (n<<2)|(CBACR_N), IRPTNDX)
+
+
+/* M2VCBR_N */
+#define GET_VMID(b, n)       GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), VMID)
+#define GET_CBNDX(b, n)      GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), CBNDX)
+#define GET_BYPASSD(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BYPASSD)
+#define GET_BPRCOSH(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCOSH)
+#define GET_BPRCISH(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCISH)
+#define GET_BPRCNSH(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPRCNSH)
+#define GET_BPSHCFG(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPSHCFG)
+#define GET_NSCFG(b, n)      GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), NSCFG)
+#define GET_BPMTCFG(b, n)    GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPMTCFG)
+#define GET_BPMEMTYPE(b, n)  GET_GLOBAL_FIELD(b, (n<<2)|(M2VCBR_N), BPMEMTYPE)
+
+
+/* CR */
+#define GET_RPUE(b)             GET_GLOBAL_FIELD(b, CR, RPUE)
+#define GET_RPUERE(b)           GET_GLOBAL_FIELD(b, CR, RPUERE)
+#define GET_RPUEIE(b)           GET_GLOBAL_FIELD(b, CR, RPUEIE)
+#define GET_DCDEE(b)            GET_GLOBAL_FIELD(b, CR, DCDEE)
+#define GET_CLIENTPD(b)                 GET_GLOBAL_FIELD(b, CR, CLIENTPD)
+#define GET_STALLD(b)           GET_GLOBAL_FIELD(b, CR, STALLD)
+#define GET_TLBLKCRWE(b)        GET_GLOBAL_FIELD(b, CR, TLBLKCRWE)
+#define GET_CR_TLBIALLCFG(b)    GET_GLOBAL_FIELD(b, CR, CR_TLBIALLCFG)
+#define GET_TLBIVMIDCFG(b)      GET_GLOBAL_FIELD(b, CR, TLBIVMIDCFG)
+#define GET_CR_HUME(b)          GET_GLOBAL_FIELD(b, CR, CR_HUME)
+
+
+/* ESR */
+#define GET_CFG(b)              GET_GLOBAL_FIELD(b, ESR, CFG)
+#define GET_BYPASS(b)           GET_GLOBAL_FIELD(b, ESR, BYPASS)
+#define GET_ESR_MULTI(b)        GET_GLOBAL_FIELD(b, ESR, ESR_MULTI)
+
+
+/* ESYNR0 */
+#define GET_ESYNR0_AMID(b)      GET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_AMID)
+#define GET_ESYNR0_APID(b)      GET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_APID)
+#define GET_ESYNR0_ABID(b)      GET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_ABID)
+#define GET_ESYNR0_AVMID(b)     GET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_AVMID)
+#define GET_ESYNR0_ATID(b)      GET_GLOBAL_FIELD(b, ESYNR0, ESYNR0_ATID)
+
+
+/* ESYNR1 */
+#define GET_ESYNR1_AMEMTYPE(b)   GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AMEMTYPE)
+#define GET_ESYNR1_ASHARED(b)    GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ASHARED)
+#define GET_ESYNR1_AINNERSHARED(b) \
+                       GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AINNERSHARED)
+#define GET_ESYNR1_APRIV(b)      GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_APRIV)
+#define GET_ESYNR1_APROTNS(b)   GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_APROTNS)
+#define GET_ESYNR1_AINST(b)     GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AINST)
+#define GET_ESYNR1_AWRITE(b)    GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AWRITE)
+#define GET_ESYNR1_ABURST(b)    GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ABURST)
+#define GET_ESYNR1_ALEN(b)      GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ALEN)
+#define GET_ESYNR1_ASIZE(b)     GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ASIZE)
+#define GET_ESYNR1_ALOCK(b)     GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_ALOCK)
+#define GET_ESYNR1_AOOO(b)      GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AOOO)
+#define GET_ESYNR1_AFULL(b)     GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AFULL)
+#define GET_ESYNR1_AC(b)        GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_AC)
+#define GET_ESYNR1_DCD(b)       GET_GLOBAL_FIELD(b, ESYNR1, ESYNR1_DCD)
+
+
+/* IDR */
+#define GET_NM2VCBMT(b)                 GET_GLOBAL_FIELD(b, IDR, NM2VCBMT)
+#define GET_HTW(b)              GET_GLOBAL_FIELD(b, IDR, HTW)
+#define GET_HUM(b)              GET_GLOBAL_FIELD(b, IDR, HUM)
+#define GET_TLBSIZE(b)          GET_GLOBAL_FIELD(b, IDR, TLBSIZE)
+#define GET_NCB(b)              GET_GLOBAL_FIELD(b, IDR, NCB)
+#define GET_NIRPT(b)            GET_GLOBAL_FIELD(b, IDR, NIRPT)
+
+
+/* REV */
+#define GET_MAJOR(b)            GET_GLOBAL_FIELD(b, REV, MAJOR)
+#define GET_MINOR(b)            GET_GLOBAL_FIELD(b, REV, MINOR)
+
+
+/* TESTBUSCR */
+#define GET_TBE(b)              GET_GLOBAL_FIELD(b, TESTBUSCR, TBE)
+#define GET_SPDMBE(b)           GET_GLOBAL_FIELD(b, TESTBUSCR, SPDMBE)
+#define GET_WGSEL(b)            GET_GLOBAL_FIELD(b, TESTBUSCR, WGSEL)
+#define GET_TBLSEL(b)           GET_GLOBAL_FIELD(b, TESTBUSCR, TBLSEL)
+#define GET_TBHSEL(b)           GET_GLOBAL_FIELD(b, TESTBUSCR, TBHSEL)
+#define GET_SPDM0SEL(b)                 GET_GLOBAL_FIELD(b, TESTBUSCR, SPDM0SEL)
+#define GET_SPDM1SEL(b)                 GET_GLOBAL_FIELD(b, TESTBUSCR, SPDM1SEL)
+#define GET_SPDM2SEL(b)                 GET_GLOBAL_FIELD(b, TESTBUSCR, SPDM2SEL)
+#define GET_SPDM3SEL(b)                 GET_GLOBAL_FIELD(b, TESTBUSCR, SPDM3SEL)
+
+
+/* TLBIVMID */
+#define GET_TLBIVMID_VMID(b)    GET_GLOBAL_FIELD(b, TLBIVMID, TLBIVMID_VMID)
+
+
+/* TLBTR0 */
+#define GET_PR(b)               GET_GLOBAL_FIELD(b, TLBTR0, PR)
+#define GET_PW(b)               GET_GLOBAL_FIELD(b, TLBTR0, PW)
+#define GET_UR(b)               GET_GLOBAL_FIELD(b, TLBTR0, UR)
+#define GET_UW(b)               GET_GLOBAL_FIELD(b, TLBTR0, UW)
+#define GET_XN(b)               GET_GLOBAL_FIELD(b, TLBTR0, XN)
+#define GET_NSDESC(b)           GET_GLOBAL_FIELD(b, TLBTR0, NSDESC)
+#define GET_ISH(b)              GET_GLOBAL_FIELD(b, TLBTR0, ISH)
+#define GET_SH(b)               GET_GLOBAL_FIELD(b, TLBTR0, SH)
+#define GET_MT(b)               GET_GLOBAL_FIELD(b, TLBTR0, MT)
+#define GET_DPSIZR(b)           GET_GLOBAL_FIELD(b, TLBTR0, DPSIZR)
+#define GET_DPSIZC(b)           GET_GLOBAL_FIELD(b, TLBTR0, DPSIZC)
+
+
+/* TLBTR1 */
+#define GET_TLBTR1_VMID(b)      GET_GLOBAL_FIELD(b, TLBTR1, TLBTR1_VMID)
+#define GET_TLBTR1_PA(b)        GET_GLOBAL_FIELD(b, TLBTR1, TLBTR1_PA)
+
+
+/* TLBTR2 */
+#define GET_TLBTR2_ASID(b)      GET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_ASID)
+#define GET_TLBTR2_V(b)                 GET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_V)
+#define GET_TLBTR2_NSTID(b)     GET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_NSTID)
+#define GET_TLBTR2_NV(b)        GET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_NV)
+#define GET_TLBTR2_VA(b)        GET_GLOBAL_FIELD(b, TLBTR2, TLBTR2_VA)
+
+
+/* Context Register setters / getters */
+/* Context Register setters */
+/* ACTLR */
+#define SET_CFERE(b, c, v)      SET_CONTEXT_FIELD(b, c, ACTLR, CFERE, v)
+#define SET_CFEIE(b, c, v)      SET_CONTEXT_FIELD(b, c, ACTLR, CFEIE, v)
+#define SET_PTSHCFG(b, c, v)    SET_CONTEXT_FIELD(b, c, ACTLR, PTSHCFG, v)
+#define SET_RCOSH(b, c, v)      SET_CONTEXT_FIELD(b, c, ACTLR, RCOSH, v)
+#define SET_RCISH(b, c, v)      SET_CONTEXT_FIELD(b, c, ACTLR, RCISH, v)
+#define SET_RCNSH(b, c, v)      SET_CONTEXT_FIELD(b, c, ACTLR, RCNSH, v)
+#define SET_PRIVCFG(b, c, v)    SET_CONTEXT_FIELD(b, c, ACTLR, PRIVCFG, v)
+#define SET_DNA(b, c, v)        SET_CONTEXT_FIELD(b, c, ACTLR, DNA, v)
+#define SET_DNLV2PA(b, c, v)    SET_CONTEXT_FIELD(b, c, ACTLR, DNLV2PA, v)
+#define SET_TLBMCFG(b, c, v)    SET_CONTEXT_FIELD(b, c, ACTLR, TLBMCFG, v)
+#define SET_CFCFG(b, c, v)      SET_CONTEXT_FIELD(b, c, ACTLR, CFCFG, v)
+#define SET_TIPCF(b, c, v)      SET_CONTEXT_FIELD(b, c, ACTLR, TIPCF, v)
+#define SET_V2PCFG(b, c, v)     SET_CONTEXT_FIELD(b, c, ACTLR, V2PCFG, v)
+#define SET_HUME(b, c, v)       SET_CONTEXT_FIELD(b, c, ACTLR, HUME, v)
+#define SET_PTMTCFG(b, c, v)    SET_CONTEXT_FIELD(b, c, ACTLR, PTMTCFG, v)
+#define SET_PTMEMTYPE(b, c, v)  SET_CONTEXT_FIELD(b, c, ACTLR, PTMEMTYPE, v)
+
+
+/* BFBCR */
+#define SET_BFBDFE(b, c, v)     SET_CONTEXT_FIELD(b, c, BFBCR, BFBDFE, v)
+#define SET_BFBSFE(b, c, v)     SET_CONTEXT_FIELD(b, c, BFBCR, BFBSFE, v)
+#define SET_SFVS(b, c, v)       SET_CONTEXT_FIELD(b, c, BFBCR, SFVS, v)
+#define SET_FLVIC(b, c, v)      SET_CONTEXT_FIELD(b, c, BFBCR, FLVIC, v)
+#define SET_SLVIC(b, c, v)      SET_CONTEXT_FIELD(b, c, BFBCR, SLVIC, v)
+
+
+/* CONTEXTIDR */
+#define SET_CONTEXTIDR_ASID(b, c, v)   \
+               SET_CONTEXT_FIELD(b, c, CONTEXTIDR, CONTEXTIDR_ASID, v)
+#define SET_CONTEXTIDR_PROCID(b, c, v) \
+               SET_CONTEXT_FIELD(b, c, CONTEXTIDR, PROCID, v)
+
+
+/* FSR */
+#define SET_TF(b, c, v)                 SET_CONTEXT_FIELD(b, c, FSR, TF, v)
+#define SET_AFF(b, c, v)        SET_CONTEXT_FIELD(b, c, FSR, AFF, v)
+#define SET_APF(b, c, v)        SET_CONTEXT_FIELD(b, c, FSR, APF, v)
+#define SET_TLBMF(b, c, v)      SET_CONTEXT_FIELD(b, c, FSR, TLBMF, v)
+#define SET_HTWDEEF(b, c, v)    SET_CONTEXT_FIELD(b, c, FSR, HTWDEEF, v)
+#define SET_HTWSEEF(b, c, v)    SET_CONTEXT_FIELD(b, c, FSR, HTWSEEF, v)
+#define SET_MHF(b, c, v)        SET_CONTEXT_FIELD(b, c, FSR, MHF, v)
+#define SET_SL(b, c, v)                 SET_CONTEXT_FIELD(b, c, FSR, SL, v)
+#define SET_SS(b, c, v)                 SET_CONTEXT_FIELD(b, c, FSR, SS, v)
+#define SET_MULTI(b, c, v)      SET_CONTEXT_FIELD(b, c, FSR, MULTI, v)
+
+
+/* FSYNR0 */
+#define SET_AMID(b, c, v)       SET_CONTEXT_FIELD(b, c, FSYNR0, AMID, v)
+#define SET_APID(b, c, v)       SET_CONTEXT_FIELD(b, c, FSYNR0, APID, v)
+#define SET_ABID(b, c, v)       SET_CONTEXT_FIELD(b, c, FSYNR0, ABID, v)
+#define SET_ATID(b, c, v)       SET_CONTEXT_FIELD(b, c, FSYNR0, ATID, v)
+
+
+/* FSYNR1 */
+#define SET_AMEMTYPE(b, c, v)   SET_CONTEXT_FIELD(b, c, FSYNR1, AMEMTYPE, v)
+#define SET_ASHARED(b, c, v)    SET_CONTEXT_FIELD(b, c, FSYNR1, ASHARED, v)
+#define SET_AINNERSHARED(b, c, v)  \
+                               SET_CONTEXT_FIELD(b, c, FSYNR1, AINNERSHARED, v)
+#define SET_APRIV(b, c, v)      SET_CONTEXT_FIELD(b, c, FSYNR1, APRIV, v)
+#define SET_APROTNS(b, c, v)    SET_CONTEXT_FIELD(b, c, FSYNR1, APROTNS, v)
+#define SET_AINST(b, c, v)      SET_CONTEXT_FIELD(b, c, FSYNR1, AINST, v)
+#define SET_AWRITE(b, c, v)     SET_CONTEXT_FIELD(b, c, FSYNR1, AWRITE, v)
+#define SET_ABURST(b, c, v)     SET_CONTEXT_FIELD(b, c, FSYNR1, ABURST, v)
+#define SET_ALEN(b, c, v)       SET_CONTEXT_FIELD(b, c, FSYNR1, ALEN, v)
+#define SET_FSYNR1_ASIZE(b, c, v) \
+                               SET_CONTEXT_FIELD(b, c, FSYNR1, FSYNR1_ASIZE, v)
+#define SET_ALOCK(b, c, v)      SET_CONTEXT_FIELD(b, c, FSYNR1, ALOCK, v)
+#define SET_AFULL(b, c, v)      SET_CONTEXT_FIELD(b, c, FSYNR1, AFULL, v)
+
+
+/* NMRR */
+#define SET_ICPC0(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, ICPC0, v)
+#define SET_ICPC1(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, ICPC1, v)
+#define SET_ICPC2(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, ICPC2, v)
+#define SET_ICPC3(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, ICPC3, v)
+#define SET_ICPC4(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, ICPC4, v)
+#define SET_ICPC5(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, ICPC5, v)
+#define SET_ICPC6(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, ICPC6, v)
+#define SET_ICPC7(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, ICPC7, v)
+#define SET_OCPC0(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, OCPC0, v)
+#define SET_OCPC1(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, OCPC1, v)
+#define SET_OCPC2(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, OCPC2, v)
+#define SET_OCPC3(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, OCPC3, v)
+#define SET_OCPC4(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, OCPC4, v)
+#define SET_OCPC5(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, OCPC5, v)
+#define SET_OCPC6(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, OCPC6, v)
+#define SET_OCPC7(b, c, v)      SET_CONTEXT_FIELD(b, c, NMRR, OCPC7, v)
+
+
+/* PAR */
+#define SET_FAULT(b, c, v)      SET_CONTEXT_FIELD(b, c, PAR, FAULT, v)
+
+#define SET_FAULT_TF(b, c, v)   SET_CONTEXT_FIELD(b, c, PAR, FAULT_TF, v)
+#define SET_FAULT_AFF(b, c, v)  SET_CONTEXT_FIELD(b, c, PAR, FAULT_AFF, v)
+#define SET_FAULT_APF(b, c, v)  SET_CONTEXT_FIELD(b, c, PAR, FAULT_APF, v)
+#define SET_FAULT_TLBMF(b, c, v) SET_CONTEXT_FIELD(b, c, PAR, FAULT_TLBMF, v)
+#define SET_FAULT_HTWDEEF(b, c, v) \
+                               SET_CONTEXT_FIELD(b, c, PAR, FAULT_HTWDEEF, v)
+#define SET_FAULT_HTWSEEF(b, c, v) \
+                               SET_CONTEXT_FIELD(b, c, PAR, FAULT_HTWSEEF, v)
+#define SET_FAULT_MHF(b, c, v)  SET_CONTEXT_FIELD(b, c, PAR, FAULT_MHF, v)
+#define SET_FAULT_SL(b, c, v)   SET_CONTEXT_FIELD(b, c, PAR, FAULT_SL, v)
+#define SET_FAULT_SS(b, c, v)   SET_CONTEXT_FIELD(b, c, PAR, FAULT_SS, v)
+
+#define SET_NOFAULT_SS(b, c, v)         SET_CONTEXT_FIELD(b, c, PAR, NOFAULT_SS, v)
+#define SET_NOFAULT_MT(b, c, v)         SET_CONTEXT_FIELD(b, c, PAR, NOFAULT_MT, v)
+#define SET_NOFAULT_SH(b, c, v)         SET_CONTEXT_FIELD(b, c, PAR, NOFAULT_SH, v)
+#define SET_NOFAULT_NS(b, c, v)         SET_CONTEXT_FIELD(b, c, PAR, NOFAULT_NS, v)
+#define SET_NOFAULT_NOS(b, c, v) SET_CONTEXT_FIELD(b, c, PAR, NOFAULT_NOS, v)
+#define SET_NPFAULT_PA(b, c, v)         SET_CONTEXT_FIELD(b, c, PAR, NPFAULT_PA, v)
+
+
+/* PRRR */
+#define SET_MTC0(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, MTC0, v)
+#define SET_MTC1(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, MTC1, v)
+#define SET_MTC2(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, MTC2, v)
+#define SET_MTC3(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, MTC3, v)
+#define SET_MTC4(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, MTC4, v)
+#define SET_MTC5(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, MTC5, v)
+#define SET_MTC6(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, MTC6, v)
+#define SET_MTC7(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, MTC7, v)
+#define SET_SHDSH0(b, c, v)     SET_CONTEXT_FIELD(b, c, PRRR, SHDSH0, v)
+#define SET_SHDSH1(b, c, v)     SET_CONTEXT_FIELD(b, c, PRRR, SHDSH1, v)
+#define SET_SHNMSH0(b, c, v)    SET_CONTEXT_FIELD(b, c, PRRR, SHNMSH0, v)
+#define SET_SHNMSH1(b, c, v)     SET_CONTEXT_FIELD(b, c, PRRR, SHNMSH1, v)
+#define SET_NOS0(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, NOS0, v)
+#define SET_NOS1(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, NOS1, v)
+#define SET_NOS2(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, NOS2, v)
+#define SET_NOS3(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, NOS3, v)
+#define SET_NOS4(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, NOS4, v)
+#define SET_NOS5(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, NOS5, v)
+#define SET_NOS6(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, NOS6, v)
+#define SET_NOS7(b, c, v)       SET_CONTEXT_FIELD(b, c, PRRR, NOS7, v)
+
+
+/* RESUME */
+#define SET_TNR(b, c, v)        SET_CONTEXT_FIELD(b, c, RESUME, TNR, v)
+
+
+/* SCTLR */
+#define SET_M(b, c, v)          SET_CONTEXT_FIELD(b, c, SCTLR, M, v)
+#define SET_TRE(b, c, v)        SET_CONTEXT_FIELD(b, c, SCTLR, TRE, v)
+#define SET_AFE(b, c, v)        SET_CONTEXT_FIELD(b, c, SCTLR, AFE, v)
+#define SET_HAF(b, c, v)        SET_CONTEXT_FIELD(b, c, SCTLR, HAF, v)
+#define SET_BE(b, c, v)                 SET_CONTEXT_FIELD(b, c, SCTLR, BE, v)
+#define SET_AFFD(b, c, v)       SET_CONTEXT_FIELD(b, c, SCTLR, AFFD, v)
+
+
+/* TLBLKCR */
+#define SET_LKE(b, c, v)          SET_CONTEXT_FIELD(b, c, TLBLKCR, LKE, v)
+#define SET_TLBLKCR_TLBIALLCFG(b, c, v) \
+                       SET_CONTEXT_FIELD(b, c, TLBLKCR, TLBLCKR_TLBIALLCFG, v)
+#define SET_TLBIASIDCFG(b, c, v) \
+                       SET_CONTEXT_FIELD(b, c, TLBLKCR, TLBIASIDCFG, v)
+#define SET_TLBIVAACFG(b, c, v)        SET_CONTEXT_FIELD(b, c, TLBLKCR, TLBIVAACFG, v)
+#define SET_FLOOR(b, c, v)     SET_CONTEXT_FIELD(b, c, TLBLKCR, FLOOR, v)
+#define SET_VICTIM(b, c, v)    SET_CONTEXT_FIELD(b, c, TLBLKCR, VICTIM, v)
+
+
+/* TTBCR */
+#define SET_N(b, c, v)          SET_CONTEXT_FIELD(b, c, TTBCR, N, v)
+#define SET_PD0(b, c, v)        SET_CONTEXT_FIELD(b, c, TTBCR, PD0, v)
+#define SET_PD1(b, c, v)        SET_CONTEXT_FIELD(b, c, TTBCR, PD1, v)
+
+
+/* TTBR0 */
+#define SET_TTBR0_IRGNH(b, c, v) SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_IRGNH, v)
+#define SET_TTBR0_SH(b, c, v)   SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_SH, v)
+#define SET_TTBR0_ORGN(b, c, v)         SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_ORGN, v)
+#define SET_TTBR0_NOS(b, c, v)  SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_NOS, v)
+#define SET_TTBR0_IRGNL(b, c, v) SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_IRGNL, v)
+#define SET_TTBR0_PA(b, c, v)   SET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_PA, v)
+
+
+/* TTBR1 */
+#define SET_TTBR1_IRGNH(b, c, v) SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_IRGNH, v)
+#define SET_TTBR1_SH(b, c, v)   SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_SH, v)
+#define SET_TTBR1_ORGN(b, c, v)         SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_ORGN, v)
+#define SET_TTBR1_NOS(b, c, v)  SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_NOS, v)
+#define SET_TTBR1_IRGNL(b, c, v) SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_IRGNL, v)
+#define SET_TTBR1_PA(b, c, v)   SET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_PA, v)
+
+
+/* V2PSR */
+#define SET_HIT(b, c, v)        SET_CONTEXT_FIELD(b, c, V2PSR, HIT, v)
+#define SET_INDEX(b, c, v)      SET_CONTEXT_FIELD(b, c, V2PSR, INDEX, v)
+
+
+/* V2Pxx UW UR PW PR */
+#define SET_V2PUW_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_INDEX, v)
+#define SET_V2PUW_VA(b, c, v)   SET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_VA, v)
+
+#define SET_V2PUR_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_INDEX, v)
+#define SET_V2PUR_VA(b, c, v)   SET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_VA, v)
+
+#define SET_V2PPW_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_INDEX, v)
+#define SET_V2PPW_VA(b, c, v)   SET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_VA, v)
+
+#define SET_V2PPR_INDEX(b, c, v) SET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_INDEX, v)
+#define SET_V2PPR_VA(b, c, v)   SET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_VA, v)
+
+
+/* Context Register getters */
+/* ACTLR */
+#define GET_CFERE(b, c)                GET_CONTEXT_FIELD(b, c, ACTLR, CFERE)
+#define GET_CFEIE(b, c)                GET_CONTEXT_FIELD(b, c, ACTLR, CFEIE)
+#define GET_PTSHCFG(b, c)       GET_CONTEXT_FIELD(b, c, ACTLR, PTSHCFG)
+#define GET_RCOSH(b, c)                GET_CONTEXT_FIELD(b, c, ACTLR, RCOSH)
+#define GET_RCISH(b, c)                GET_CONTEXT_FIELD(b, c, ACTLR, RCISH)
+#define GET_RCNSH(b, c)                GET_CONTEXT_FIELD(b, c, ACTLR, RCNSH)
+#define GET_PRIVCFG(b, c)       GET_CONTEXT_FIELD(b, c, ACTLR, PRIVCFG)
+#define GET_DNA(b, c)          GET_CONTEXT_FIELD(b, c, ACTLR, DNA)
+#define GET_DNLV2PA(b, c)       GET_CONTEXT_FIELD(b, c, ACTLR, DNLV2PA)
+#define GET_TLBMCFG(b, c)       GET_CONTEXT_FIELD(b, c, ACTLR, TLBMCFG)
+#define GET_CFCFG(b, c)                GET_CONTEXT_FIELD(b, c, ACTLR, CFCFG)
+#define GET_TIPCF(b, c)                GET_CONTEXT_FIELD(b, c, ACTLR, TIPCF)
+#define GET_V2PCFG(b, c)        GET_CONTEXT_FIELD(b, c, ACTLR, V2PCFG)
+#define GET_HUME(b, c)         GET_CONTEXT_FIELD(b, c, ACTLR, HUME)
+#define GET_PTMTCFG(b, c)       GET_CONTEXT_FIELD(b, c, ACTLR, PTMTCFG)
+#define GET_PTMEMTYPE(b, c)     GET_CONTEXT_FIELD(b, c, ACTLR, PTMEMTYPE)
+
+/* BFBCR */
+#define GET_BFBDFE(b, c)       GET_CONTEXT_FIELD(b, c, BFBCR, BFBDFE)
+#define GET_BFBSFE(b, c)       GET_CONTEXT_FIELD(b, c, BFBCR, BFBSFE)
+#define GET_SFVS(b, c)         GET_CONTEXT_FIELD(b, c, BFBCR, SFVS)
+#define GET_FLVIC(b, c)                GET_CONTEXT_FIELD(b, c, BFBCR, FLVIC)
+#define GET_SLVIC(b, c)                GET_CONTEXT_FIELD(b, c, BFBCR, SLVIC)
+
+
+/* CONTEXTIDR */
+#define GET_CONTEXTIDR_ASID(b, c) \
+                       GET_CONTEXT_FIELD(b, c, CONTEXTIDR, CONTEXTIDR_ASID)
+#define GET_CONTEXTIDR_PROCID(b, c) GET_CONTEXT_FIELD(b, c, CONTEXTIDR, PROCID)
+
+
+/* FSR */
+#define GET_TF(b, c)           GET_CONTEXT_FIELD(b, c, FSR, TF)
+#define GET_AFF(b, c)          GET_CONTEXT_FIELD(b, c, FSR, AFF)
+#define GET_APF(b, c)          GET_CONTEXT_FIELD(b, c, FSR, APF)
+#define GET_TLBMF(b, c)                GET_CONTEXT_FIELD(b, c, FSR, TLBMF)
+#define GET_HTWDEEF(b, c)      GET_CONTEXT_FIELD(b, c, FSR, HTWDEEF)
+#define GET_HTWSEEF(b, c)      GET_CONTEXT_FIELD(b, c, FSR, HTWSEEF)
+#define GET_MHF(b, c)          GET_CONTEXT_FIELD(b, c, FSR, MHF)
+#define GET_SL(b, c)           GET_CONTEXT_FIELD(b, c, FSR, SL)
+#define GET_SS(b, c)           GET_CONTEXT_FIELD(b, c, FSR, SS)
+#define GET_MULTI(b, c)                GET_CONTEXT_FIELD(b, c, FSR, MULTI)
+
+
+/* FSYNR0 */
+#define GET_AMID(b, c)         GET_CONTEXT_FIELD(b, c, FSYNR0, AMID)
+#define GET_APID(b, c)         GET_CONTEXT_FIELD(b, c, FSYNR0, APID)
+#define GET_ABID(b, c)         GET_CONTEXT_FIELD(b, c, FSYNR0, ABID)
+#define GET_ATID(b, c)         GET_CONTEXT_FIELD(b, c, FSYNR0, ATID)
+
+
+/* FSYNR1 */
+#define GET_AMEMTYPE(b, c)     GET_CONTEXT_FIELD(b, c, FSYNR1, AMEMTYPE)
+#define GET_ASHARED(b, c)      GET_CONTEXT_FIELD(b, c, FSYNR1, ASHARED)
+#define GET_AINNERSHARED(b, c)  GET_CONTEXT_FIELD(b, c, FSYNR1, AINNERSHARED)
+#define GET_APRIV(b, c)                GET_CONTEXT_FIELD(b, c, FSYNR1, APRIV)
+#define GET_APROTNS(b, c)      GET_CONTEXT_FIELD(b, c, FSYNR1, APROTNS)
+#define GET_AINST(b, c)                GET_CONTEXT_FIELD(b, c, FSYNR1, AINST)
+#define GET_AWRITE(b, c)       GET_CONTEXT_FIELD(b, c, FSYNR1, AWRITE)
+#define GET_ABURST(b, c)       GET_CONTEXT_FIELD(b, c, FSYNR1, ABURST)
+#define GET_ALEN(b, c)         GET_CONTEXT_FIELD(b, c, FSYNR1, ALEN)
+#define GET_FSYNR1_ASIZE(b, c) GET_CONTEXT_FIELD(b, c, FSYNR1, FSYNR1_ASIZE)
+#define GET_ALOCK(b, c)                GET_CONTEXT_FIELD(b, c, FSYNR1, ALOCK)
+#define GET_AFULL(b, c)                GET_CONTEXT_FIELD(b, c, FSYNR1, AFULL)
+
+
+/* NMRR */
+#define GET_ICPC0(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, ICPC0)
+#define GET_ICPC1(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, ICPC1)
+#define GET_ICPC2(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, ICPC2)
+#define GET_ICPC3(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, ICPC3)
+#define GET_ICPC4(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, ICPC4)
+#define GET_ICPC5(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, ICPC5)
+#define GET_ICPC6(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, ICPC6)
+#define GET_ICPC7(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, ICPC7)
+#define GET_OCPC0(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, OCPC0)
+#define GET_OCPC1(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, OCPC1)
+#define GET_OCPC2(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, OCPC2)
+#define GET_OCPC3(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, OCPC3)
+#define GET_OCPC4(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, OCPC4)
+#define GET_OCPC5(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, OCPC5)
+#define GET_OCPC6(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, OCPC6)
+#define GET_OCPC7(b, c)                GET_CONTEXT_FIELD(b, c, NMRR, OCPC7)
+
+
+/* PAR */
+#define GET_FAULT(b, c)                GET_CONTEXT_FIELD(b, c, PAR, FAULT)
+
+#define GET_FAULT_TF(b, c)     GET_CONTEXT_FIELD(b, c, PAR, FAULT_TF)
+#define GET_FAULT_AFF(b, c)    GET_CONTEXT_FIELD(b, c, PAR, FAULT_AFF)
+#define GET_FAULT_APF(b, c)    GET_CONTEXT_FIELD(b, c, PAR, FAULT_APF)
+#define GET_FAULT_TLBMF(b, c)   GET_CONTEXT_FIELD(b, c, PAR, FAULT_TLBMF)
+#define GET_FAULT_HTWDEEF(b, c) GET_CONTEXT_FIELD(b, c, PAR, FAULT_HTWDEEF)
+#define GET_FAULT_HTWSEEF(b, c) GET_CONTEXT_FIELD(b, c, PAR, FAULT_HTWSEEF)
+#define GET_FAULT_MHF(b, c)    GET_CONTEXT_FIELD(b, c, PAR, FAULT_MHF)
+#define GET_FAULT_SL(b, c)     GET_CONTEXT_FIELD(b, c, PAR, FAULT_SL)
+#define GET_FAULT_SS(b, c)     GET_CONTEXT_FIELD(b, c, PAR, FAULT_SS)
+
+#define GET_NOFAULT_SS(b, c)   GET_CONTEXT_FIELD(b, c, PAR, PAR_NOFAULT_SS)
+#define GET_NOFAULT_MT(b, c)   GET_CONTEXT_FIELD(b, c, PAR, PAR_NOFAULT_MT)
+#define GET_NOFAULT_SH(b, c)   GET_CONTEXT_FIELD(b, c, PAR, PAR_NOFAULT_SH)
+#define GET_NOFAULT_NS(b, c)   GET_CONTEXT_FIELD(b, c, PAR, PAR_NOFAULT_NS)
+#define GET_NOFAULT_NOS(b, c)   GET_CONTEXT_FIELD(b, c, PAR, PAR_NOFAULT_NOS)
+#define GET_NPFAULT_PA(b, c)   GET_CONTEXT_FIELD(b, c, PAR, PAR_NPFAULT_PA)
+
+
+/* PRRR */
+#define GET_MTC0(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, MTC0)
+#define GET_MTC1(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, MTC1)
+#define GET_MTC2(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, MTC2)
+#define GET_MTC3(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, MTC3)
+#define GET_MTC4(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, MTC4)
+#define GET_MTC5(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, MTC5)
+#define GET_MTC6(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, MTC6)
+#define GET_MTC7(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, MTC7)
+#define GET_SHDSH0(b, c)       GET_CONTEXT_FIELD(b, c, PRRR, SHDSH0)
+#define GET_SHDSH1(b, c)       GET_CONTEXT_FIELD(b, c, PRRR, SHDSH1)
+#define GET_SHNMSH0(b, c)      GET_CONTEXT_FIELD(b, c, PRRR, SHNMSH0)
+#define GET_SHNMSH1(b, c)      GET_CONTEXT_FIELD(b, c, PRRR, SHNMSH1)
+#define GET_NOS0(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, NOS0)
+#define GET_NOS1(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, NOS1)
+#define GET_NOS2(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, NOS2)
+#define GET_NOS3(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, NOS3)
+#define GET_NOS4(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, NOS4)
+#define GET_NOS5(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, NOS5)
+#define GET_NOS6(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, NOS6)
+#define GET_NOS7(b, c)         GET_CONTEXT_FIELD(b, c, PRRR, NOS7)
+
+
+/* RESUME */
+#define GET_TNR(b, c)          GET_CONTEXT_FIELD(b, c, RESUME, TNR)
+
+
+/* SCTLR */
+#define GET_M(b, c)            GET_CONTEXT_FIELD(b, c, SCTLR, M)
+#define GET_TRE(b, c)          GET_CONTEXT_FIELD(b, c, SCTLR, TRE)
+#define GET_AFE(b, c)          GET_CONTEXT_FIELD(b, c, SCTLR, AFE)
+#define GET_HAF(b, c)          GET_CONTEXT_FIELD(b, c, SCTLR, HAF)
+#define GET_BE(b, c)           GET_CONTEXT_FIELD(b, c, SCTLR, BE)
+#define GET_AFFD(b, c)         GET_CONTEXT_FIELD(b, c, SCTLR, AFFD)
+
+
+/* TLBLKCR */
+#define GET_LKE(b, c)          GET_CONTEXT_FIELD(b, c, TLBLKCR, LKE)
+#define GET_TLBLCKR_TLBIALLCFG(b, c) \
+                       GET_CONTEXT_FIELD(b, c, TLBLKCR, TLBLCKR_TLBIALLCFG)
+#define GET_TLBIASIDCFG(b, c)   GET_CONTEXT_FIELD(b, c, TLBLKCR, TLBIASIDCFG)
+#define GET_TLBIVAACFG(b, c)   GET_CONTEXT_FIELD(b, c, TLBLKCR, TLBIVAACFG)
+#define GET_FLOOR(b, c)                GET_CONTEXT_FIELD(b, c, TLBLKCR, FLOOR)
+#define GET_VICTIM(b, c)       GET_CONTEXT_FIELD(b, c, TLBLKCR, VICTIM)
+
+
+/* TTBCR */
+#define GET_N(b, c)            GET_CONTEXT_FIELD(b, c, TTBCR, N)
+#define GET_PD0(b, c)          GET_CONTEXT_FIELD(b, c, TTBCR, PD0)
+#define GET_PD1(b, c)          GET_CONTEXT_FIELD(b, c, TTBCR, PD1)
+
+
+/* TTBR0 */
+#define GET_TTBR0_IRGNH(b, c)  GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_IRGNH)
+#define GET_TTBR0_SH(b, c)     GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_SH)
+#define GET_TTBR0_ORGN(b, c)   GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_ORGN)
+#define GET_TTBR0_NOS(b, c)    GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_NOS)
+#define GET_TTBR0_IRGNL(b, c)  GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_IRGNL)
+#define GET_TTBR0_PA(b, c)     GET_CONTEXT_FIELD(b, c, TTBR0, TTBR0_PA)
+
+
+/* TTBR1 */
+#define GET_TTBR1_IRGNH(b, c)  GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_IRGNH)
+#define GET_TTBR1_SH(b, c)     GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_SH)
+#define GET_TTBR1_ORGN(b, c)   GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_ORGN)
+#define GET_TTBR1_NOS(b, c)    GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_NOS)
+#define GET_TTBR1_IRGNL(b, c)  GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_IRGNL)
+#define GET_TTBR1_PA(b, c)     GET_CONTEXT_FIELD(b, c, TTBR1, TTBR1_PA)
+
+
+/* V2PSR */
+#define GET_HIT(b, c)          GET_CONTEXT_FIELD(b, c, V2PSR, HIT)
+#define GET_INDEX(b, c)                GET_CONTEXT_FIELD(b, c, V2PSR, INDEX)
+
+
+/* V2Pxx UW UR PW PR */
+#define GET_V2PUW_INDEX(b, c)  GET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_INDEX)
+#define GET_V2PUW_VA(b, c)     GET_CONTEXT_FIELD(b, c, V2PUW, V2Pxx_VA)
+
+#define GET_V2PUR_INDEX(b, c)  GET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_INDEX)
+#define GET_V2PUR_VA(b, c)     GET_CONTEXT_FIELD(b, c, V2PUR, V2Pxx_VA)
+
+#define GET_V2PPW_INDEX(b, c)  GET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_INDEX)
+#define GET_V2PPW_VA(b, c)     GET_CONTEXT_FIELD(b, c, V2PPW, V2Pxx_VA)
+
+#define GET_V2PPR_INDEX(b, c)  GET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_INDEX)
+#define GET_V2PPR_VA(b, c)     GET_CONTEXT_FIELD(b, c, V2PPR, V2Pxx_VA)
+
+
+/* Global Registers */
+#define M2VCBR_N       (0xFF000)
+#define CBACR_N                (0xFF800)
+#define TLBRSW         (0xFFE00)
+#define TLBTR0         (0xFFE80)
+#define TLBTR1         (0xFFE84)
+#define TLBTR2         (0xFFE88)
+#define TESTBUSCR      (0xFFE8C)
+#define GLOBAL_TLBIALL (0xFFF00)
+#define TLBIVMID       (0xFFF04)
+#define CR             (0xFFF80)
+#define EAR            (0xFFF84)
+#define ESR            (0xFFF88)
+#define ESRRESTORE     (0xFFF8C)
+#define ESYNR0         (0xFFF90)
+#define ESYNR1         (0xFFF94)
+#define REV            (0xFFFF4)
+#define IDR            (0xFFFF8)
+#define RPU_ACR                (0xFFFFC)
+
+
+/* Context Bank Registers */
+#define SCTLR          (0x000)
+#define ACTLR          (0x004)
+#define CONTEXTIDR     (0x008)
+#define TTBR0          (0x010)
+#define TTBR1          (0x014)
+#define TTBCR          (0x018)
+#define PAR            (0x01C)
+#define FSR            (0x020)
+#define FSRRESTORE     (0x024)
+#define FAR            (0x028)
+#define FSYNR0         (0x02C)
+#define FSYNR1         (0x030)
+#define PRRR           (0x034)
+#define NMRR           (0x038)
+#define TLBLCKR                (0x03C)
+#define V2PSR          (0x040)
+#define TLBFLPTER      (0x044)
+#define TLBSLPTER      (0x048)
+#define BFBCR          (0x04C)
+#define CTX_TLBIALL    (0x800)
+#define TLBIASID       (0x804)
+#define TLBIVA         (0x808)
+#define TLBIVAA                (0x80C)
+#define V2PPR          (0x810)
+#define V2PPW          (0x814)
+#define V2PUR          (0x818)
+#define V2PUW          (0x81C)
+#define RESUME         (0x820)
+
+
+/* Global Register Fields */
+/* CBACRn */
+#define RWVMID        (RWVMID_MASK       << RWVMID_SHIFT)
+#define RWE           (RWE_MASK          << RWE_SHIFT)
+#define RWGE          (RWGE_MASK         << RWGE_SHIFT)
+#define CBVMID        (CBVMID_MASK       << CBVMID_SHIFT)
+#define IRPTNDX       (IRPTNDX_MASK      << IRPTNDX_SHIFT)
+
+
+/* CR */
+#define RPUE          (RPUE_MASK          << RPUE_SHIFT)
+#define RPUERE        (RPUERE_MASK        << RPUERE_SHIFT)
+#define RPUEIE        (RPUEIE_MASK        << RPUEIE_SHIFT)
+#define DCDEE         (DCDEE_MASK         << DCDEE_SHIFT)
+#define CLIENTPD      (CLIENTPD_MASK      << CLIENTPD_SHIFT)
+#define STALLD        (STALLD_MASK        << STALLD_SHIFT)
+#define TLBLKCRWE     (TLBLKCRWE_MASK     << TLBLKCRWE_SHIFT)
+#define CR_TLBIALLCFG (CR_TLBIALLCFG_MASK << CR_TLBIALLCFG_SHIFT)
+#define TLBIVMIDCFG   (TLBIVMIDCFG_MASK   << TLBIVMIDCFG_SHIFT)
+#define CR_HUME       (CR_HUME_MASK       << CR_HUME_SHIFT)
+
+
+/* ESR */
+#define CFG           (CFG_MASK          << CFG_SHIFT)
+#define BYPASS        (BYPASS_MASK       << BYPASS_SHIFT)
+#define ESR_MULTI     (ESR_MULTI_MASK    << ESR_MULTI_SHIFT)
+
+
+/* ESYNR0 */
+#define ESYNR0_AMID   (ESYNR0_AMID_MASK  << ESYNR0_AMID_SHIFT)
+#define ESYNR0_APID   (ESYNR0_APID_MASK  << ESYNR0_APID_SHIFT)
+#define ESYNR0_ABID   (ESYNR0_ABID_MASK  << ESYNR0_ABID_SHIFT)
+#define ESYNR0_AVMID  (ESYNR0_AVMID_MASK << ESYNR0_AVMID_SHIFT)
+#define ESYNR0_ATID   (ESYNR0_ATID_MASK  << ESYNR0_ATID_SHIFT)
+
+
+/* ESYNR1 */
+#define ESYNR1_AMEMTYPE      (ESYNR1_AMEMTYPE_MASK    << ESYNR1_AMEMTYPE_SHIFT)
+#define ESYNR1_ASHARED       (ESYNR1_ASHARED_MASK     << ESYNR1_ASHARED_SHIFT)
+#define ESYNR1_AINNERSHARED  (ESYNR1_AINNERSHARED_MASK<< \
+                                               ESYNR1_AINNERSHARED_SHIFT)
+#define ESYNR1_APRIV         (ESYNR1_APRIV_MASK       << ESYNR1_APRIV_SHIFT)
+#define ESYNR1_APROTNS       (ESYNR1_APROTNS_MASK     << ESYNR1_APROTNS_SHIFT)
+#define ESYNR1_AINST         (ESYNR1_AINST_MASK       << ESYNR1_AINST_SHIFT)
+#define ESYNR1_AWRITE        (ESYNR1_AWRITE_MASK      << ESYNR1_AWRITE_SHIFT)
+#define ESYNR1_ABURST        (ESYNR1_ABURST_MASK      << ESYNR1_ABURST_SHIFT)
+#define ESYNR1_ALEN          (ESYNR1_ALEN_MASK        << ESYNR1_ALEN_SHIFT)
+#define ESYNR1_ASIZE         (ESYNR1_ASIZE_MASK       << ESYNR1_ASIZE_SHIFT)
+#define ESYNR1_ALOCK         (ESYNR1_ALOCK_MASK       << ESYNR1_ALOCK_SHIFT)
+#define ESYNR1_AOOO          (ESYNR1_AOOO_MASK        << ESYNR1_AOOO_SHIFT)
+#define ESYNR1_AFULL         (ESYNR1_AFULL_MASK       << ESYNR1_AFULL_SHIFT)
+#define ESYNR1_AC            (ESYNR1_AC_MASK          << ESYNR1_AC_SHIFT)
+#define ESYNR1_DCD           (ESYNR1_DCD_MASK         << ESYNR1_DCD_SHIFT)
+
+
+/* IDR */
+#define NM2VCBMT      (NM2VCBMT_MASK     << NM2VCBMT_SHIFT)
+#define HTW           (HTW_MASK          << HTW_SHIFT)
+#define HUM           (HUM_MASK          << HUM_SHIFT)
+#define TLBSIZE       (TLBSIZE_MASK      << TLBSIZE_SHIFT)
+#define NCB           (NCB_MASK          << NCB_SHIFT)
+#define NIRPT         (NIRPT_MASK        << NIRPT_SHIFT)
+
+
+/* M2VCBRn */
+#define VMID          (VMID_MASK         << VMID_SHIFT)
+#define CBNDX         (CBNDX_MASK        << CBNDX_SHIFT)
+#define BYPASSD       (BYPASSD_MASK      << BYPASSD_SHIFT)
+#define BPRCOSH       (BPRCOSH_MASK      << BPRCOSH_SHIFT)
+#define BPRCISH       (BPRCISH_MASK      << BPRCISH_SHIFT)
+#define BPRCNSH       (BPRCNSH_MASK      << BPRCNSH_SHIFT)
+#define BPSHCFG       (BPSHCFG_MASK      << BPSHCFG_SHIFT)
+#define NSCFG         (NSCFG_MASK        << NSCFG_SHIFT)
+#define BPMTCFG       (BPMTCFG_MASK      << BPMTCFG_SHIFT)
+#define BPMEMTYPE     (BPMEMTYPE_MASK    << BPMEMTYPE_SHIFT)
+
+
+/* REV */
+#define IDR_MINOR     (MINOR_MASK        << MINOR_SHIFT)
+#define IDR_MAJOR     (MAJOR_MASK        << MAJOR_SHIFT)
+
+
+/* TESTBUSCR */
+#define TBE           (TBE_MASK          << TBE_SHIFT)
+#define SPDMBE        (SPDMBE_MASK       << SPDMBE_SHIFT)
+#define WGSEL         (WGSEL_MASK        << WGSEL_SHIFT)
+#define TBLSEL        (TBLSEL_MASK       << TBLSEL_SHIFT)
+#define TBHSEL        (TBHSEL_MASK       << TBHSEL_SHIFT)
+#define SPDM0SEL      (SPDM0SEL_MASK     << SPDM0SEL_SHIFT)
+#define SPDM1SEL      (SPDM1SEL_MASK     << SPDM1SEL_SHIFT)
+#define SPDM2SEL      (SPDM2SEL_MASK     << SPDM2SEL_SHIFT)
+#define SPDM3SEL      (SPDM3SEL_MASK     << SPDM3SEL_SHIFT)
+
+
+/* TLBIVMID */
+#define TLBIVMID_VMID (TLBIVMID_VMID_MASK << TLBIVMID_VMID_SHIFT)
+
+
+/* TLBRSW */
+#define TLBRSW_INDEX  (TLBRSW_INDEX_MASK << TLBRSW_INDEX_SHIFT)
+#define TLBBFBS       (TLBBFBS_MASK      << TLBBFBS_SHIFT)
+
+
+/* TLBTR0 */
+#define PR            (PR_MASK           << PR_SHIFT)
+#define PW            (PW_MASK           << PW_SHIFT)
+#define UR            (UR_MASK           << UR_SHIFT)
+#define UW            (UW_MASK           << UW_SHIFT)
+#define XN            (XN_MASK           << XN_SHIFT)
+#define NSDESC        (NSDESC_MASK       << NSDESC_SHIFT)
+#define ISH           (ISH_MASK          << ISH_SHIFT)
+#define SH            (SH_MASK           << SH_SHIFT)
+#define MT            (MT_MASK           << MT_SHIFT)
+#define DPSIZR        (DPSIZR_MASK       << DPSIZR_SHIFT)
+#define DPSIZC        (DPSIZC_MASK       << DPSIZC_SHIFT)
+
+
+/* TLBTR1 */
+#define TLBTR1_VMID   (TLBTR1_VMID_MASK  << TLBTR1_VMID_SHIFT)
+#define TLBTR1_PA     (TLBTR1_PA_MASK    << TLBTR1_PA_SHIFT)
+
+
+/* TLBTR2 */
+#define TLBTR2_ASID   (TLBTR2_ASID_MASK  << TLBTR2_ASID_SHIFT)
+#define TLBTR2_V      (TLBTR2_V_MASK     << TLBTR2_V_SHIFT)
+#define TLBTR2_NSTID  (TLBTR2_NSTID_MASK << TLBTR2_NSTID_SHIFT)
+#define TLBTR2_NV     (TLBTR2_NV_MASK    << TLBTR2_NV_SHIFT)
+#define TLBTR2_VA     (TLBTR2_VA_MASK    << TLBTR2_VA_SHIFT)
+
+
+/* Context Register Fields */
+/* ACTLR */
+#define CFERE              (CFERE_MASK              << CFERE_SHIFT)
+#define CFEIE              (CFEIE_MASK              << CFEIE_SHIFT)
+#define PTSHCFG            (PTSHCFG_MASK            << PTSHCFG_SHIFT)
+#define RCOSH              (RCOSH_MASK              << RCOSH_SHIFT)
+#define RCISH              (RCISH_MASK              << RCISH_SHIFT)
+#define RCNSH              (RCNSH_MASK              << RCNSH_SHIFT)
+#define PRIVCFG            (PRIVCFG_MASK            << PRIVCFG_SHIFT)
+#define DNA                (DNA_MASK                << DNA_SHIFT)
+#define DNLV2PA            (DNLV2PA_MASK            << DNLV2PA_SHIFT)
+#define TLBMCFG            (TLBMCFG_MASK            << TLBMCFG_SHIFT)
+#define CFCFG              (CFCFG_MASK              << CFCFG_SHIFT)
+#define TIPCF              (TIPCF_MASK              << TIPCF_SHIFT)
+#define V2PCFG             (V2PCFG_MASK             << V2PCFG_SHIFT)
+#define HUME               (HUME_MASK               << HUME_SHIFT)
+#define PTMTCFG            (PTMTCFG_MASK            << PTMTCFG_SHIFT)
+#define PTMEMTYPE          (PTMEMTYPE_MASK          << PTMEMTYPE_SHIFT)
+
+
+/* BFBCR */
+#define BFBDFE             (BFBDFE_MASK             << BFBDFE_SHIFT)
+#define BFBSFE             (BFBSFE_MASK             << BFBSFE_SHIFT)
+#define SFVS               (SFVS_MASK               << SFVS_SHIFT)
+#define FLVIC              (FLVIC_MASK              << FLVIC_SHIFT)
+#define SLVIC              (SLVIC_MASK              << SLVIC_SHIFT)
+
+
+/* CONTEXTIDR */
+#define CONTEXTIDR_ASID    (CONTEXTIDR_ASID_MASK    << CONTEXTIDR_ASID_SHIFT)
+#define PROCID             (PROCID_MASK             << PROCID_SHIFT)
+
+
+/* FSR */
+#define TF                 (TF_MASK                 << TF_SHIFT)
+#define AFF                (AFF_MASK                << AFF_SHIFT)
+#define APF                (APF_MASK                << APF_SHIFT)
+#define TLBMF              (TLBMF_MASK              << TLBMF_SHIFT)
+#define HTWDEEF            (HTWDEEF_MASK            << HTWDEEF_SHIFT)
+#define HTWSEEF            (HTWSEEF_MASK            << HTWSEEF_SHIFT)
+#define MHF                (MHF_MASK                << MHF_SHIFT)
+#define SL                 (SL_MASK                 << SL_SHIFT)
+#define SS                 (SS_MASK                 << SS_SHIFT)
+#define MULTI              (MULTI_MASK              << MULTI_SHIFT)
+
+
+/* FSYNR0 */
+#define AMID               (AMID_MASK               << AMID_SHIFT)
+#define APID               (APID_MASK               << APID_SHIFT)
+#define ABID               (ABID_MASK               << ABID_SHIFT)
+#define ATID               (ATID_MASK               << ATID_SHIFT)
+
+
+/* FSYNR1 */
+#define AMEMTYPE           (AMEMTYPE_MASK           << AMEMTYPE_SHIFT)
+#define ASHARED            (ASHARED_MASK            << ASHARED_SHIFT)
+#define AINNERSHARED       (AINNERSHARED_MASK       << AINNERSHARED_SHIFT)
+#define APRIV              (APRIV_MASK              << APRIV_SHIFT)
+#define APROTNS            (APROTNS_MASK            << APROTNS_SHIFT)
+#define AINST              (AINST_MASK              << AINST_SHIFT)
+#define AWRITE             (AWRITE_MASK             << AWRITE_SHIFT)
+#define ABURST             (ABURST_MASK             << ABURST_SHIFT)
+#define ALEN               (ALEN_MASK               << ALEN_SHIFT)
+#define FSYNR1_ASIZE       (FSYNR1_ASIZE_MASK       << FSYNR1_ASIZE_SHIFT)
+#define ALOCK              (ALOCK_MASK              << ALOCK_SHIFT)
+#define AFULL              (AFULL_MASK              << AFULL_SHIFT)
+
+
+/* NMRR */
+#define ICPC0              (ICPC0_MASK              << ICPC0_SHIFT)
+#define ICPC1              (ICPC1_MASK              << ICPC1_SHIFT)
+#define ICPC2              (ICPC2_MASK              << ICPC2_SHIFT)
+#define ICPC3              (ICPC3_MASK              << ICPC3_SHIFT)
+#define ICPC4              (ICPC4_MASK              << ICPC4_SHIFT)
+#define ICPC5              (ICPC5_MASK              << ICPC5_SHIFT)
+#define ICPC6              (ICPC6_MASK              << ICPC6_SHIFT)
+#define ICPC7              (ICPC7_MASK              << ICPC7_SHIFT)
+#define OCPC0              (OCPC0_MASK              << OCPC0_SHIFT)
+#define OCPC1              (OCPC1_MASK              << OCPC1_SHIFT)
+#define OCPC2              (OCPC2_MASK              << OCPC2_SHIFT)
+#define OCPC3              (OCPC3_MASK              << OCPC3_SHIFT)
+#define OCPC4              (OCPC4_MASK              << OCPC4_SHIFT)
+#define OCPC5              (OCPC5_MASK              << OCPC5_SHIFT)
+#define OCPC6              (OCPC6_MASK              << OCPC6_SHIFT)
+#define OCPC7              (OCPC7_MASK              << OCPC7_SHIFT)
+
+
+/* PAR */
+#define FAULT              (FAULT_MASK              << FAULT_SHIFT)
+/* If a fault is present, these are the
+same as the fault fields in the FAR */
+#define FAULT_TF           (FAULT_TF_MASK           << FAULT_TF_SHIFT)
+#define FAULT_AFF          (FAULT_AFF_MASK          << FAULT_AFF_SHIFT)
+#define FAULT_APF          (FAULT_APF_MASK          << FAULT_APF_SHIFT)
+#define FAULT_TLBMF        (FAULT_TLBMF_MASK        << FAULT_TLBMF_SHIFT)
+#define FAULT_HTWDEEF      (FAULT_HTWDEEF_MASK      << FAULT_HTWDEEF_SHIFT)
+#define FAULT_HTWSEEF      (FAULT_HTWSEEF_MASK      << FAULT_HTWSEEF_SHIFT)
+#define FAULT_MHF          (FAULT_MHF_MASK          << FAULT_MHF_SHIFT)
+#define FAULT_SL           (FAULT_SL_MASK           << FAULT_SL_SHIFT)
+#define FAULT_SS           (FAULT_SS_MASK           << FAULT_SS_SHIFT)
+
+/* If NO fault is present, the following fields are in effect */
+/* (FAULT remains as before) */
+#define PAR_NOFAULT_SS     (PAR_NOFAULT_SS_MASK     << PAR_NOFAULT_SS_SHIFT)
+#define PAR_NOFAULT_MT     (PAR_NOFAULT_MT_MASK     << PAR_NOFAULT_MT_SHIFT)
+#define PAR_NOFAULT_SH     (PAR_NOFAULT_SH_MASK     << PAR_NOFAULT_SH_SHIFT)
+#define PAR_NOFAULT_NS     (PAR_NOFAULT_NS_MASK     << PAR_NOFAULT_NS_SHIFT)
+#define PAR_NOFAULT_NOS    (PAR_NOFAULT_NOS_MASK    << PAR_NOFAULT_NOS_SHIFT)
+#define PAR_NPFAULT_PA     (PAR_NPFAULT_PA_MASK     << PAR_NPFAULT_PA_SHIFT)
+
+
+/* PRRR */
+#define MTC0               (MTC0_MASK               << MTC0_SHIFT)
+#define MTC1               (MTC1_MASK               << MTC1_SHIFT)
+#define MTC2               (MTC2_MASK               << MTC2_SHIFT)
+#define MTC3               (MTC3_MASK               << MTC3_SHIFT)
+#define MTC4               (MTC4_MASK               << MTC4_SHIFT)
+#define MTC5               (MTC5_MASK               << MTC5_SHIFT)
+#define MTC6               (MTC6_MASK               << MTC6_SHIFT)
+#define MTC7               (MTC7_MASK               << MTC7_SHIFT)
+#define SHDSH0             (SHDSH0_MASK             << SHDSH0_SHIFT)
+#define SHDSH1             (SHDSH1_MASK             << SHDSH1_SHIFT)
+#define SHNMSH0            (SHNMSH0_MASK            << SHNMSH0_SHIFT)
+#define SHNMSH1            (SHNMSH1_MASK            << SHNMSH1_SHIFT)
+#define NOS0               (NOS0_MASK               << NOS0_SHIFT)
+#define NOS1               (NOS1_MASK               << NOS1_SHIFT)
+#define NOS2               (NOS2_MASK               << NOS2_SHIFT)
+#define NOS3               (NOS3_MASK               << NOS3_SHIFT)
+#define NOS4               (NOS4_MASK               << NOS4_SHIFT)
+#define NOS5               (NOS5_MASK               << NOS5_SHIFT)
+#define NOS6               (NOS6_MASK               << NOS6_SHIFT)
+#define NOS7               (NOS7_MASK               << NOS7_SHIFT)
+
+
+/* RESUME */
+#define TNR                (TNR_MASK                << TNR_SHIFT)
+
+
+/* SCTLR */
+#define M                  (M_MASK                  << M_SHIFT)
+#define TRE                (TRE_MASK                << TRE_SHIFT)
+#define AFE                (AFE_MASK                << AFE_SHIFT)
+#define HAF                (HAF_MASK                << HAF_SHIFT)
+#define BE                 (BE_MASK                 << BE_SHIFT)
+#define AFFD               (AFFD_MASK               << AFFD_SHIFT)
+
+
+/* TLBIASID */
+#define TLBIASID_ASID      (TLBIASID_ASID_MASK      << TLBIASID_ASID_SHIFT)
+
+
+/* TLBIVA */
+#define TLBIVA_ASID        (TLBIVA_ASID_MASK        << TLBIVA_ASID_SHIFT)
+#define TLBIVA_VA          (TLBIVA_VA_MASK          << TLBIVA_VA_SHIFT)
+
+
+/* TLBIVAA */
+#define TLBIVAA_VA         (TLBIVAA_VA_MASK         << TLBIVAA_VA_SHIFT)
+
+
+/* TLBLCKR */
+#define LKE                (LKE_MASK                << LKE_SHIFT)
+#define TLBLCKR_TLBIALLCFG (TLBLCKR_TLBIALLCFG_MASK<<TLBLCKR_TLBIALLCFG_SHIFT)
+#define TLBIASIDCFG        (TLBIASIDCFG_MASK        << TLBIASIDCFG_SHIFT)
+#define TLBIVAACFG         (TLBIVAACFG_MASK         << TLBIVAACFG_SHIFT)
+#define FLOOR              (FLOOR_MASK              << FLOOR_SHIFT)
+#define VICTIM             (VICTIM_MASK             << VICTIM_SHIFT)
+
+
+/* TTBCR */
+#define N                  (N_MASK                  << N_SHIFT)
+#define PD0                (PD0_MASK                << PD0_SHIFT)
+#define PD1                (PD1_MASK                << PD1_SHIFT)
+
+
+/* TTBR0 */
+#define TTBR0_IRGNH        (TTBR0_IRGNH_MASK        << TTBR0_IRGNH_SHIFT)
+#define TTBR0_SH           (TTBR0_SH_MASK           << TTBR0_SH_SHIFT)
+#define TTBR0_ORGN         (TTBR0_ORGN_MASK         << TTBR0_ORGN_SHIFT)
+#define TTBR0_NOS          (TTBR0_NOS_MASK          << TTBR0_NOS_SHIFT)
+#define TTBR0_IRGNL        (TTBR0_IRGNL_MASK        << TTBR0_IRGNL_SHIFT)
+#define TTBR0_PA           (TTBR0_PA_MASK           << TTBR0_PA_SHIFT)
+
+
+/* TTBR1 */
+#define TTBR1_IRGNH        (TTBR1_IRGNH_MASK        << TTBR1_IRGNH_SHIFT)
+#define TTBR1_SH           (TTBR1_SH_MASK           << TTBR1_SH_SHIFT)
+#define TTBR1_ORGN         (TTBR1_ORGN_MASK         << TTBR1_ORGN_SHIFT)
+#define TTBR1_NOS          (TTBR1_NOS_MASK          << TTBR1_NOS_SHIFT)
+#define TTBR1_IRGNL        (TTBR1_IRGNL_MASK        << TTBR1_IRGNL_SHIFT)
+#define TTBR1_PA           (TTBR1_PA_MASK           << TTBR1_PA_SHIFT)
+
+
+/* V2PSR */
+#define HIT                (HIT_MASK                << HIT_SHIFT)
+#define INDEX              (INDEX_MASK              << INDEX_SHIFT)
+
+
+/* V2Pxx */
+#define V2Pxx_INDEX        (V2Pxx_INDEX_MASK        << V2Pxx_INDEX_SHIFT)
+#define V2Pxx_VA           (V2Pxx_VA_MASK           << V2Pxx_VA_SHIFT)
+
+
+/* Global Register Masks */
+/* CBACRn */
+#define RWVMID_MASK               0x1F
+#define RWE_MASK                  0x01
+#define RWGE_MASK                 0x01
+#define CBVMID_MASK               0x1F
+#define IRPTNDX_MASK              0xFF
+
+
+/* CR */
+#define RPUE_MASK                 0x01
+#define RPUERE_MASK               0x01
+#define RPUEIE_MASK               0x01
+#define DCDEE_MASK                0x01
+#define CLIENTPD_MASK             0x01
+#define STALLD_MASK               0x01
+#define TLBLKCRWE_MASK            0x01
+#define CR_TLBIALLCFG_MASK        0x01
+#define TLBIVMIDCFG_MASK          0x01
+#define CR_HUME_MASK              0x01
+
+
+/* ESR */
+#define CFG_MASK                  0x01
+#define BYPASS_MASK               0x01
+#define ESR_MULTI_MASK            0x01
+
+
+/* ESYNR0 */
+#define ESYNR0_AMID_MASK          0xFF
+#define ESYNR0_APID_MASK          0x1F
+#define ESYNR0_ABID_MASK          0x07
+#define ESYNR0_AVMID_MASK         0x1F
+#define ESYNR0_ATID_MASK          0xFF
+
+
+/* ESYNR1 */
+#define ESYNR1_AMEMTYPE_MASK             0x07
+#define ESYNR1_ASHARED_MASK              0x01
+#define ESYNR1_AINNERSHARED_MASK         0x01
+#define ESYNR1_APRIV_MASK                0x01
+#define ESYNR1_APROTNS_MASK              0x01
+#define ESYNR1_AINST_MASK                0x01
+#define ESYNR1_AWRITE_MASK               0x01
+#define ESYNR1_ABURST_MASK               0x01
+#define ESYNR1_ALEN_MASK                 0x0F
+#define ESYNR1_ASIZE_MASK                0x01
+#define ESYNR1_ALOCK_MASK                0x03
+#define ESYNR1_AOOO_MASK                 0x01
+#define ESYNR1_AFULL_MASK                0x01
+#define ESYNR1_AC_MASK                   0x01
+#define ESYNR1_DCD_MASK                  0x01
+
+
+/* IDR */
+#define NM2VCBMT_MASK             0x1FF
+#define HTW_MASK                  0x01
+#define HUM_MASK                  0x01
+#define TLBSIZE_MASK              0x0F
+#define NCB_MASK                  0xFF
+#define NIRPT_MASK                0xFF
+
+
+/* M2VCBRn */
+#define VMID_MASK                 0x1F
+#define CBNDX_MASK                0xFF
+#define BYPASSD_MASK              0x01
+#define BPRCOSH_MASK              0x01
+#define BPRCISH_MASK              0x01
+#define BPRCNSH_MASK              0x01
+#define BPSHCFG_MASK              0x03
+#define NSCFG_MASK                0x03
+#define BPMTCFG_MASK              0x01
+#define BPMEMTYPE_MASK            0x07
+
+
+/* REV */
+#define MINOR_MASK                0x0F
+#define MAJOR_MASK                0x0F
+
+
+/* TESTBUSCR */
+#define TBE_MASK                  0x01
+#define SPDMBE_MASK               0x01
+#define WGSEL_MASK                0x03
+#define TBLSEL_MASK               0x03
+#define TBHSEL_MASK               0x03
+#define SPDM0SEL_MASK             0x0F
+#define SPDM1SEL_MASK             0x0F
+#define SPDM2SEL_MASK             0x0F
+#define SPDM3SEL_MASK             0x0F
+
+
+/* TLBIMID */
+#define TLBIVMID_VMID_MASK        0x1F
+
+
+/* TLBRSW */
+#define TLBRSW_INDEX_MASK         0xFF
+#define TLBBFBS_MASK              0x03
+
+
+/* TLBTR0 */
+#define PR_MASK                   0x01
+#define PW_MASK                   0x01
+#define UR_MASK                   0x01
+#define UW_MASK                   0x01
+#define XN_MASK                   0x01
+#define NSDESC_MASK               0x01
+#define ISH_MASK                  0x01
+#define SH_MASK                   0x01
+#define MT_MASK                   0x07
+#define DPSIZR_MASK               0x07
+#define DPSIZC_MASK               0x07
+
+
+/* TLBTR1 */
+#define TLBTR1_VMID_MASK          0x1F
+#define TLBTR1_PA_MASK            0x000FFFFF
+
+
+/* TLBTR2 */
+#define TLBTR2_ASID_MASK          0xFF
+#define TLBTR2_V_MASK             0x01
+#define TLBTR2_NSTID_MASK         0x01
+#define TLBTR2_NV_MASK            0x01
+#define TLBTR2_VA_MASK            0x000FFFFF
+
+
+/* Global Register Shifts */
+/* CBACRn */
+#define RWVMID_SHIFT             0
+#define RWE_SHIFT                8
+#define RWGE_SHIFT               9
+#define CBVMID_SHIFT             16
+#define IRPTNDX_SHIFT            24
+
+
+/* CR */
+#define RPUE_SHIFT               0
+#define RPUERE_SHIFT             1
+#define RPUEIE_SHIFT             2
+#define DCDEE_SHIFT              3
+#define CLIENTPD_SHIFT           4
+#define STALLD_SHIFT             5
+#define TLBLKCRWE_SHIFT          6
+#define CR_TLBIALLCFG_SHIFT      7
+#define TLBIVMIDCFG_SHIFT        8
+#define CR_HUME_SHIFT            9
+
+
+/* ESR */
+#define CFG_SHIFT                0
+#define BYPASS_SHIFT             1
+#define ESR_MULTI_SHIFT          31
+
+
+/* ESYNR0 */
+#define ESYNR0_AMID_SHIFT        0
+#define ESYNR0_APID_SHIFT        8
+#define ESYNR0_ABID_SHIFT        13
+#define ESYNR0_AVMID_SHIFT       16
+#define ESYNR0_ATID_SHIFT        24
+
+
+/* ESYNR1 */
+#define ESYNR1_AMEMTYPE_SHIFT           0
+#define ESYNR1_ASHARED_SHIFT            3
+#define ESYNR1_AINNERSHARED_SHIFT       4
+#define ESYNR1_APRIV_SHIFT              5
+#define ESYNR1_APROTNS_SHIFT            6
+#define ESYNR1_AINST_SHIFT              7
+#define ESYNR1_AWRITE_SHIFT             8
+#define ESYNR1_ABURST_SHIFT             10
+#define ESYNR1_ALEN_SHIFT               12
+#define ESYNR1_ASIZE_SHIFT              16
+#define ESYNR1_ALOCK_SHIFT              20
+#define ESYNR1_AOOO_SHIFT               22
+#define ESYNR1_AFULL_SHIFT              24
+#define ESYNR1_AC_SHIFT                 30
+#define ESYNR1_DCD_SHIFT                31
+
+
+/* IDR */
+#define NM2VCBMT_SHIFT           0
+#define HTW_SHIFT                9
+#define HUM_SHIFT                10
+#define TLBSIZE_SHIFT            12
+#define NCB_SHIFT                16
+#define NIRPT_SHIFT              24
+
+
+/* M2VCBRn */
+#define VMID_SHIFT               0
+#define CBNDX_SHIFT              8
+#define BYPASSD_SHIFT            16
+#define BPRCOSH_SHIFT            17
+#define BPRCISH_SHIFT            18
+#define BPRCNSH_SHIFT            19
+#define BPSHCFG_SHIFT            20
+#define NSCFG_SHIFT              22
+#define BPMTCFG_SHIFT            24
+#define BPMEMTYPE_SHIFT          25
+
+
+/* REV */
+#define MINOR_SHIFT              0
+#define MAJOR_SHIFT              4
+
+
+/* TESTBUSCR */
+#define TBE_SHIFT                0
+#define SPDMBE_SHIFT             1
+#define WGSEL_SHIFT              8
+#define TBLSEL_SHIFT             12
+#define TBHSEL_SHIFT             14
+#define SPDM0SEL_SHIFT           16
+#define SPDM1SEL_SHIFT           20
+#define SPDM2SEL_SHIFT           24
+#define SPDM3SEL_SHIFT           28
+
+
+/* TLBIMID */
+#define TLBIVMID_VMID_SHIFT      0
+
+
+/* TLBRSW */
+#define TLBRSW_INDEX_SHIFT       0
+#define TLBBFBS_SHIFT            8
+
+
+/* TLBTR0 */
+#define PR_SHIFT                 0
+#define PW_SHIFT                 1
+#define UR_SHIFT                 2
+#define UW_SHIFT                 3
+#define XN_SHIFT                 4
+#define NSDESC_SHIFT             6
+#define ISH_SHIFT                7
+#define SH_SHIFT                 8
+#define MT_SHIFT                 9
+#define DPSIZR_SHIFT             16
+#define DPSIZC_SHIFT             20
+
+
+/* TLBTR1 */
+#define TLBTR1_VMID_SHIFT        0
+#define TLBTR1_PA_SHIFT          12
+
+
+/* TLBTR2 */
+#define TLBTR2_ASID_SHIFT        0
+#define TLBTR2_V_SHIFT           8
+#define TLBTR2_NSTID_SHIFT       9
+#define TLBTR2_NV_SHIFT          10
+#define TLBTR2_VA_SHIFT          12
+
+
+/* Context Register Masks */
+/* ACTLR */
+#define CFERE_MASK                       0x01
+#define CFEIE_MASK                       0x01
+#define PTSHCFG_MASK                     0x03
+#define RCOSH_MASK                       0x01
+#define RCISH_MASK                       0x01
+#define RCNSH_MASK                       0x01
+#define PRIVCFG_MASK                     0x03
+#define DNA_MASK                         0x01
+#define DNLV2PA_MASK                     0x01
+#define TLBMCFG_MASK                     0x03
+#define CFCFG_MASK                       0x01
+#define TIPCF_MASK                       0x01
+#define V2PCFG_MASK                      0x03
+#define HUME_MASK                        0x01
+#define PTMTCFG_MASK                     0x01
+#define PTMEMTYPE_MASK                   0x07
+
+
+/* BFBCR */
+#define BFBDFE_MASK                      0x01
+#define BFBSFE_MASK                      0x01
+#define SFVS_MASK                        0x01
+#define FLVIC_MASK                       0x0F
+#define SLVIC_MASK                       0x0F
+
+
+/* CONTEXTIDR */
+#define CONTEXTIDR_ASID_MASK             0xFF
+#define PROCID_MASK                      0x00FFFFFF
+
+
+/* FSR */
+#define TF_MASK                          0x01
+#define AFF_MASK                         0x01
+#define APF_MASK                         0x01
+#define TLBMF_MASK                       0x01
+#define HTWDEEF_MASK                     0x01
+#define HTWSEEF_MASK                     0x01
+#define MHF_MASK                         0x01
+#define SL_MASK                          0x01
+#define SS_MASK                          0x01
+#define MULTI_MASK                       0x01
+
+
+/* FSYNR0 */
+#define AMID_MASK                        0xFF
+#define APID_MASK                        0x1F
+#define ABID_MASK                        0x07
+#define ATID_MASK                        0xFF
+
+
+/* FSYNR1 */
+#define AMEMTYPE_MASK                    0x07
+#define ASHARED_MASK                     0x01
+#define AINNERSHARED_MASK                0x01
+#define APRIV_MASK                       0x01
+#define APROTNS_MASK                     0x01
+#define AINST_MASK                       0x01
+#define AWRITE_MASK                      0x01
+#define ABURST_MASK                      0x01
+#define ALEN_MASK                        0x0F
+#define FSYNR1_ASIZE_MASK                0x07
+#define ALOCK_MASK                       0x03
+#define AFULL_MASK                       0x01
+
+
+/* NMRR */
+#define ICPC0_MASK                       0x03
+#define ICPC1_MASK                       0x03
+#define ICPC2_MASK                       0x03
+#define ICPC3_MASK                       0x03
+#define ICPC4_MASK                       0x03
+#define ICPC5_MASK                       0x03
+#define ICPC6_MASK                       0x03
+#define ICPC7_MASK                       0x03
+#define OCPC0_MASK                       0x03
+#define OCPC1_MASK                       0x03
+#define OCPC2_MASK                       0x03
+#define OCPC3_MASK                       0x03
+#define OCPC4_MASK                       0x03
+#define OCPC5_MASK                       0x03
+#define OCPC6_MASK                       0x03
+#define OCPC7_MASK                       0x03
+
+
+/* PAR */
+#define FAULT_MASK                       0x01
+/* If a fault is present, these are the
+same as the fault fields in the FAR */
+#define FAULT_TF_MASK                    0x01
+#define FAULT_AFF_MASK                   0x01
+#define FAULT_APF_MASK                   0x01
+#define FAULT_TLBMF_MASK                 0x01
+#define FAULT_HTWDEEF_MASK               0x01
+#define FAULT_HTWSEEF_MASK               0x01
+#define FAULT_MHF_MASK                   0x01
+#define FAULT_SL_MASK                    0x01
+#define FAULT_SS_MASK                    0x01
+
+/* If NO fault is present, the following
+ * fields are in effect
+ * (FAULT remains as before) */
+#define PAR_NOFAULT_SS_MASK              0x01
+#define PAR_NOFAULT_MT_MASK              0x07
+#define PAR_NOFAULT_SH_MASK              0x01
+#define PAR_NOFAULT_NS_MASK              0x01
+#define PAR_NOFAULT_NOS_MASK             0x01
+#define PAR_NPFAULT_PA_MASK              0x000FFFFF
+
+
+/* PRRR */
+#define MTC0_MASK                        0x03
+#define MTC1_MASK                        0x03
+#define MTC2_MASK                        0x03
+#define MTC3_MASK                        0x03
+#define MTC4_MASK                        0x03
+#define MTC5_MASK                        0x03
+#define MTC6_MASK                        0x03
+#define MTC7_MASK                        0x03
+#define SHDSH0_MASK                      0x01
+#define SHDSH1_MASK                      0x01
+#define SHNMSH0_MASK                     0x01
+#define SHNMSH1_MASK                     0x01
+#define NOS0_MASK                        0x01
+#define NOS1_MASK                        0x01
+#define NOS2_MASK                        0x01
+#define NOS3_MASK                        0x01
+#define NOS4_MASK                        0x01
+#define NOS5_MASK                        0x01
+#define NOS6_MASK                        0x01
+#define NOS7_MASK                        0x01
+
+
+/* RESUME */
+#define TNR_MASK                         0x01
+
+
+/* SCTLR */
+#define M_MASK                           0x01
+#define TRE_MASK                         0x01
+#define AFE_MASK                         0x01
+#define HAF_MASK                         0x01
+#define BE_MASK                          0x01
+#define AFFD_MASK                        0x01
+
+
+/* TLBIASID */
+#define TLBIASID_ASID_MASK               0xFF
+
+
+/* TLBIVA */
+#define TLBIVA_ASID_MASK                 0xFF
+#define TLBIVA_VA_MASK                   0x000FFFFF
+
+
+/* TLBIVAA */
+#define TLBIVAA_VA_MASK                  0x000FFFFF
+
+
+/* TLBLCKR */
+#define LKE_MASK                         0x01
+#define TLBLCKR_TLBIALLCFG_MASK          0x01
+#define TLBIASIDCFG_MASK                 0x01
+#define TLBIVAACFG_MASK                  0x01
+#define FLOOR_MASK                       0xFF
+#define VICTIM_MASK                      0xFF
+
+
+/* TTBCR */
+#define N_MASK                           0x07
+#define PD0_MASK                         0x01
+#define PD1_MASK                         0x01
+
+
+/* TTBR0 */
+#define TTBR0_IRGNH_MASK                 0x01
+#define TTBR0_SH_MASK                    0x01
+#define TTBR0_ORGN_MASK                  0x03
+#define TTBR0_NOS_MASK                   0x01
+#define TTBR0_IRGNL_MASK                 0x01
+#define TTBR0_PA_MASK                    0x0003FFFF
+
+
+/* TTBR1 */
+#define TTBR1_IRGNH_MASK                 0x01
+#define TTBR1_SH_MASK                    0x01
+#define TTBR1_ORGN_MASK                  0x03
+#define TTBR1_NOS_MASK                   0x01
+#define TTBR1_IRGNL_MASK                 0x01
+#define TTBR1_PA_MASK                    0x0003FFFF
+
+
+/* V2PSR */
+#define HIT_MASK                         0x01
+#define INDEX_MASK                       0xFF
+
+
+/* V2Pxx */
+#define V2Pxx_INDEX_MASK                 0xFF
+#define V2Pxx_VA_MASK                    0x000FFFFF
+
+
+/* Context Register Shifts */
+/* ACTLR */
+#define CFERE_SHIFT                    0
+#define CFEIE_SHIFT                    1
+#define PTSHCFG_SHIFT                  2
+#define RCOSH_SHIFT                    4
+#define RCISH_SHIFT                    5
+#define RCNSH_SHIFT                    6
+#define PRIVCFG_SHIFT                  8
+#define DNA_SHIFT                      10
+#define DNLV2PA_SHIFT                  11
+#define TLBMCFG_SHIFT                  12
+#define CFCFG_SHIFT                    14
+#define TIPCF_SHIFT                    15
+#define V2PCFG_SHIFT                   16
+#define HUME_SHIFT                     18
+#define PTMTCFG_SHIFT                  20
+#define PTMEMTYPE_SHIFT                21
+
+
+/* BFBCR */
+#define BFBDFE_SHIFT                   0
+#define BFBSFE_SHIFT                   1
+#define SFVS_SHIFT                     2
+#define FLVIC_SHIFT                    4
+#define SLVIC_SHIFT                    8
+
+
+/* CONTEXTIDR */
+#define CONTEXTIDR_ASID_SHIFT          0
+#define PROCID_SHIFT                   8
+
+
+/* FSR */
+#define TF_SHIFT                       1
+#define AFF_SHIFT                      2
+#define APF_SHIFT                      3
+#define TLBMF_SHIFT                    4
+#define HTWDEEF_SHIFT                  5
+#define HTWSEEF_SHIFT                  6
+#define MHF_SHIFT                      7
+#define SL_SHIFT                       16
+#define SS_SHIFT                       30
+#define MULTI_SHIFT                    31
+
+
+/* FSYNR0 */
+#define AMID_SHIFT                     0
+#define APID_SHIFT                     8
+#define ABID_SHIFT                     13
+#define ATID_SHIFT                     24
+
+
+/* FSYNR1 */
+#define AMEMTYPE_SHIFT                 0
+#define ASHARED_SHIFT                  3
+#define AINNERSHARED_SHIFT             4
+#define APRIV_SHIFT                    5
+#define APROTNS_SHIFT                  6
+#define AINST_SHIFT                    7
+#define AWRITE_SHIFT                   8
+#define ABURST_SHIFT                   10
+#define ALEN_SHIFT                     12
+#define FSYNR1_ASIZE_SHIFT             16
+#define ALOCK_SHIFT                    20
+#define AFULL_SHIFT                    24
+
+
+/* NMRR */
+#define ICPC0_SHIFT                    0
+#define ICPC1_SHIFT                    2
+#define ICPC2_SHIFT                    4
+#define ICPC3_SHIFT                    6
+#define ICPC4_SHIFT                    8
+#define ICPC5_SHIFT                    10
+#define ICPC6_SHIFT                    12
+#define ICPC7_SHIFT                    14
+#define OCPC0_SHIFT                    16
+#define OCPC1_SHIFT                    18
+#define OCPC2_SHIFT                    20
+#define OCPC3_SHIFT                    22
+#define OCPC4_SHIFT                    24
+#define OCPC5_SHIFT                    26
+#define OCPC6_SHIFT                    28
+#define OCPC7_SHIFT                    30
+
+
+/* PAR */
+#define FAULT_SHIFT                    0
+/* If a fault is present, these are the
+same as the fault fields in the FAR */
+#define FAULT_TF_SHIFT                 1
+#define FAULT_AFF_SHIFT                2
+#define FAULT_APF_SHIFT                3
+#define FAULT_TLBMF_SHIFT              4
+#define FAULT_HTWDEEF_SHIFT            5
+#define FAULT_HTWSEEF_SHIFT            6
+#define FAULT_MHF_SHIFT                7
+#define FAULT_SL_SHIFT                 16
+#define FAULT_SS_SHIFT                 30
+
+/* If NO fault is present, the following
+ * fields are in effect
+ * (FAULT remains as before) */
+#define PAR_NOFAULT_SS_SHIFT           1
+#define PAR_NOFAULT_MT_SHIFT           4
+#define PAR_NOFAULT_SH_SHIFT           7
+#define PAR_NOFAULT_NS_SHIFT           9
+#define PAR_NOFAULT_NOS_SHIFT          10
+#define PAR_NPFAULT_PA_SHIFT           12
+
+
+/* PRRR */
+#define MTC0_SHIFT                     0
+#define MTC1_SHIFT                     2
+#define MTC2_SHIFT                     4
+#define MTC3_SHIFT                     6
+#define MTC4_SHIFT                     8
+#define MTC5_SHIFT                     10
+#define MTC6_SHIFT                     12
+#define MTC7_SHIFT                     14
+#define SHDSH0_SHIFT                   16
+#define SHDSH1_SHIFT                   17
+#define SHNMSH0_SHIFT                  18
+#define SHNMSH1_SHIFT                  19
+#define NOS0_SHIFT                     24
+#define NOS1_SHIFT                     25
+#define NOS2_SHIFT                     26
+#define NOS3_SHIFT                     27
+#define NOS4_SHIFT                     28
+#define NOS5_SHIFT                     29
+#define NOS6_SHIFT                     30
+#define NOS7_SHIFT                     31
+
+
+/* RESUME */
+#define TNR_SHIFT                      0
+
+
+/* SCTLR */
+#define M_SHIFT                        0
+#define TRE_SHIFT                      1
+#define AFE_SHIFT                      2
+#define HAF_SHIFT                      3
+#define BE_SHIFT                       4
+#define AFFD_SHIFT                     5
+
+
+/* TLBIASID */
+#define TLBIASID_ASID_SHIFT            0
+
+
+/* TLBIVA */
+#define TLBIVA_ASID_SHIFT              0
+#define TLBIVA_VA_SHIFT                12
+
+
+/* TLBIVAA */
+#define TLBIVAA_VA_SHIFT               12
+
+
+/* TLBLCKR */
+#define LKE_SHIFT                      0
+#define TLBLCKR_TLBIALLCFG_SHIFT       1
+#define TLBIASIDCFG_SHIFT              2
+#define TLBIVAACFG_SHIFT               3
+#define FLOOR_SHIFT                    8
+#define VICTIM_SHIFT                   8
+
+
+/* TTBCR */
+#define N_SHIFT                        3
+#define PD0_SHIFT                      4
+#define PD1_SHIFT                      5
+
+
+/* TTBR0 */
+#define TTBR0_IRGNH_SHIFT              0
+#define TTBR0_SH_SHIFT                 1
+#define TTBR0_ORGN_SHIFT               3
+#define TTBR0_NOS_SHIFT                5
+#define TTBR0_IRGNL_SHIFT              6
+#define TTBR0_PA_SHIFT                 14
+
+
+/* TTBR1 */
+#define TTBR1_IRGNH_SHIFT              0
+#define TTBR1_SH_SHIFT                 1
+#define TTBR1_ORGN_SHIFT               3
+#define TTBR1_NOS_SHIFT                5
+#define TTBR1_IRGNL_SHIFT              6
+#define TTBR1_PA_SHIFT                 14
+
+
+/* V2PSR */
+#define HIT_SHIFT                      0
+#define INDEX_SHIFT                    8
+
+
+/* V2Pxx */
+#define V2Pxx_INDEX_SHIFT              0
+#define V2Pxx_VA_SHIFT                 12
+
+#endif
diff --git a/arch/arm/mach-msm/include/mach/irqs-8x60.h b/arch/arm/mach-msm/include/mach/irqs-8x60.h
new file mode 100644 (file)
index 0000000..36074cf
--- /dev/null
@@ -0,0 +1,253 @@
+/* Copyright (c) 2010 Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IRQS_8X60_H
+#define __ASM_ARCH_MSM_IRQS_8X60_H
+
+/* MSM ACPU Interrupt Numbers */
+
+/* 0-15:  STI/SGI (software triggered/generated interrupts)
+ * 16-31: PPI (private peripheral interrupts)
+ * 32+:   SPI (shared peripheral interrupts)
+ */
+
+#define GIC_PPI_START 16
+#define GIC_SPI_START 32
+
+#define INT_DEBUG_TIMER_EXP                    (GIC_PPI_START + 0)
+#define INT_GP_TIMER_EXP                       (GIC_PPI_START + 1)
+#define INT_GP_TIMER2_EXP                      (GIC_PPI_START + 2)
+#define WDT0_ACCSCSSNBARK_INT                  (GIC_PPI_START + 3)
+#define WDT1_ACCSCSSNBARK_INT                  (GIC_PPI_START + 4)
+#define AVS_SVICINT                            (GIC_PPI_START + 5)
+#define AVS_SVICINTSWDONE                      (GIC_PPI_START + 6)
+#define CPU_DBGCPUXCOMMRXFULL                  (GIC_PPI_START + 7)
+#define CPU_DBGCPUXCOMMTXEMPTY                 (GIC_PPI_START + 8)
+#define CPU_SICCPUXPERFMONIRPTREQ              (GIC_PPI_START + 9)
+#define SC_AVSCPUXDOWN                         (GIC_PPI_START + 10)
+#define SC_AVSCPUXUP                           (GIC_PPI_START + 11)
+#define SC_SICCPUXACGIRPTREQ                   (GIC_PPI_START + 12)
+/* PPI 13 to 15 are unused */
+
+
+#define SC_SICMPUIRPTREQ                       (GIC_SPI_START + 0)
+#define SC_SICL2IRPTREQ                                (GIC_SPI_START + 1)
+#define SC_SICL2ACGIRPTREQ                     (GIC_SPI_START + 2)
+#define NC                                     (GIC_SPI_START + 3)
+#define TLMM_SCSS_DIR_CONN_IRQ_0               (GIC_SPI_START + 4)
+#define TLMM_SCSS_DIR_CONN_IRQ_1               (GIC_SPI_START + 5)
+#define TLMM_SCSS_DIR_CONN_IRQ_2               (GIC_SPI_START + 6)
+#define TLMM_SCSS_DIR_CONN_IRQ_3               (GIC_SPI_START + 7)
+#define TLMM_SCSS_DIR_CONN_IRQ_4               (GIC_SPI_START + 8)
+#define TLMM_SCSS_DIR_CONN_IRQ_5               (GIC_SPI_START + 9)
+#define TLMM_SCSS_DIR_CONN_IRQ_6               (GIC_SPI_START + 10)
+#define TLMM_SCSS_DIR_CONN_IRQ_7               (GIC_SPI_START + 11)
+#define TLMM_SCSS_DIR_CONN_IRQ_8               (GIC_SPI_START + 12)
+#define TLMM_SCSS_DIR_CONN_IRQ_9               (GIC_SPI_START + 13)
+#define PM8058_SEC_IRQ_N                       (GIC_SPI_START + 14)
+#define PM8901_SEC_IRQ_N                       (GIC_SPI_START + 15)
+#define TLMM_SCSS_SUMMARY_IRQ                  (GIC_SPI_START + 16)
+#define SPDM_RT_1_IRQ                          (GIC_SPI_START + 17)
+#define SPDM_DIAG_IRQ                          (GIC_SPI_START + 18)
+#define RPM_SCSS_CPU0_GP_HIGH_IRQ              (GIC_SPI_START + 19)
+#define RPM_SCSS_CPU0_GP_MEDIUM_IRQ            (GIC_SPI_START + 20)
+#define RPM_SCSS_CPU0_GP_LOW_IRQ               (GIC_SPI_START + 21)
+#define RPM_SCSS_CPU0_WAKE_UP_IRQ              (GIC_SPI_START + 22)
+#define RPM_SCSS_CPU1_GP_HIGH_IRQ              (GIC_SPI_START + 23)
+#define RPM_SCSS_CPU1_GP_MEDIUM_IRQ            (GIC_SPI_START + 24)
+#define RPM_SCSS_CPU1_GP_LOW_IRQ               (GIC_SPI_START + 25)
+#define RPM_SCSS_CPU1_WAKE_UP_IRQ              (GIC_SPI_START + 26)
+#define SSBI2_2_SC_CPU0_SECURE_INT             (GIC_SPI_START + 27)
+#define SSBI2_2_SC_CPU0_NON_SECURE_INT         (GIC_SPI_START + 28)
+#define SSBI2_1_SC_CPU0_SECURE_INT             (GIC_SPI_START + 29)
+#define SSBI2_1_SC_CPU0_NON_SECURE_INT         (GIC_SPI_START + 30)
+#define MSMC_SC_SEC_CE_IRQ                     (GIC_SPI_START + 31)
+#define MSMC_SC_PRI_CE_IRQ                     (GIC_SPI_START + 32)
+#define MARM_FIQ                               (GIC_SPI_START + 33)
+#define MARM_IRQ                               (GIC_SPI_START + 34)
+#define MARM_L2CC_IRQ                          (GIC_SPI_START + 35)
+#define MARM_WDOG_EXPIRED                      (GIC_SPI_START + 36)
+#define MARM_SCSS_GP_IRQ_0                     (GIC_SPI_START + 37)
+#define MARM_SCSS_GP_IRQ_1                     (GIC_SPI_START + 38)
+#define MARM_SCSS_GP_IRQ_2                     (GIC_SPI_START + 39)
+#define MARM_SCSS_GP_IRQ_3                     (GIC_SPI_START + 40)
+#define MARM_SCSS_GP_IRQ_4                     (GIC_SPI_START + 41)
+#define MARM_SCSS_GP_IRQ_5                     (GIC_SPI_START + 42)
+#define MARM_SCSS_GP_IRQ_6                     (GIC_SPI_START + 43)
+#define MARM_SCSS_GP_IRQ_7                     (GIC_SPI_START + 44)
+#define MARM_SCSS_GP_IRQ_8                     (GIC_SPI_START + 45)
+#define MARM_SCSS_GP_IRQ_9                     (GIC_SPI_START + 46)
+#define VPE_IRQ                                        (GIC_SPI_START + 47)
+#define VFE_IRQ                                        (GIC_SPI_START + 48)
+#define VCODEC_IRQ                             (GIC_SPI_START + 49)
+#define TV_ENC_IRQ                             (GIC_SPI_START + 50)
+#define SMMU_VPE_CB_SC_SECURE_IRQ              (GIC_SPI_START + 51)
+#define SMMU_VPE_CB_SC_NON_SECURE_IRQ          (GIC_SPI_START + 52)
+#define SMMU_VFE_CB_SC_SECURE_IRQ              (GIC_SPI_START + 53)
+#define SMMU_VFE_CB_SC_NON_SECURE_IRQ          (GIC_SPI_START + 54)
+#define SMMU_VCODEC_B_CB_SC_SECURE_IRQ         (GIC_SPI_START + 55)
+#define SMMU_VCODEC_B_CB_SC_NON_SECURE_IRQ     (GIC_SPI_START + 56)
+#define SMMU_VCODEC_A_CB_SC_SECURE_IRQ         (GIC_SPI_START + 57)
+#define SMMU_VCODEC_A_CB_SC_NON_SECURE_IRQ     (GIC_SPI_START + 58)
+#define SMMU_ROT_CB_SC_SECURE_IRQ              (GIC_SPI_START + 59)
+#define SMMU_ROT_CB_SC_NON_SECURE_IRQ          (GIC_SPI_START + 60)
+#define SMMU_MDP1_CB_SC_SECURE_IRQ             (GIC_SPI_START + 61)
+#define SMMU_MDP1_CB_SC_NON_SECURE_IRQ         (GIC_SPI_START + 62)
+#define SMMU_MDP0_CB_SC_SECURE_IRQ             (GIC_SPI_START + 63)
+#define SMMU_MDP0_CB_SC_NON_SECURE_IRQ         (GIC_SPI_START + 64)
+#define SMMU_JPEGD_CB_SC_SECURE_IRQ            (GIC_SPI_START + 65)
+#define SMMU_JPEGD_CB_SC_NON_SECURE_IRQ                (GIC_SPI_START + 66)
+#define SMMU_IJPEG_CB_SC_SECURE_IRQ            (GIC_SPI_START + 67)
+#define SMMU_IJPEG_CB_SC_NON_SECURE_IRQ                (GIC_SPI_START + 68)
+#define SMMU_GFX3D_CB_SC_SECURE_IRQ            (GIC_SPI_START + 69)
+#define SMMU_GFX3D_CB_SC_NON_SECURE_IRQ                (GIC_SPI_START + 70)
+#define SMMU_GFX2D0_CB_SC_SECURE_IRQ           (GIC_SPI_START + 71)
+#define SMMU_GFX2D0_CB_SC_NON_SECURE_IRQ       (GIC_SPI_START + 72)
+#define ROT_IRQ                                        (GIC_SPI_START + 73)
+#define MMSS_FABRIC_IRQ                                (GIC_SPI_START + 74)
+#define MDP_IRQ                                        (GIC_SPI_START + 75)
+#define JPEGD_IRQ                              (GIC_SPI_START + 76)
+#define JPEG_IRQ                               (GIC_SPI_START + 77)
+#define MMSS_IMEM_IRQ                          (GIC_SPI_START + 78)
+#define HDMI_IRQ                               (GIC_SPI_START + 79)
+#define GFX3D_IRQ                              (GIC_SPI_START + 80)
+#define GFX2D0_IRQ                             (GIC_SPI_START + 81)
+#define DSI_IRQ                                        (GIC_SPI_START + 82)
+#define CSI_1_IRQ                              (GIC_SPI_START + 83)
+#define CSI_0_IRQ                              (GIC_SPI_START + 84)
+#define LPASS_SCSS_AUDIO_IF_OUT0_IRQ           (GIC_SPI_START + 85)
+#define LPASS_SCSS_MIDI_IRQ                    (GIC_SPI_START + 86)
+#define LPASS_Q6SS_WDOG_EXPIRED                        (GIC_SPI_START + 87)
+#define LPASS_SCSS_GP_LOW_IRQ                  (GIC_SPI_START + 88)
+#define LPASS_SCSS_GP_MEDIUM_IRQ               (GIC_SPI_START + 89)
+#define LPASS_SCSS_GP_HIGH_IRQ                 (GIC_SPI_START + 90)
+#define TOP_IMEM_IRQ                           (GIC_SPI_START + 91)
+#define FABRIC_SYS_IRQ                         (GIC_SPI_START + 92)
+#define FABRIC_APPS_IRQ                                (GIC_SPI_START + 93)
+#define USB1_HS_BAM_IRQ                                (GIC_SPI_START + 94)
+#define SDC4_BAM_IRQ                           (GIC_SPI_START + 95)
+#define SDC3_BAM_IRQ                           (GIC_SPI_START + 96)
+#define SDC2_BAM_IRQ                           (GIC_SPI_START + 97)
+#define SDC1_BAM_IRQ                           (GIC_SPI_START + 98)
+#define FABRIC_SPS_IRQ                         (GIC_SPI_START + 99)
+#define USB1_HS_IRQ                            (GIC_SPI_START + 100)
+#define SDC4_IRQ_0                             (GIC_SPI_START + 101)
+#define SDC3_IRQ_0                             (GIC_SPI_START + 102)
+#define SDC2_IRQ_0                             (GIC_SPI_START + 103)
+#define SDC1_IRQ_0                             (GIC_SPI_START + 104)
+#define SPS_BAM_DMA_IRQ                                (GIC_SPI_START + 105)
+#define SPS_SEC_VIOL_IRQ                       (GIC_SPI_START + 106)
+#define SPS_MTI_0                              (GIC_SPI_START + 107)
+#define SPS_MTI_1                              (GIC_SPI_START + 108)
+#define SPS_MTI_2                              (GIC_SPI_START + 109)
+#define SPS_MTI_3                              (GIC_SPI_START + 110)
+#define SPS_MTI_4                              (GIC_SPI_START + 111)
+#define SPS_MTI_5                              (GIC_SPI_START + 112)
+#define SPS_MTI_6                              (GIC_SPI_START + 113)
+#define SPS_MTI_7                              (GIC_SPI_START + 114)
+#define SPS_MTI_8                              (GIC_SPI_START + 115)
+#define SPS_MTI_9                              (GIC_SPI_START + 116)
+#define SPS_MTI_10                             (GIC_SPI_START + 117)
+#define SPS_MTI_11                             (GIC_SPI_START + 118)
+#define SPS_MTI_12                             (GIC_SPI_START + 119)
+#define SPS_MTI_13                             (GIC_SPI_START + 120)
+#define SPS_MTI_14                             (GIC_SPI_START + 121)
+#define SPS_MTI_15                             (GIC_SPI_START + 122)
+#define SPS_MTI_16                             (GIC_SPI_START + 123)
+#define SPS_MTI_17                             (GIC_SPI_START + 124)
+#define SPS_MTI_18                             (GIC_SPI_START + 125)
+#define SPS_MTI_19                             (GIC_SPI_START + 126)
+#define SPS_MTI_20                             (GIC_SPI_START + 127)
+#define SPS_MTI_21                             (GIC_SPI_START + 128)
+#define SPS_MTI_22                             (GIC_SPI_START + 129)
+#define SPS_MTI_23                             (GIC_SPI_START + 130)
+#define SPS_MTI_24                             (GIC_SPI_START + 131)
+#define SPS_MTI_25                             (GIC_SPI_START + 132)
+#define SPS_MTI_26                             (GIC_SPI_START + 133)
+#define SPS_MTI_27                             (GIC_SPI_START + 134)
+#define SPS_MTI_28                             (GIC_SPI_START + 135)
+#define SPS_MTI_29                             (GIC_SPI_START + 136)
+#define SPS_MTI_30                             (GIC_SPI_START + 137)
+#define SPS_MTI_31                             (GIC_SPI_START + 138)
+#define UXMC_EBI2_WR_ER_DONE_IRQ               (GIC_SPI_START + 139)
+#define UXMC_EBI2_OP_DONE_IRQ                  (GIC_SPI_START + 140)
+#define USB2_IRQ                               (GIC_SPI_START + 141)
+#define USB1_IRQ                               (GIC_SPI_START + 142)
+#define TSSC_SSBI_IRQ                          (GIC_SPI_START + 143)
+#define TSSC_SAMPLE_IRQ                                (GIC_SPI_START + 144)
+#define TSSC_PENUP_IRQ                         (GIC_SPI_START + 145)
+#define INT_UART1DM_IRQ                                (GIC_SPI_START + 146)
+#define GSBI1_QUP_IRQ                          (GIC_SPI_START + 147)
+#define INT_UART2DM_IRQ                                (GIC_SPI_START + 148)
+#define GSBI2_QUP_IRQ                          (GIC_SPI_START + 149)
+#define INT_UART3DM_IRQ                                (GIC_SPI_START + 150)
+#define GSBI3_QUP_IRQ                          (GIC_SPI_START + 151)
+#define INT_UART4DM_IRQ                                (GIC_SPI_START + 152)
+#define GSBI4_QUP_IRQ                          (GIC_SPI_START + 153)
+#define INT_UART5DM_IRQ                                (GIC_SPI_START + 154)
+#define GSBI5_QUP_IRQ                          (GIC_SPI_START + 155)
+#define INT_UART6DM_IRQ                                (GIC_SPI_START + 156)
+#define GSBI6_QUP_IRQ                          (GIC_SPI_START + 157)
+#define INT_UART7DM_IRQ                                (GIC_SPI_START + 158)
+#define GSBI7_QUP_IRQ                          (GIC_SPI_START + 159)
+#define INT_UART8DM_IRQ                                (GIC_SPI_START + 160)
+#define GSBI8_QUP_IRQ                          (GIC_SPI_START + 161)
+#define TSIF_TSPP_IRQ                          (GIC_SPI_START + 162)
+#define TSIF_BAM_IRQ                           (GIC_SPI_START + 163)
+#define TSIF2_IRQ                              (GIC_SPI_START + 164)
+#define TSIF1_IRQ                              (GIC_SPI_START + 165)
+#define INT_ADM1_MASTER                                (GIC_SPI_START + 166)
+#define INT_ADM1_AARM                          (GIC_SPI_START + 167)
+#define INT_ADM1_SD2                           (GIC_SPI_START + 168)
+#define INT_ADM1_SD3                           (GIC_SPI_START + 169)
+#define INT_ADM0_MASTER                                (GIC_SPI_START + 170)
+#define INT_ADM0_AARM                          (GIC_SPI_START + 171)
+#define INT_ADM0_SD2                           (GIC_SPI_START + 172)
+#define INT_ADM0_SD3                           (GIC_SPI_START + 173)
+#define CC_SCSS_WDT1CPU1BITEEXPIRED            (GIC_SPI_START + 174)
+#define CC_SCSS_WDT1CPU0BITEEXPIRED            (GIC_SPI_START + 175)
+#define CC_SCSS_WDT0CPU1BITEEXPIRED            (GIC_SPI_START + 176)
+#define CC_SCSS_WDT0CPU0BITEEXPIRED            (GIC_SPI_START + 177)
+#define TSENS_UPPER_LOWER_INT                  (GIC_SPI_START + 178)
+#define SSBI2_2_SC_CPU1_SECURE_INT             (GIC_SPI_START + 179)
+#define SSBI2_2_SC_CPU1_NON_SECURE_INT         (GIC_SPI_START + 180)
+#define SSBI2_1_SC_CPU1_SECURE_INT             (GIC_SPI_START + 181)
+#define SSBI2_1_SC_CPU1_NON_SECURE_INT         (GIC_SPI_START + 182)
+#define XPU_SUMMARY_IRQ                                (GIC_SPI_START + 183)
+#define BUS_EXCEPTION_SUMMARY_IRQ              (GIC_SPI_START + 184)
+#define HSDDRX_SMICH0_IRQ                      (GIC_SPI_START + 185)
+#define HSDDRX_EBI1_IRQ                                (GIC_SPI_START + 186)
+#define SDC5_BAM_IRQ                           (GIC_SPI_START + 187)
+#define SDC5_IRQ_0                             (GIC_SPI_START + 188)
+#define INT_UART9DM_IRQ                                (GIC_SPI_START + 189)
+#define GSBI9_QUP_IRQ                          (GIC_SPI_START + 190)
+#define INT_UART10DM_IRQ                       (GIC_SPI_START + 191)
+#define GSBI10_QUP_IRQ                         (GIC_SPI_START + 192)
+#define INT_UART11DM_IRQ                       (GIC_SPI_START + 193)
+#define GSBI11_QUP_IRQ                         (GIC_SPI_START + 194)
+#define INT_UART12DM_IRQ                       (GIC_SPI_START + 195)
+#define GSBI12_QUP_IRQ                         (GIC_SPI_START + 196)
+/*SPI 197 to 216 arent used in 8x60*/
+#define SMPSS_SPARE_1                          (GIC_SPI_START + 217)
+#define SMPSS_SPARE_2                          (GIC_SPI_START + 218)
+#define SMPSS_SPARE_3                          (GIC_SPI_START + 219)
+#define SMPSS_SPARE_4                          (GIC_SPI_START + 220)
+#define SMPSS_SPARE_5                          (GIC_SPI_START + 221)
+#define SMPSS_SPARE_6                          (GIC_SPI_START + 222)
+#define SMPSS_SPARE_7                          (GIC_SPI_START + 223)
+
+#define NR_GPIO_IRQS 173
+#define NR_MSM_IRQS 256
+#define NR_BOARD_IRQS 0
+
+#endif
index 164d355c96ea99d5a9b884de18b201f4461054f4..8679a45647447c213902c297efd953aabba7ecba 100644 (file)
@@ -24,6 +24,8 @@
 #elif defined(CONFIG_ARCH_QSD8X50)
 #include "irqs-8x50.h"
 #include "sirc.h"
+#elif defined(CONFIG_ARCH_MSM8X60)
+#include "irqs-8x60.h"
 #elif defined(CONFIG_ARCH_MSM_ARM11)
 #include "irqs-7x00.h"
 #else
index 50c7847e6002d3311b265c514f471ee39ad371ce..070e17d237f1926916391a56822d2cc6b8c3d444 100644 (file)
@@ -23,6 +23,8 @@
 #define PHYS_OFFSET            UL(0x20000000)
 #elif defined(CONFIG_ARCH_MSM7X30)
 #define PHYS_OFFSET            UL(0x00200000)
+#elif defined(CONFIG_ARCH_MSM8X60)
+#define PHYS_OFFSET            UL(0x40200000)
 #else
 #define PHYS_OFFSET            UL(0x10000000)
 #endif
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h b/arch/arm/mach-msm/include/mach/msm_iomap-8x60.h
new file mode 100644 (file)
index 0000000..45bab50
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * The MSM peripherals are spread all over across 768MB of physical
+ * space, which makes just having a simple IO_ADDRESS macro to slide
+ * them into the right virtual location rough.  Instead, we will
+ * provide a master phys->virt mapping for peripherals here.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_IOMAP_8X60_H
+#define __ASM_ARCH_MSM_IOMAP_8X60_H
+
+/* Physical base address and size of peripherals.
+ * Ordered by the virtual base addresses they will be mapped at.
+ *
+ * MSM_VIC_BASE must be an value that can be loaded via a "mov"
+ * instruction, otherwise entry-macro.S will not compile.
+ *
+ * If you add or remove entries here, you'll want to edit the
+ * msm_io_desc array in arch/arm/mach-msm/io.c to reflect your
+ * changes.
+ *
+ */
+
+#define MSM_QGIC_DIST_BASE     IOMEM(0xF0000000)
+#define MSM_QGIC_DIST_PHYS     0x02080000
+#define MSM_QGIC_DIST_SIZE     SZ_4K
+
+#define MSM_QGIC_CPU_BASE      IOMEM(0xF0001000)
+#define MSM_QGIC_CPU_PHYS      0x02081000
+#define MSM_QGIC_CPU_SIZE      SZ_4K
+
+#define MSM_ACC_BASE           IOMEM(0xF0002000)
+#define MSM_ACC_PHYS           0x02001000
+#define MSM_ACC_SIZE           SZ_4K
+
+#define MSM_GCC_BASE           IOMEM(0xF0003000)
+#define MSM_GCC_PHYS           0x02082000
+#define MSM_GCC_SIZE           SZ_4K
+
+#define MSM_TLMM_BASE          IOMEM(0xF0004000)
+#define MSM_TLMM_PHYS          0x00800000
+#define MSM_TLMM_SIZE          SZ_16K
+
+#define MSM_SHARED_RAM_BASE    IOMEM(0xF0100000)
+#define MSM_SHARED_RAM_SIZE    SZ_1M
+
+#define MSM_TMR_BASE           IOMEM(0xF0200000)
+#define MSM_TMR_PHYS           0x02000000
+#define MSM_TMR_SIZE           (SZ_1M)
+
+#define MSM_GPT_BASE           (MSM_TMR_BASE + 0x4)
+#define MSM_DGT_BASE           (MSM_TMR_BASE + 0x24)
+
+#define MSM_IOMMU_JPEGD_PHYS   0x07300000
+#define MSM_IOMMU_JPEGD_SIZE   SZ_1M
+
+#define MSM_IOMMU_VPE_PHYS     0x07400000
+#define MSM_IOMMU_VPE_SIZE     SZ_1M
+
+#define MSM_IOMMU_MDP0_PHYS    0x07500000
+#define MSM_IOMMU_MDP0_SIZE    SZ_1M
+
+#define MSM_IOMMU_MDP1_PHYS    0x07600000
+#define MSM_IOMMU_MDP1_SIZE    SZ_1M
+
+#define MSM_IOMMU_ROT_PHYS     0x07700000
+#define MSM_IOMMU_ROT_SIZE     SZ_1M
+
+#define MSM_IOMMU_IJPEG_PHYS   0x07800000
+#define MSM_IOMMU_IJPEG_SIZE   SZ_1M
+
+#define MSM_IOMMU_VFE_PHYS     0x07900000
+#define MSM_IOMMU_VFE_SIZE     SZ_1M
+
+#define MSM_IOMMU_VCODEC_A_PHYS        0x07A00000
+#define MSM_IOMMU_VCODEC_A_SIZE        SZ_1M
+
+#define MSM_IOMMU_VCODEC_B_PHYS        0x07B00000
+#define MSM_IOMMU_VCODEC_B_SIZE        SZ_1M
+
+#define MSM_IOMMU_GFX3D_PHYS   0x07C00000
+#define MSM_IOMMU_GFX3D_SIZE   SZ_1M
+
+#define MSM_IOMMU_GFX2D0_PHYS  0x07D00000
+#define MSM_IOMMU_GFX2D0_SIZE  SZ_1M
+
+#endif
index e6b1821cc4ea130e0266d83191e95195694ee9d4..8e24dd8121397871de5bc3f8ee4a5d5769bca8f6 100644 (file)
 #include "msm_iomap-7x30.h"
 #elif defined(CONFIG_ARCH_QSD8X50)
 #include "msm_iomap-8x50.h"
+#elif defined(CONFIG_ARCH_MSM8X60)
+#include "msm_iomap-8x60.h"
 #else
 #include "msm_iomap-7x00.h"
 #endif
 
+
+
 #endif
diff --git a/arch/arm/mach-msm/include/mach/smp.h b/arch/arm/mach-msm/include/mach/smp.h
new file mode 100644 (file)
index 0000000..3ff7bf5
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Code Aurora nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __ASM_ARCH_MSM_SMP_H
+#define __ASM_ARCH_MSM_SMP_H
+
+#include <asm/hardware/gic.h>
+
+static inline void smp_cross_call(const struct cpumask *mask)
+{
+       gic_raise_softirq(mask, 1);
+}
+
+#endif
index 05f81fd8623c2534a680a2be78bf824e3673e43b..31a32ad062dcd7eee3c280aa91e63c55ea11cf64 100644 (file)
@@ -16,7 +16,7 @@
 #ifndef __ASM_ARCH_MSM_VMALLOC_H
 #define __ASM_ARCH_MSM_VMALLOC_H
 
-#define VMALLOC_END      (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END      0xd0000000
 
 #endif
 
index 1c05060b5f3b40545dce99453d97f55500c69f6d..d36b61074146eb35aa862f9c0ff46c619840c9bf 100644 (file)
@@ -100,6 +100,21 @@ void __init msm_map_qsd8x50_io(void)
 }
 #endif /* CONFIG_ARCH_QSD8X50 */
 
+#ifdef CONFIG_ARCH_MSM8X60
+static struct map_desc msm8x60_io_desc[] __initdata = {
+       MSM_DEVICE(QGIC_DIST),
+       MSM_DEVICE(QGIC_CPU),
+       MSM_DEVICE(TMR),
+       MSM_DEVICE(ACC),
+       MSM_DEVICE(GCC),
+};
+
+void __init msm_map_msm8x60_io(void)
+{
+       iotable_init(msm8x60_io_desc, ARRAY_SIZE(msm8x60_io_desc));
+}
+#endif /* CONFIG_ARCH_MSM8X60 */
+
 #ifdef CONFIG_ARCH_MSM7X30
 static struct map_desc msm7x30_io_desc[] __initdata = {
        MSM_DEVICE(VIC),
diff --git a/arch/arm/mach-msm/iommu.c b/arch/arm/mach-msm/iommu.c
new file mode 100644 (file)
index 0000000..f71747d
--- /dev/null
@@ -0,0 +1,597 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/iommu.h>
+
+#include <asm/cacheflush.h>
+#include <asm/sizes.h>
+
+#include <mach/iommu_hw-8xxx.h>
+#include <mach/iommu.h>
+
+DEFINE_SPINLOCK(msm_iommu_lock);
+
+struct msm_priv {
+       unsigned long *pgtable;
+       struct list_head list_attached;
+};
+
+static void __flush_iotlb(struct iommu_domain *domain)
+{
+       struct msm_priv *priv = domain->priv;
+       struct msm_iommu_drvdata *iommu_drvdata;
+       struct msm_iommu_ctx_drvdata *ctx_drvdata;
+
+#ifndef CONFIG_IOMMU_PGTABLES_L2
+       unsigned long *fl_table = priv->pgtable;
+       int i;
+
+       dmac_flush_range(fl_table, fl_table + SZ_16K);
+
+       for (i = 0; i < NUM_FL_PTE; i++)
+               if ((fl_table[i] & 0x03) == FL_TYPE_TABLE) {
+                       void *sl_table = __va(fl_table[i] & FL_BASE_MASK);
+                       dmac_flush_range(sl_table, sl_table + SZ_4K);
+               }
+#endif
+
+       list_for_each_entry(ctx_drvdata, &priv->list_attached, attached_elm) {
+               if (!ctx_drvdata->pdev || !ctx_drvdata->pdev->dev.parent)
+                       BUG();
+
+               iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+               SET_CTX_TLBIALL(iommu_drvdata->base, ctx_drvdata->num, 0);
+       }
+}
+
+static void __reset_context(void __iomem *base, int ctx)
+{
+       SET_BPRCOSH(base, ctx, 0);
+       SET_BPRCISH(base, ctx, 0);
+       SET_BPRCNSH(base, ctx, 0);
+       SET_BPSHCFG(base, ctx, 0);
+       SET_BPMTCFG(base, ctx, 0);
+       SET_ACTLR(base, ctx, 0);
+       SET_SCTLR(base, ctx, 0);
+       SET_FSRRESTORE(base, ctx, 0);
+       SET_TTBR0(base, ctx, 0);
+       SET_TTBR1(base, ctx, 0);
+       SET_TTBCR(base, ctx, 0);
+       SET_BFBCR(base, ctx, 0);
+       SET_PAR(base, ctx, 0);
+       SET_FAR(base, ctx, 0);
+       SET_CTX_TLBIALL(base, ctx, 0);
+       SET_TLBFLPTER(base, ctx, 0);
+       SET_TLBSLPTER(base, ctx, 0);
+       SET_TLBLKCR(base, ctx, 0);
+       SET_PRRR(base, ctx, 0);
+       SET_NMRR(base, ctx, 0);
+       SET_CONTEXTIDR(base, ctx, 0);
+}
+
+static void __program_context(void __iomem *base, int ctx, phys_addr_t pgtable)
+{
+       __reset_context(base, ctx);
+
+       /* Set up HTW mode */
+       /* TLB miss configuration: perform HTW on miss */
+       SET_TLBMCFG(base, ctx, 0x3);
+
+       /* V2P configuration: HTW for access */
+       SET_V2PCFG(base, ctx, 0x3);
+
+       SET_TTBCR(base, ctx, 0);
+       SET_TTBR0_PA(base, ctx, (pgtable >> 14));
+
+       /* Invalidate the TLB for this context */
+       SET_CTX_TLBIALL(base, ctx, 0);
+
+       /* Set interrupt number to "secure" interrupt */
+       SET_IRPTNDX(base, ctx, 0);
+
+       /* Enable context fault interrupt */
+       SET_CFEIE(base, ctx, 1);
+
+       /* Stall access on a context fault and let the handler deal with it */
+       SET_CFCFG(base, ctx, 1);
+
+       /* Redirect all cacheable requests to L2 slave port. */
+       SET_RCISH(base, ctx, 1);
+       SET_RCOSH(base, ctx, 1);
+       SET_RCNSH(base, ctx, 1);
+
+       /* Turn on TEX Remap */
+       SET_TRE(base, ctx, 1);
+
+       /* Do not configure PRRR / NMRR on the IOMMU for now. We will assume
+        * TEX class 0 for everything until attributes are properly worked out
+        */
+       SET_PRRR(base, ctx, 0);
+       SET_NMRR(base, ctx, 0);
+
+       /* Turn on BFB prefetch */
+       SET_BFBDFE(base, ctx, 1);
+
+#ifdef CONFIG_IOMMU_PGTABLES_L2
+       /* Configure page tables as inner-cacheable and shareable to reduce
+        * the TLB miss penalty.
+        */
+       SET_TTBR0_SH(base, ctx, 1);
+       SET_TTBR1_SH(base, ctx, 1);
+
+       SET_TTBR0_NOS(base, ctx, 1);
+       SET_TTBR1_NOS(base, ctx, 1);
+
+       SET_TTBR0_IRGNH(base, ctx, 0); /* WB, WA */
+       SET_TTBR0_IRGNL(base, ctx, 1);
+
+       SET_TTBR1_IRGNH(base, ctx, 0); /* WB, WA */
+       SET_TTBR1_IRGNL(base, ctx, 1);
+
+       SET_TTBR0_ORGN(base, ctx, 1); /* WB, WA */
+       SET_TTBR1_ORGN(base, ctx, 1); /* WB, WA */
+#endif
+
+       /* Enable the MMU */
+       SET_M(base, ctx, 1);
+}
+
+static int msm_iommu_domain_init(struct iommu_domain *domain)
+{
+       struct msm_priv *priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+
+       if (!priv)
+               goto fail_nomem;
+
+       INIT_LIST_HEAD(&priv->list_attached);
+       priv->pgtable = (unsigned long *)__get_free_pages(GFP_KERNEL,
+                                                         get_order(SZ_16K));
+
+       if (!priv->pgtable)
+               goto fail_nomem;
+
+       memset(priv->pgtable, 0, SZ_16K);
+       domain->priv = priv;
+       return 0;
+
+fail_nomem:
+       kfree(priv);
+       return -ENOMEM;
+}
+
+static void msm_iommu_domain_destroy(struct iommu_domain *domain)
+{
+       struct msm_priv *priv;
+       unsigned long flags;
+       unsigned long *fl_table;
+       int i;
+
+       spin_lock_irqsave(&msm_iommu_lock, flags);
+       priv = domain->priv;
+       domain->priv = NULL;
+
+       if (priv) {
+               fl_table = priv->pgtable;
+
+               for (i = 0; i < NUM_FL_PTE; i++)
+                       if ((fl_table[i] & 0x03) == FL_TYPE_TABLE)
+                               free_page((unsigned long) __va(((fl_table[i]) &
+                                                               FL_BASE_MASK)));
+
+               free_pages((unsigned long)priv->pgtable, get_order(SZ_16K));
+               priv->pgtable = NULL;
+       }
+
+       kfree(priv);
+       spin_unlock_irqrestore(&msm_iommu_lock, flags);
+}
+
+static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev)
+{
+       struct msm_priv *priv;
+       struct msm_iommu_ctx_dev *ctx_dev;
+       struct msm_iommu_drvdata *iommu_drvdata;
+       struct msm_iommu_ctx_drvdata *ctx_drvdata;
+       struct msm_iommu_ctx_drvdata *tmp_drvdata;
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&msm_iommu_lock, flags);
+
+       priv = domain->priv;
+
+       if (!priv || !dev) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       iommu_drvdata = dev_get_drvdata(dev->parent);
+       ctx_drvdata = dev_get_drvdata(dev);
+       ctx_dev = dev->platform_data;
+
+       if (!iommu_drvdata || !ctx_drvdata || !ctx_dev) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       list_for_each_entry(tmp_drvdata, &priv->list_attached, attached_elm)
+               if (tmp_drvdata == ctx_drvdata) {
+                       ret = -EBUSY;
+                       goto fail;
+               }
+
+       __program_context(iommu_drvdata->base, ctx_dev->num,
+                         __pa(priv->pgtable));
+
+       list_add(&(ctx_drvdata->attached_elm), &priv->list_attached);
+       __flush_iotlb(domain);
+
+fail:
+       spin_unlock_irqrestore(&msm_iommu_lock, flags);
+       return ret;
+}
+
+static void msm_iommu_detach_dev(struct iommu_domain *domain,
+                                struct device *dev)
+{
+       struct msm_priv *priv;
+       struct msm_iommu_ctx_dev *ctx_dev;
+       struct msm_iommu_drvdata *iommu_drvdata;
+       struct msm_iommu_ctx_drvdata *ctx_drvdata;
+       unsigned long flags;
+
+       spin_lock_irqsave(&msm_iommu_lock, flags);
+       priv = domain->priv;
+
+       if (!priv || !dev)
+               goto fail;
+
+       iommu_drvdata = dev_get_drvdata(dev->parent);
+       ctx_drvdata = dev_get_drvdata(dev);
+       ctx_dev = dev->platform_data;
+
+       if (!iommu_drvdata || !ctx_drvdata || !ctx_dev)
+               goto fail;
+
+       __flush_iotlb(domain);
+       __reset_context(iommu_drvdata->base, ctx_dev->num);
+       list_del_init(&ctx_drvdata->attached_elm);
+
+fail:
+       spin_unlock_irqrestore(&msm_iommu_lock, flags);
+}
+
+static int msm_iommu_map(struct iommu_domain *domain, unsigned long va,
+                        phys_addr_t pa, int order, int prot)
+{
+       struct msm_priv *priv;
+       unsigned long flags;
+       unsigned long *fl_table;
+       unsigned long *fl_pte;
+       unsigned long fl_offset;
+       unsigned long *sl_table;
+       unsigned long *sl_pte;
+       unsigned long sl_offset;
+       size_t len = 0x1000UL << order;
+       int ret = 0;
+
+       spin_lock_irqsave(&msm_iommu_lock, flags);
+       priv = domain->priv;
+
+       if (!priv) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       fl_table = priv->pgtable;
+
+       if (len != SZ_16M && len != SZ_1M &&
+           len != SZ_64K && len != SZ_4K) {
+               pr_debug("Bad size: %d\n", len);
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       if (!fl_table) {
+               pr_debug("Null page table\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       fl_offset = FL_OFFSET(va);      /* Upper 12 bits */
+       fl_pte = fl_table + fl_offset;  /* int pointers, 4 bytes */
+
+       if (len == SZ_16M) {
+               int i = 0;
+               for (i = 0; i < 16; i++)
+                       *(fl_pte+i) = (pa & 0xFF000000) | FL_SUPERSECTION |
+                                 FL_AP_READ | FL_AP_WRITE | FL_TYPE_SECT |
+                                 FL_SHARED;
+       }
+
+       if (len == SZ_1M)
+               *fl_pte = (pa & 0xFFF00000) | FL_AP_READ | FL_AP_WRITE |
+                                               FL_TYPE_SECT | FL_SHARED;
+
+       /* Need a 2nd level table */
+       if ((len == SZ_4K || len == SZ_64K) && (*fl_pte) == 0) {
+               unsigned long *sl;
+               sl = (unsigned long *) __get_free_pages(GFP_KERNEL,
+                                                       get_order(SZ_4K));
+
+               if (!sl) {
+                       pr_debug("Could not allocate second level table\n");
+                       ret = -ENOMEM;
+                       goto fail;
+               }
+
+               memset(sl, 0, SZ_4K);
+               *fl_pte = ((((int)__pa(sl)) & FL_BASE_MASK) | FL_TYPE_TABLE);
+       }
+
+       sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
+       sl_offset = SL_OFFSET(va);
+       sl_pte = sl_table + sl_offset;
+
+
+       if (len == SZ_4K)
+               *sl_pte = (pa & SL_BASE_MASK_SMALL) | SL_AP0 | SL_AP1 |
+                                         SL_SHARED | SL_TYPE_SMALL;
+
+       if (len == SZ_64K) {
+               int i;
+
+               for (i = 0; i < 16; i++)
+                       *(sl_pte+i) = (pa & SL_BASE_MASK_LARGE) | SL_AP0 |
+                                           SL_AP1 | SL_SHARED | SL_TYPE_LARGE;
+       }
+
+       __flush_iotlb(domain);
+fail:
+       spin_unlock_irqrestore(&msm_iommu_lock, flags);
+       return ret;
+}
+
+static int msm_iommu_unmap(struct iommu_domain *domain, unsigned long va,
+                           int order)
+{
+       struct msm_priv *priv;
+       unsigned long flags;
+       unsigned long *fl_table;
+       unsigned long *fl_pte;
+       unsigned long fl_offset;
+       unsigned long *sl_table;
+       unsigned long *sl_pte;
+       unsigned long sl_offset;
+       size_t len = 0x1000UL << order;
+       int i, ret = 0;
+
+       spin_lock_irqsave(&msm_iommu_lock, flags);
+
+       priv = domain->priv;
+
+       if (!priv) {
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       fl_table = priv->pgtable;
+
+       if (len != SZ_16M && len != SZ_1M &&
+           len != SZ_64K && len != SZ_4K) {
+               pr_debug("Bad length: %d\n", len);
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       if (!fl_table) {
+               pr_debug("Null page table\n");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       fl_offset = FL_OFFSET(va);      /* Upper 12 bits */
+       fl_pte = fl_table + fl_offset;  /* int pointers, 4 bytes */
+
+       if (*fl_pte == 0) {
+               pr_debug("First level PTE is 0\n");
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       /* Unmap supersection */
+       if (len == SZ_16M)
+               for (i = 0; i < 16; i++)
+                       *(fl_pte+i) = 0;
+
+       if (len == SZ_1M)
+               *fl_pte = 0;
+
+       sl_table = (unsigned long *) __va(((*fl_pte) & FL_BASE_MASK));
+       sl_offset = SL_OFFSET(va);
+       sl_pte = sl_table + sl_offset;
+
+       if (len == SZ_64K) {
+               for (i = 0; i < 16; i++)
+                       *(sl_pte+i) = 0;
+       }
+
+       if (len == SZ_4K)
+               *sl_pte = 0;
+
+       if (len == SZ_4K || len == SZ_64K) {
+               int used = 0;
+
+               for (i = 0; i < NUM_SL_PTE; i++)
+                       if (sl_table[i])
+                               used = 1;
+               if (!used) {
+                       free_page((unsigned long)sl_table);
+                       *fl_pte = 0;
+               }
+       }
+
+       __flush_iotlb(domain);
+fail:
+       spin_unlock_irqrestore(&msm_iommu_lock, flags);
+       return ret;
+}
+
+static phys_addr_t msm_iommu_iova_to_phys(struct iommu_domain *domain,
+                                         unsigned long va)
+{
+       struct msm_priv *priv;
+       struct msm_iommu_drvdata *iommu_drvdata;
+       struct msm_iommu_ctx_drvdata *ctx_drvdata;
+       unsigned int par;
+       unsigned long flags;
+       void __iomem *base;
+       phys_addr_t ret = 0;
+       int ctx;
+
+       spin_lock_irqsave(&msm_iommu_lock, flags);
+
+       priv = domain->priv;
+       if (list_empty(&priv->list_attached))
+               goto fail;
+
+       ctx_drvdata = list_entry(priv->list_attached.next,
+                                struct msm_iommu_ctx_drvdata, attached_elm);
+       iommu_drvdata = dev_get_drvdata(ctx_drvdata->pdev->dev.parent);
+
+       base = iommu_drvdata->base;
+       ctx = ctx_drvdata->num;
+
+       /* Invalidate context TLB */
+       SET_CTX_TLBIALL(base, ctx, 0);
+       SET_V2PPR_VA(base, ctx, va >> V2Pxx_VA_SHIFT);
+
+       if (GET_FAULT(base, ctx))
+               goto fail;
+
+       par = GET_PAR(base, ctx);
+
+       /* We are dealing with a supersection */
+       if (GET_NOFAULT_SS(base, ctx))
+               ret = (par & 0xFF000000) | (va & 0x00FFFFFF);
+       else    /* Upper 20 bits from PAR, lower 12 from VA */
+               ret = (par & 0xFFFFF000) | (va & 0x00000FFF);
+
+fail:
+       spin_unlock_irqrestore(&msm_iommu_lock, flags);
+       return ret;
+}
+
+static int msm_iommu_domain_has_cap(struct iommu_domain *domain,
+                                   unsigned long cap)
+{
+       return 0;
+}
+
+static void print_ctx_regs(void __iomem *base, int ctx)
+{
+       unsigned int fsr = GET_FSR(base, ctx);
+       pr_err("FAR    = %08x    PAR    = %08x\n",
+              GET_FAR(base, ctx), GET_PAR(base, ctx));
+       pr_err("FSR    = %08x [%s%s%s%s%s%s%s%s%s%s]\n", fsr,
+                       (fsr & 0x02) ? "TF " : "",
+                       (fsr & 0x04) ? "AFF " : "",
+                       (fsr & 0x08) ? "APF " : "",
+                       (fsr & 0x10) ? "TLBMF " : "",
+                       (fsr & 0x20) ? "HTWDEEF " : "",
+                       (fsr & 0x40) ? "HTWSEEF " : "",
+                       (fsr & 0x80) ? "MHF " : "",
+                       (fsr & 0x10000) ? "SL " : "",
+                       (fsr & 0x40000000) ? "SS " : "",
+                       (fsr & 0x80000000) ? "MULTI " : "");
+
+       pr_err("FSYNR0 = %08x    FSYNR1 = %08x\n",
+              GET_FSYNR0(base, ctx), GET_FSYNR1(base, ctx));
+       pr_err("TTBR0  = %08x    TTBR1  = %08x\n",
+              GET_TTBR0(base, ctx), GET_TTBR1(base, ctx));
+       pr_err("SCTLR  = %08x    ACTLR  = %08x\n",
+              GET_SCTLR(base, ctx), GET_ACTLR(base, ctx));
+       pr_err("PRRR   = %08x    NMRR   = %08x\n",
+              GET_PRRR(base, ctx), GET_NMRR(base, ctx));
+}
+
+irqreturn_t msm_iommu_fault_handler(int irq, void *dev_id)
+{
+       struct msm_iommu_drvdata *drvdata = dev_id;
+       void __iomem *base;
+       unsigned int fsr = 0;
+       int ncb = 0, i = 0;
+
+       spin_lock(&msm_iommu_lock);
+
+       if (!drvdata) {
+               pr_err("Invalid device ID in context interrupt handler\n");
+               goto fail;
+       }
+
+       base = drvdata->base;
+
+       pr_err("===== WOAH! =====\n");
+       pr_err("Unexpected IOMMU page fault!\n");
+       pr_err("base = %08x\n", (unsigned int) base);
+
+       ncb = GET_NCB(base)+1;
+       for (i = 0; i < ncb; i++) {
+               fsr = GET_FSR(base, i);
+               if (fsr) {
+                       pr_err("Fault occurred in context %d.\n", i);
+                       pr_err("Interesting registers:\n");
+                       print_ctx_regs(base, i);
+                       SET_FSR(base, i, 0x4000000F);
+               }
+       }
+fail:
+       spin_unlock(&msm_iommu_lock);
+       return 0;
+}
+
+static struct iommu_ops msm_iommu_ops = {
+       .domain_init = msm_iommu_domain_init,
+       .domain_destroy = msm_iommu_domain_destroy,
+       .attach_dev = msm_iommu_attach_dev,
+       .detach_dev = msm_iommu_detach_dev,
+       .map = msm_iommu_map,
+       .unmap = msm_iommu_unmap,
+       .iova_to_phys = msm_iommu_iova_to_phys,
+       .domain_has_cap = msm_iommu_domain_has_cap
+};
+
+static int msm_iommu_init(void)
+{
+       register_iommu(&msm_iommu_ops);
+       return 0;
+}
+
+subsys_initcall(msm_iommu_init);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");
diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
new file mode 100644 (file)
index 0000000..c33ae78
--- /dev/null
@@ -0,0 +1,374 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/iommu.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include <mach/iommu_hw-8xxx.h>
+#include <mach/iommu.h>
+
+struct iommu_ctx_iter_data {
+       /* input */
+       const char *name;
+
+       /* output */
+       struct device *dev;
+};
+
+static struct platform_device *msm_iommu_root_dev;
+
+static int each_iommu_ctx(struct device *dev, void *data)
+{
+       struct iommu_ctx_iter_data *res = data;
+       struct msm_iommu_ctx_dev *c = dev->platform_data;
+
+       if (!res || !c || !c->name || !res->name)
+               return -EINVAL;
+
+       if (!strcmp(res->name, c->name)) {
+               res->dev = dev;
+               return 1;
+       }
+       return 0;
+}
+
+static int each_iommu(struct device *dev, void *data)
+{
+       return device_for_each_child(dev, data, each_iommu_ctx);
+}
+
+struct device *msm_iommu_get_ctx(const char *ctx_name)
+{
+       struct iommu_ctx_iter_data r;
+       int found;
+
+       if (!msm_iommu_root_dev) {
+               pr_err("No root IOMMU device.\n");
+               goto fail;
+       }
+
+       r.name = ctx_name;
+       found = device_for_each_child(&msm_iommu_root_dev->dev, &r, each_iommu);
+
+       if (!found) {
+               pr_err("Could not find context <%s>\n", ctx_name);
+               goto fail;
+       }
+
+       return r.dev;
+fail:
+       return NULL;
+}
+EXPORT_SYMBOL(msm_iommu_get_ctx);
+
+static void msm_iommu_reset(void __iomem *base)
+{
+       int ctx, ncb;
+
+       SET_RPUE(base, 0);
+       SET_RPUEIE(base, 0);
+       SET_ESRRESTORE(base, 0);
+       SET_TBE(base, 0);
+       SET_CR(base, 0);
+       SET_SPDMBE(base, 0);
+       SET_TESTBUSCR(base, 0);
+       SET_TLBRSW(base, 0);
+       SET_GLOBAL_TLBIALL(base, 0);
+       SET_RPU_ACR(base, 0);
+       SET_TLBLKCRWE(base, 1);
+       ncb = GET_NCB(base)+1;
+
+       for (ctx = 0; ctx < ncb; ctx++) {
+               SET_BPRCOSH(base, ctx, 0);
+               SET_BPRCISH(base, ctx, 0);
+               SET_BPRCNSH(base, ctx, 0);
+               SET_BPSHCFG(base, ctx, 0);
+               SET_BPMTCFG(base, ctx, 0);
+               SET_ACTLR(base, ctx, 0);
+               SET_SCTLR(base, ctx, 0);
+               SET_FSRRESTORE(base, ctx, 0);
+               SET_TTBR0(base, ctx, 0);
+               SET_TTBR1(base, ctx, 0);
+               SET_TTBCR(base, ctx, 0);
+               SET_BFBCR(base, ctx, 0);
+               SET_PAR(base, ctx, 0);
+               SET_FAR(base, ctx, 0);
+               SET_CTX_TLBIALL(base, ctx, 0);
+               SET_TLBFLPTER(base, ctx, 0);
+               SET_TLBSLPTER(base, ctx, 0);
+               SET_TLBLKCR(base, ctx, 0);
+               SET_PRRR(base, ctx, 0);
+               SET_NMRR(base, ctx, 0);
+               SET_CONTEXTIDR(base, ctx, 0);
+       }
+}
+
+static int msm_iommu_probe(struct platform_device *pdev)
+{
+       struct resource *r;
+       struct clk *iommu_clk;
+       struct msm_iommu_drvdata *drvdata;
+       struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;
+       void __iomem *regs_base;
+       resource_size_t len;
+       int ret = 0, ncb, nm2v, irq;
+
+       if (pdev->id != -1) {
+               drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+
+               if (!drvdata) {
+                       ret = -ENOMEM;
+                       goto fail;
+               }
+
+               if (!iommu_dev) {
+                       ret = -ENODEV;
+                       goto fail;
+               }
+
+               if (iommu_dev->clk_rate != 0) {
+                       iommu_clk = clk_get(&pdev->dev, "iommu_clk");
+
+                       if (IS_ERR(iommu_clk)) {
+                               ret = -ENODEV;
+                               goto fail;
+                       }
+
+                       if (iommu_dev->clk_rate > 0) {
+                               ret = clk_set_rate(iommu_clk,
+                                                       iommu_dev->clk_rate);
+                               if (ret) {
+                                       clk_put(iommu_clk);
+                                       goto fail;
+                               }
+                       }
+
+                       ret = clk_enable(iommu_clk);
+                       if (ret) {
+                               clk_put(iommu_clk);
+                               goto fail;
+                       }
+                       clk_put(iommu_clk);
+               }
+
+               r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                                "physbase");
+               if (!r) {
+                       ret = -ENODEV;
+                       goto fail;
+               }
+
+               len = r->end - r->start + 1;
+
+               r = request_mem_region(r->start, len, r->name);
+               if (!r) {
+                       pr_err("Could not request memory region: "
+                       "start=%p, len=%d\n", (void *) r->start, len);
+                       ret = -EBUSY;
+                       goto fail;
+               }
+
+               regs_base = ioremap(r->start, len);
+
+               if (!regs_base) {
+                       pr_err("Could not ioremap: start=%p, len=%d\n",
+                                (void *) r->start, len);
+                       ret = -EBUSY;
+                       goto fail;
+               }
+
+               irq = platform_get_irq_byname(pdev, "secure_irq");
+               if (irq < 0) {
+                       ret = -ENODEV;
+                       goto fail;
+               }
+
+               mb();
+
+               if (GET_IDR(regs_base) == 0) {
+                       pr_err("Invalid IDR value detected\n");
+                       ret = -ENODEV;
+                       goto fail;
+               }
+
+               ret = request_irq(irq, msm_iommu_fault_handler, 0,
+                               "msm_iommu_secure_irpt_handler", drvdata);
+               if (ret) {
+                       pr_err("Request IRQ %d failed with ret=%d\n", irq, ret);
+                       goto fail;
+               }
+
+               msm_iommu_reset(regs_base);
+               drvdata->base = regs_base;
+               drvdata->irq = irq;
+
+               nm2v = GET_NM2VCBMT((unsigned long) regs_base);
+               ncb = GET_NCB((unsigned long) regs_base);
+
+               pr_info("device %s mapped at %p, irq %d with %d ctx banks\n",
+                       iommu_dev->name, regs_base, irq, ncb+1);
+
+               platform_set_drvdata(pdev, drvdata);
+       } else
+               msm_iommu_root_dev = pdev;
+
+       return 0;
+
+fail:
+       kfree(drvdata);
+       return ret;
+}
+
+static int msm_iommu_remove(struct platform_device *pdev)
+{
+       struct msm_iommu_drvdata *drv = NULL;
+
+       drv = platform_get_drvdata(pdev);
+       if (drv) {
+               memset(drv, 0, sizeof(struct msm_iommu_drvdata));
+               kfree(drv);
+               platform_set_drvdata(pdev, NULL);
+       }
+       return 0;
+}
+
+static int msm_iommu_ctx_probe(struct platform_device *pdev)
+{
+       struct msm_iommu_ctx_dev *c = pdev->dev.platform_data;
+       struct msm_iommu_drvdata *drvdata;
+       struct msm_iommu_ctx_drvdata *ctx_drvdata = NULL;
+       int i, ret = 0;
+       if (!c || !pdev->dev.parent) {
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       drvdata = dev_get_drvdata(pdev->dev.parent);
+
+       if (!drvdata) {
+               ret = -ENODEV;
+               goto fail;
+       }
+
+       ctx_drvdata = kzalloc(sizeof(*ctx_drvdata), GFP_KERNEL);
+       if (!ctx_drvdata) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+       ctx_drvdata->num = c->num;
+       ctx_drvdata->pdev = pdev;
+
+       INIT_LIST_HEAD(&ctx_drvdata->attached_elm);
+       platform_set_drvdata(pdev, ctx_drvdata);
+
+       /* Program the M2V tables for this context */
+       for (i = 0; i < MAX_NUM_MIDS; i++) {
+               int mid = c->mids[i];
+               if (mid == -1)
+                       break;
+
+               SET_M2VCBR_N(drvdata->base, mid, 0);
+               SET_CBACR_N(drvdata->base, c->num, 0);
+
+               /* Set VMID = MID */
+               SET_VMID(drvdata->base, mid, mid);
+
+               /* Set the context number for that MID to this context */
+               SET_CBNDX(drvdata->base, mid, c->num);
+
+               /* Set MID associated with this context bank */
+               SET_CBVMID(drvdata->base, c->num, mid);
+
+               /* Set security bit override to be Non-secure */
+               SET_NSCFG(drvdata->base, mid, 3);
+       }
+
+       pr_info("context device %s with bank index %d\n", c->name, c->num);
+
+       return 0;
+fail:
+       kfree(ctx_drvdata);
+       return ret;
+}
+
+static int msm_iommu_ctx_remove(struct platform_device *pdev)
+{
+       struct msm_iommu_ctx_drvdata *drv = NULL;
+       drv = platform_get_drvdata(pdev);
+       if (drv) {
+               memset(drv, 0, sizeof(struct msm_iommu_ctx_drvdata));
+               kfree(drv);
+               platform_set_drvdata(pdev, NULL);
+       }
+       return 0;
+}
+
+static struct platform_driver msm_iommu_driver = {
+       .driver = {
+               .name   = "msm_iommu",
+       },
+       .probe          = msm_iommu_probe,
+       .remove         = msm_iommu_remove,
+};
+
+static struct platform_driver msm_iommu_ctx_driver = {
+       .driver = {
+               .name   = "msm_iommu_ctx",
+       },
+       .probe          = msm_iommu_ctx_probe,
+       .remove         = msm_iommu_ctx_remove,
+};
+
+static int msm_iommu_driver_init(void)
+{
+       int ret;
+       ret = platform_driver_register(&msm_iommu_driver);
+       if (ret != 0) {
+               pr_err("Failed to register IOMMU driver\n");
+               goto error;
+       }
+
+       ret = platform_driver_register(&msm_iommu_ctx_driver);
+       if (ret != 0) {
+               pr_err("Failed to register IOMMU context driver\n");
+               goto error;
+       }
+
+error:
+       return ret;
+}
+
+static void msm_iommu_driver_exit(void)
+{
+       platform_driver_unregister(&msm_iommu_ctx_driver);
+       platform_driver_unregister(&msm_iommu_driver);
+}
+
+subsys_initcall(msm_iommu_driver_init);
+module_exit(msm_iommu_driver_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stepan Moskovchenko <stepanm@codeaurora.org>");
index dec5ca622d7daf6963450f612d7062109cae6e92..7689848ec680d28a322040e9bf8e9c7764de27ac 100644 (file)
@@ -28,7 +28,6 @@
 #ifndef MSM_DGT_BASE
 #define MSM_DGT_BASE (MSM_GPT_BASE + 0x10)
 #endif
-#define MSM_DGT_SHIFT (5)
 
 #define TIMER_MATCH_VAL         0x0000
 #define TIMER_COUNT_VAL         0x0004
 #define TIMER_ENABLE_CLR_ON_MATCH_EN    2
 #define TIMER_ENABLE_EN                 1
 #define TIMER_CLEAR             0x000C
-
+#define DGT_CLK_CTL             0x0034
+enum {
+       DGT_CLK_CTL_DIV_1 = 0,
+       DGT_CLK_CTL_DIV_2 = 1,
+       DGT_CLK_CTL_DIV_3 = 2,
+       DGT_CLK_CTL_DIV_4 = 3,
+};
 #define CSR_PROTECTION          0x0020
 #define CSR_PROTECTION_EN               1
 
 #define GPT_HZ 32768
+
+#if defined(CONFIG_ARCH_QSD8X50)
+#define DGT_HZ (19200000 / 4) /* 19.2 MHz / 4 by default */
+#define MSM_DGT_SHIFT (0)
+#elif defined(CONFIG_ARCH_MSM7X30) || defined(CONFIG_ARCH_MSM8X60)
+#define DGT_HZ (24576000 / 4) /* 24.576 MHz (LPXO) / 4 by default */
+#define MSM_DGT_SHIFT (0)
+#else
 #define DGT_HZ 19200000 /* 19.2 MHz or 600 KHz after shift */
+#define MSM_DGT_SHIFT (5)
+#endif
 
 struct msm_clock {
        struct clock_event_device   clockevent;
@@ -170,6 +185,10 @@ static void __init msm_timer_init(void)
        int i;
        int res;
 
+#ifdef CONFIG_ARCH_MSM8X60
+       writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
+#endif
+
        for (i = 0; i < ARRAY_SIZE(msm_clocks); i++) {
                struct msm_clock *clock = &msm_clocks[i];
                struct clock_event_device *ce = &clock->clockevent;
index 61e5e583603b10f009f5a7ec6b6207806a0d29f4..29e390e89ff41b57c9c887d3acfeb917210b817e 100644 (file)
@@ -145,8 +145,6 @@ subsys_initcall(wxl_pci_init);
 
 MACHINE_START(TERASTATION_WXL, "Buffalo Nas WXL")
        /* Maintainer: Sebastien Requiem <sebastien@requiem.fr> */
-       .phys_io        = MV78XX0_REGS_PHYS_BASE,
-       .io_pg_offst    = ((MV78XX0_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = wxl_init,
        .map_io         = mv78xx0_map_io,
index efdabe04c69ef80bad21f5a5ad3a661741cbae79..207c95e403b95c04593a73d490db07570d65b93c 100644 (file)
@@ -93,8 +93,6 @@ subsys_initcall(db78x00_pci_init);
 
 MACHINE_START(DB78X00_BP, "Marvell DB-78x00-BP Development Board")
        /* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-       .phys_io        = MV78XX0_REGS_PHYS_BASE,
-       .io_pg_offst    = ((MV78XX0_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = db78x00_init,
        .map_io         = mv78xx0_map_io,
index cd81689c4621dad5bfa9b08d2b1a35bed5049b8a..04891428e48bcd9d4cc164679a8fbc0a77fff900 100644 (file)
@@ -8,12 +8,11 @@
 
 #include <mach/mv78xx0.h>
 
-       .macro  addruart, rx, tmp
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                                 @ MMU enabled?
-       ldreq   \rx, =MV78XX0_REGS_PHYS_BASE
-       ldrne   \rx, =MV78XX0_REGS_VIRT_BASE
-       orr     \rx, \rx, #0x00012000
+       .macro  addruart, rp, rv
+       ldr     \rp, =MV78XX0_REGS_PHYS_BASE
+       ldr     \rv, =MV78XX0_REGS_VIRT_BASE
+       orr     \rp, \rp, #0x00012000
+       orr     \rv, \rv, #0x00012000
        .endm
 
 #define UART_SHIFT     2
index e136b7a03355bc445c74cd626969acb73cedcc89..3511ad4d973b7218a6a9fa3669c8def6d649fc56 100644 (file)
@@ -78,8 +78,6 @@ subsys_initcall(rd78x00_pci_init);
 
 MACHINE_START(RD78X00_MASA, "Marvell RD-78x00-MASA Development Board")
        /* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-       .phys_io        = MV78XX0_REGS_PHYS_BASE,
-       .io_pg_offst    = ((MV78XX0_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = rd78x00_masa_init,
        .map_io         = mv78xx0_map_io,
index c71a7bc19284bf64b14f939f3094bfc501631240..aa57e35ce3cd2c097cd0af5bb8f56d75480c87bd 100644 (file)
@@ -12,6 +12,8 @@ config MACH_EUKREA_CPUIMX25
        select IMX_HAVE_PLATFORM_IMX_I2C
        select IMX_HAVE_PLATFORM_IMX_UART
        select IMX_HAVE_PLATFORM_MXC_NAND
+       select IMX_HAVE_PLATFORM_FLEXCAN
+       select IMX_HAVE_PLATFORM_ESDHC
        select MXC_ULPI if USB_ULPI
 
 choice
@@ -20,8 +22,8 @@ choice
        default MACH_EUKREA_MBIMXSD25_BASEBOARD
 
 config MACH_EUKREA_MBIMXSD25_BASEBOARD
-       prompt "Eukrea MBIMXSD development board"
-       bool
+       bool "Eukrea MBIMXSD development board"
+       select IMX_HAVE_PLATFORM_IMX_SSI
        help
          This adds board specific devices that can be found on Eukrea's
          MBIMXSD evaluation board.
index 40c7cc41cee372c906e3339f5da50f9e709f36df..9e4a5578c2fb9dc6a392aa07b5fb085dde900651 100644 (file)
@@ -72,7 +72,7 @@ unsigned long get_rate_arm(struct clk *clk)
        unsigned long rate = get_rate_mpll();
 
        if (cctl & (1 << 14))
-               rate = (rate * 3) >> 1;
+               rate = (rate * 3) >> 2;
 
        return rate / ((cctl >> 30) + 1);
 }
@@ -99,7 +99,7 @@ static unsigned long get_rate_per(int per)
        if (readl(CRM_BASE + 0x64) & (1 << per))
                fref = get_rate_upll();
        else
-               fref = get_rate_ipg(NULL);
+               fref = get_rate_ahb(NULL);
 
        return fref / (val + 1);
 }
@@ -139,6 +139,16 @@ static unsigned long get_rate_lcdc(struct clk *clk)
        return get_rate_per(7);
 }
 
+static unsigned long get_rate_esdhc1(struct clk *clk)
+{
+       return get_rate_per(3);
+}
+
+static unsigned long get_rate_esdhc2(struct clk *clk)
+{
+       return get_rate_per(4);
+}
+
 static unsigned long get_rate_csi(struct clk *clk)
 {
        return get_rate_per(0);
@@ -213,6 +223,12 @@ DEFINE_CLOCK(ssi2_per_clk, 0, CCM_CGCR0, 14, get_rate_ipg, NULL, NULL);
 DEFINE_CLOCK(cspi1_clk,  0, CCM_CGCR1,  5, get_rate_ipg, NULL, NULL);
 DEFINE_CLOCK(cspi2_clk,  0, CCM_CGCR1,  6, get_rate_ipg, NULL, NULL);
 DEFINE_CLOCK(cspi3_clk,  0, CCM_CGCR1,  7, get_rate_ipg, NULL, NULL);
+DEFINE_CLOCK(esdhc1_ahb_clk, 0, CCM_CGCR0, 21, get_rate_esdhc1,         NULL, NULL);
+DEFINE_CLOCK(esdhc1_per_clk, 0, CCM_CGCR0,  3, get_rate_esdhc1,         NULL,
+               &esdhc1_ahb_clk);
+DEFINE_CLOCK(esdhc2_ahb_clk, 0, CCM_CGCR0, 22, get_rate_esdhc2,         NULL, NULL);
+DEFINE_CLOCK(esdhc2_per_clk, 0, CCM_CGCR0,  4, get_rate_esdhc2,         NULL,
+               &esdhc2_ahb_clk);
 DEFINE_CLOCK(fec_ahb_clk, 0, CCM_CGCR0, 23, NULL,       NULL, NULL);
 DEFINE_CLOCK(lcdc_ahb_clk, 0, CCM_CGCR0, 24, NULL,      NULL, NULL);
 DEFINE_CLOCK(lcdc_per_clk, 0, CCM_CGCR0,  7, NULL,      NULL, &lcdc_ahb_clk);
@@ -238,10 +254,14 @@ DEFINE_CLOCK(lcdc_clk,     0, CCM_CGCR1, 29, get_rate_lcdc, NULL, &lcdc_per_clk);
 DEFINE_CLOCK(wdt_clk,    0, CCM_CGCR2, 19, get_rate_ipg, NULL,  NULL);
 DEFINE_CLOCK(ssi1_clk,  0, CCM_CGCR2, 11, get_rate_ssi1, NULL, &ssi1_per_clk);
 DEFINE_CLOCK(ssi2_clk,  1, CCM_CGCR2, 12, get_rate_ssi2, NULL, &ssi2_per_clk);
+DEFINE_CLOCK(esdhc1_clk,  0, CCM_CGCR1, 13, get_rate_esdhc1, NULL,
+               &esdhc1_per_clk);
+DEFINE_CLOCK(esdhc2_clk,  1, CCM_CGCR1, 14, get_rate_esdhc2, NULL,
+               &esdhc2_per_clk);
 DEFINE_CLOCK(audmux_clk, 0, CCM_CGCR1, 0, NULL, NULL, NULL);
 DEFINE_CLOCK(csi_clk,    0, CCM_CGCR1,  4, get_rate_csi, NULL,  &csi_per_clk);
 DEFINE_CLOCK(can1_clk,  0, CCM_CGCR1,  2, get_rate_ipg, NULL, NULL);
-DEFINE_CLOCK(can2_clk,  0, CCM_CGCR1,  3, get_rate_ipg, NULL, NULL);
+DEFINE_CLOCK(can2_clk,  1, CCM_CGCR1,  3, get_rate_ipg, NULL, NULL);
 
 #define _REGISTER_CLOCK(d, n, c)       \
        {                               \
@@ -261,9 +281,9 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk)
        _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
-       _REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
-       _REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
-       _REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
+       _REGISTER_CLOCK("imx25-cspi.0", NULL, cspi1_clk)
+       _REGISTER_CLOCK("imx25-cspi.1", NULL, cspi2_clk)
+       _REGISTER_CLOCK("imx25-cspi.2", NULL, cspi3_clk)
        _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk)
        _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk)
        _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm3_clk)
@@ -279,6 +299,8 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("imx-wdt.0", NULL, wdt_clk)
        _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
        _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
        _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk)
        _REGISTER_CLOCK(NULL, "audmux", audmux_clk)
        _REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
index d86a7c3ca8b0cf64c7b7cb69af2e7dc883194df0..93afa10b13cf929de543f5f3eea3b51dead77629 100644 (file)
@@ -9,35 +9,46 @@
 #include <mach/mx25.h>
 #include <mach/devices-common.h>
 
+extern const struct imx_fec_data imx25_fec_data __initconst;
+#define imx25_add_fec(pdata)   \
+       imx_add_fec(&imx25_fec_data, pdata)
+
 #define imx25_add_flexcan0(pdata)      \
        imx_add_flexcan(0, MX25_CAN1_BASE_ADDR, SZ_16K, MX25_INT_CAN1, pdata)
 #define imx25_add_flexcan1(pdata)      \
        imx_add_flexcan(1, MX25_CAN2_BASE_ADDR, SZ_16K, MX25_INT_CAN2, pdata)
 
-#define imx25_add_imx_i2c0(pdata)      \
-       imx_add_imx_i2c(0, MX25_I2C1_BASE_ADDR, SZ_16K, MX25_INT_I2C1, pdata)
-#define imx25_add_imx_i2c1(pdata)      \
-       imx_add_imx_i2c(1, MX25_I2C2_BASE_ADDR, SZ_16K, MX25_INT_I2C2, pdata)
-#define imx25_add_imx_i2c2(pdata)      \
-       imx_add_imx_i2c(2, MX25_I2C3_BASE_ADDR, SZ_16K, MX25_INT_I2C3, pdata)
-
-#define imx25_add_imx_uart0(pdata)     \
-       imx_add_imx_uart_1irq(0, MX25_UART1_BASE_ADDR, SZ_16K, MX25_INT_UART1, pdata)
-#define imx25_add_imx_uart1(pdata)     \
-       imx_add_imx_uart_1irq(1, MX25_UART2_BASE_ADDR, SZ_16K, MX25_INT_UART2, pdata)
-#define imx25_add_imx_uart2(pdata)     \
-       imx_add_imx_uart_1irq(2, MX25_UART3_BASE_ADDR, SZ_16K, MX25_INT_UART3, pdata)
-#define imx25_add_imx_uart3(pdata)     \
-       imx_add_imx_uart_1irq(3, MX25_UART4_BASE_ADDR, SZ_16K, MX25_INT_UART4, pdata)
-#define imx25_add_imx_uart4(pdata)     \
-       imx_add_imx_uart_1irq(4, MX25_UART5_BASE_ADDR, SZ_16K, MX25_INT_UART5, pdata)
+extern const struct imx_imx_i2c_data imx25_imx_i2c_data[] __initconst;
+#define imx25_add_imx_i2c(id, pdata)   \
+       imx_add_imx_i2c(&imx25_imx_i2c_data[id], pdata)
+#define imx25_add_imx_i2c0(pdata)      imx25_add_imx_i2c(0, pdata)
+#define imx25_add_imx_i2c1(pdata)      imx25_add_imx_i2c(1, pdata)
+#define imx25_add_imx_i2c2(pdata)      imx25_add_imx_i2c(2, pdata)
+
+extern const struct imx_imx_ssi_data imx25_imx_ssi_data[] __initconst;
+#define imx25_add_imx_ssi(id, pdata)   \
+       imx_add_imx_ssi(&imx25_imx_ssi_data[id], pdata)
+
+extern const struct imx_imx_uart_1irq_data imx25_imx_uart_data[] __initconst;
+#define imx25_add_imx_uart(id, pdata)  \
+       imx_add_imx_uart_1irq(&imx25_imx_uart_data[id], pdata)
+#define imx25_add_imx_uart0(pdata)     imx25_add_imx_uart(0, pdata)
+#define imx25_add_imx_uart1(pdata)     imx25_add_imx_uart(1, pdata)
+#define imx25_add_imx_uart2(pdata)     imx25_add_imx_uart(2, pdata)
+#define imx25_add_imx_uart3(pdata)     imx25_add_imx_uart(3, pdata)
+#define imx25_add_imx_uart4(pdata)     imx25_add_imx_uart(4, pdata)
 
+extern const struct imx_mxc_nand_data imx25_mxc_nand_data __initconst;
 #define imx25_add_mxc_nand(pdata)      \
-       imx_add_mxc_nand_v21(MX25_NFC_BASE_ADDR, MX25_INT_NANDFC, pdata)
-
-#define imx25_add_spi_imx0(pdata)      \
-       imx_add_spi_imx(0, MX25_CSPI1_BASE_ADDR, SZ_16K, MX25_INT_CSPI1, pdata)
-#define imx25_add_spi_imx1(pdata)      \
-       imx_add_spi_imx(1, MX25_CSPI2_BASE_ADDR, SZ_16K, MX25_INT_CSPI2, pdata)
-#define imx25_add_spi_imx2(pdata)      \
-       imx_add_spi_imx(2, MX25_CSPI3_BASE_ADDR, SZ_16K, MX25_INT_CSPI3, pdata)
+       imx_add_mxc_nand(&imx25_mxc_nand_data, pdata)
+
+extern const struct imx_spi_imx_data imx25_spi_imx_data[] __initconst;
+#define imx25_add_spi_imx(id, pdata)   \
+       imx_add_spi_imx(&imx25_spi_imx_data[id], pdata)
+#define imx25_add_spi_imx0(pdata)      imx25_add_spi_imx(0, pdata)
+#define imx25_add_spi_imx1(pdata)      imx25_add_spi_imx(1, pdata)
+#define imx25_add_spi_imx2(pdata)      imx25_add_spi_imx(2, pdata)
+
+extern const struct imx_esdhc_imx_data imx25_esdhc_data[] __initconst;
+#define imx25_add_esdhc(id, pdata)     \
+       imx_add_esdhc(&imx25_esdhc_data[id], pdata)
index 3468eb15b2367fd1a4c197bf76d3b59af4b3372a..1d0eb3e85941030d091fc6094bc955ae40035128 100644 (file)
@@ -208,26 +208,6 @@ int __init imx25_register_gpios(void)
        return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
 }
 
-static struct resource mx25_fec_resources[] = {
-       {
-               .start  = MX25_FEC_BASE_ADDR,
-               .end    = MX25_FEC_BASE_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM,
-       },
-       {
-               .start  = MX25_INT_FEC,
-               .end    = MX25_INT_FEC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mx25_fec_device = {
-       .name   = "fec",
-       .id     = 0,
-       .num_resources  = ARRAY_SIZE(mx25_fec_resources),
-       .resource       = mx25_fec_resources,
-};
-
 static struct resource mx25_rtc_resources[] = {
        {
                .start  = MX25_DRYICE_BASE_ADDR,
@@ -305,44 +285,6 @@ struct platform_device mx25_kpp_device = {
        .resource       = mx25_kpp_resources,
 };
 
-static struct resource imx_ssi_resources0[] = {
-       {
-               .start  = MX25_SSI1_BASE_ADDR,
-               .end    = MX25_SSI1_BASE_ADDR + 0x3fff,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = MX25_INT_SSI1,
-               .end    = MX25_INT_SSI1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct resource imx_ssi_resources1[] = {
-       {
-               .start  = MX25_SSI2_BASE_ADDR,
-               .end    = MX25_SSI2_BASE_ADDR + 0x3fff,
-               .flags  = IORESOURCE_MEM
-       }, {
-               .start  = MX25_INT_SSI2,
-               .end    = MX25_INT_SSI2,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device imx_ssi_device0 = {
-       .name = "imx-ssi",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(imx_ssi_resources0),
-       .resource = imx_ssi_resources0,
-};
-
-struct platform_device imx_ssi_device1 = {
-       .name = "imx-ssi",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(imx_ssi_resources1),
-       .resource = imx_ssi_resources1,
-};
-
 static struct resource mx25_csi_resources[] = {
        {
                .start  = MX25_CSI_BASE_ADDR,
index 4aceb68e35a77003e11505dfb3eca338006263fb..7b70a43c3a4be3bccf692c4dea2e62f2af1615f5 100644 (file)
@@ -6,11 +6,8 @@ extern struct platform_device mxc_pwm_device1;
 extern struct platform_device mxc_pwm_device2;
 extern struct platform_device mxc_pwm_device3;
 extern struct platform_device mxc_keypad_device;
-extern struct platform_device mx25_fec_device;
 extern struct platform_device mx25_rtc_device;
 extern struct platform_device mx25_fb_device;
 extern struct platform_device mxc_wdt;
 extern struct platform_device mx25_kpp_device;
-extern struct platform_device imx_ssi_device0;
-extern struct platform_device imx_ssi_device1;
 extern struct platform_device mx25_csi_device;
index 4aaadc753d3e6ff4e60b88c17e62e5b3c0cfb812..e765ac5d9a08ad7c501d10e3e61682bfb45ead78 100644 (file)
@@ -34,7 +34,6 @@
 #include <mach/mx25.h>
 #include <mach/imx-uart.h>
 #include <mach/imxfb.h>
-#include <mach/ssi.h>
 #include <mach/audmux.h>
 
 #include "devices-imx25.h"
@@ -90,6 +89,9 @@ static struct pad_desc eukrea_mbimxsd_pads[] = {
        MX25_PAD_KPP_COL2__AUD5_TXC,
        MX25_PAD_KPP_COL1__AUD5_RXD,
        MX25_PAD_KPP_COL0__AUD5_TXD,
+       /* CAN */
+       MX25_PAD_GPIO_D__CAN2_RX,
+       MX25_PAD_GPIO_C__CAN2_TX,
 };
 
 #define GPIO_LED1      83
@@ -114,6 +116,38 @@ static struct imx_fb_videomode eukrea_mximxsd_modes[] = {
                },
                .bpp    = 16,
                .pcr    = 0xCAD08B80,
+       }, {
+               .mode = {
+                       .name           = "DVI-VGA",
+                       .refresh        = 60,
+                       .xres           = 640,
+                       .yres           = 480,
+                       .pixclock       = 32000,
+                       .hsync_len      = 7,
+                       .left_margin    = 100,
+                       .right_margin   = 100,
+                       .vsync_len      = 7,
+                       .upper_margin   = 7,
+                       .lower_margin   = 100,
+               },
+               .pcr            = 0xFA208B80,
+               .bpp            = 16,
+       }, {
+               .mode = {
+                       .name           = "DVI-SVGA",
+                       .refresh        = 60,
+                       .xres           = 800,
+                       .yres           = 600,
+                       .pixclock       = 25000,
+                       .hsync_len      = 7,
+                       .left_margin    = 75,
+                       .right_margin   = 75,
+                       .vsync_len      = 7,
+                       .upper_margin   = 7,
+                       .lower_margin   = 75,
+               },
+               .pcr            = 0xFA208B80,
+               .bpp            = 16,
        },
 };
 
@@ -205,7 +239,8 @@ static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = {
        },
 };
 
-struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata = {
+static const
+struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = {
        .flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE,
 };
 
@@ -239,7 +274,10 @@ void __init eukrea_mbimxsd25_baseboard_init(void)
 
        imx25_add_imx_uart1(&uart_pdata);
        mxc_register_device(&mx25_fb_device, &eukrea_mximxsd_fb_pdata);
-       mxc_register_device(&imx_ssi_device0, &eukrea_mbimxsd_ssi_pdata);
+       imx25_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata);
+
+       imx25_add_flexcan1(NULL);
+       imx25_add_esdhc(0, NULL);
 
        gpio_request(GPIO_LED1, "LED1");
        gpio_direction_output(GPIO_LED1, 1);
index e064bb3d69197b8ddee286eda06dee980052712d..f6f9ad60c25e37f724217c0e5f7a05393992812c 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/clk.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
-#include <linux/fec.h>
 #include <linux/platform_device.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
@@ -41,7 +40,6 @@
 #include <mach/mxc_nand.h>
 #include <mach/imxfb.h>
 #include <mach/mxc_ehci.h>
-#include <mach/ulpi.h>
 #include <mach/iomux-mx25.h>
 
 #include "devices-imx25.h"
@@ -67,7 +65,7 @@ static struct pad_desc eukrea_cpuimx25_pads[] = {
        MX25_PAD_I2C1_DAT__I2C1_DAT,
 };
 
-static struct fec_platform_data mx25_fec_pdata = {
+static const struct fec_platform_data mx25_fec_pdata __initconst = {
        .phy    = PHY_INTERFACE_MODE_RMII,
 };
 
@@ -129,24 +127,19 @@ static void __init eukrea_cpuimx25_init(void)
        imx25_add_imx_uart0(&uart_pdata);
        imx25_add_mxc_nand(&eukrea_cpuimx25_nand_board_info);
        mxc_register_device(&mx25_rtc_device, NULL);
-       mxc_register_device(&mx25_fec_device, &mx25_fec_pdata);
+       imx25_add_fec(&mx25_fec_pdata);
 
        i2c_register_board_info(0, eukrea_cpuimx25_i2c_devices,
                                ARRAY_SIZE(eukrea_cpuimx25_i2c_devices));
        imx25_add_imx_i2c0(&eukrea_cpuimx25_i2c0_data);
 
-#if defined(CONFIG_USB_ULPI)
-       if (otg_mode_host) {
-               otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
-                               ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
+       if (otg_mode_host)
                mxc_register_device(&mxc_otg, &otg_pdata);
-       }
-       mxc_register_device(&mxc_usbh2, &usbh2_pdata);
-#endif
-       if (!otg_mode_host)
+       else
                mxc_register_device(&otg_udc_device, &otg_device_pdata);
 
+       mxc_register_device(&mxc_usbh2, &usbh2_pdata);
+
 #ifdef CONFIG_MACH_EUKREA_MBIMXSD25_BASEBOARD
        eukrea_mbimxsd25_baseboard_init();
 #endif
@@ -163,8 +156,6 @@ static struct sys_timer eukrea_cpuimx25_timer = {
 
 MACHINE_START(EUKREA_CPUIMX25, "Eukrea CPUIMX25")
        /* Maintainer: Eukrea Electromatique */
-       .phys_io        = MX25_AIPS1_BASE_ADDR,
-       .io_pg_offst    = ((MX25_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX25_PHYS_OFFSET + 0x100,
        .map_io         = mx25_map_io,
        .init_irq       = mx25_init_irq,
index 62bc21f11a714aa46df5e439d4965f340d59460a..80805107a73eb74bbf7b18d2e22fd7b18e194965 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/clk.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
-#include <linux/fec.h>
 #include <linux/platform_device.h>
 #include <linux/input/matrix_keypad.h>
 
@@ -99,7 +98,7 @@ static struct pad_desc mx25pdk_pads[] = {
        MX25_PAD_KPP_COL3__KPP_COL3,
 };
 
-static struct fec_platform_data mx25_fec_pdata = {
+static const struct fec_platform_data mx25_fec_pdata __initconst = {
         .phy    = PHY_INTERFACE_MODE_RMII,
 };
 
@@ -192,7 +191,7 @@ static void __init mx25pdk_init(void)
        mxc_register_device(&mxc_wdt, NULL);
 
        mx25pdk_fec_reset();
-       mxc_register_device(&mx25_fec_device, &mx25_fec_pdata);
+       imx25_add_fec(&mx25_fec_pdata);
        mxc_register_device(&mx25_kpp_device, &mx25pdk_keymap_data);
 }
 
@@ -207,8 +206,6 @@ static struct sys_timer mx25pdk_timer = {
 
 MACHINE_START(MX25_3DS, "Freescale MX25PDK (3DS)")
        /* Maintainer: Freescale Semiconductor, Inc. */
-       .phys_io        = MX25_AIPS1_BASE_ADDR,
-       .io_pg_offst    = ((MX25_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX25_PHYS_OFFSET + 0x100,
        .map_io         = mx25_map_io,
        .init_irq       = mx25_init_irq,
index 85beece802aab702a71331f63fd6ff7065adb7bb..096fd33f8ab9ad6b77c4689361be00172f3bd327 100644 (file)
@@ -9,6 +9,7 @@ config ARCH_MX35
        bool
        select ARCH_MXC_IOMUX_V3
        select ARCH_MXC_AUDMUX_V2
+       select HAVE_EPIT
 
 comment "MX3 platforms:"
 
@@ -16,6 +17,7 @@ config MACH_MX31ADS
        bool "Support MX31ADS platforms"
        select ARCH_MX31
        select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_SSI
        select IMX_HAVE_PLATFORM_IMX_UART
        default y
        help
@@ -117,9 +119,11 @@ config MACH_PCM043
        bool "Support Phytec pcm043 (i.MX35) platforms"
        select ARCH_MX35
        select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_SSI
        select IMX_HAVE_PLATFORM_IMX_UART
        select IMX_HAVE_PLATFORM_MXC_NAND
        select IMX_HAVE_PLATFORM_FLEXCAN
+       select IMX_HAVE_PLATFORM_ESDHC
        select MXC_ULPI if USB_ULPI
        help
          Include support for Phytec pcm043 platform. This includes
@@ -140,6 +144,7 @@ config MACH_MX35_3DS
        bool "Support MX35PDK platform"
        select ARCH_MX35
        select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
        default n
        help
          Include support for MX35PDK platform. This includes specific
@@ -159,6 +164,8 @@ config MACH_EUKREA_CPUIMX35
        select IMX_HAVE_PLATFORM_IMX_UART
        select IMX_HAVE_PLATFORM_IMX_I2C
        select IMX_HAVE_PLATFORM_MXC_NAND
+       select IMX_HAVE_PLATFORM_FLEXCAN
+       select IMX_HAVE_PLATFORM_ESDHC
        select MXC_ULPI if USB_ULPI
        help
          Include support for Eukrea CPUIMX35 platform. This includes
@@ -170,8 +177,8 @@ choice
        default MACH_EUKREA_MBIMXSD35_BASEBOARD
 
 config MACH_EUKREA_MBIMXSD35_BASEBOARD
-       prompt "Eukrea MBIMXSD development board"
-       bool
+       bool "Eukrea MBIMXSD development board"
+       select IMX_HAVE_PLATFORM_IMX_SSI
        help
          This adds board specific devices that can be found on Eukrea's
          MBIMXSD evaluation board.
index 2bd7beceb99182879a7100d14e6d54dd5cdac6a2..8a182d0a3fcf9d11aa6307c9410c94ee27541924 100644 (file)
@@ -7,7 +7,6 @@
 obj-y                          := mm.o devices.o cpu.o
 CFLAGS_mm.o = -DIMX_NEEDS_DEPRECATED_SYMBOLS
 CFLAGS_devices.o = -DIMX_NEEDS_DEPRECATED_SYMBOLS
-CFLAGS_cpu.o = -DIMX_NEEDS_DEPRECATED_SYMBOLS
 obj-$(CONFIG_ARCH_MX31)                += clock-imx31.o iomux-imx31.o
 obj-$(CONFIG_ARCH_MX35)                += clock-imx35.o
 obj-$(CONFIG_MACH_MX31ADS)     += mach-mx31ads.o
index 9a9eb6de6127efd0b7a6241a17a5f9d88b4e09e1..109e98f323e0568a299d46f1481ee3a31116476e 100644 (file)
@@ -477,7 +477,7 @@ DEFINE_CLOCK(epit1_clk,   0, MXC_CCM_CGR0,  6, NULL, NULL, &perclk_clk);
 DEFINE_CLOCK(epit2_clk,   1, MXC_CCM_CGR0,  8, NULL, NULL, &perclk_clk);
 DEFINE_CLOCK(iim_clk,     0, MXC_CCM_CGR0, 10, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(ata_clk,     0, MXC_CCM_CGR0, 12, NULL, NULL, &ipg_clk);
-DEFINE_CLOCK(sdma_clk1,   0, MXC_CCM_CGR0, 14, NULL, &sdma_clk1, &ahb_clk);
+DEFINE_CLOCK(sdma_clk1,   0, MXC_CCM_CGR0, 14, NULL, NULL, &ahb_clk);
 DEFINE_CLOCK(cspi3_clk,   2, MXC_CCM_CGR0, 16, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(rng_clk,     0, MXC_CCM_CGR0, 18, NULL, NULL, &ipg_clk);
 DEFINE_CLOCK(uart1_clk,   0, MXC_CCM_CGR0, 20, NULL, NULL, &perclk_clk);
@@ -525,9 +525,9 @@ DEFINE_CLOCK(ipg_clk,     0, NULL,          0, ipg_get_rate, NULL, &ahb_clk);
 
 static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "emi", emi_clk)
-       _REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
-       _REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
-       _REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
+       _REGISTER_CLOCK("imx31-cspi.0", NULL, cspi1_clk)
+       _REGISTER_CLOCK("imx31-cspi.1", NULL, cspi2_clk)
+       _REGISTER_CLOCK("imx31-cspi.2", NULL, cspi3_clk)
        _REGISTER_CLOCK(NULL, "gpt", gpt_clk)
        _REGISTER_CLOCK(NULL, "pwm", pwm_clk)
        _REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
@@ -564,7 +564,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "ata", ata_clk)
        _REGISTER_CLOCK(NULL, "rtic", rtic_clk)
        _REGISTER_CLOCK(NULL, "rng", rng_clk)
-       _REGISTER_CLOCK(NULL, "sdma_ahb", sdma_clk1)
+       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk1)
        _REGISTER_CLOCK(NULL, "sdma_ipg", sdma_clk2)
        _REGISTER_CLOCK(NULL, "mstick", mstick1_clk)
        _REGISTER_CLOCK(NULL, "mstick", mstick2_clk)
index 7a62e744a8b0fcbc5eef1da9645bf663199608f8..61e4a318980a2bc9fe4fa25c7de02a08a7b89bb8 100644 (file)
@@ -364,8 +364,8 @@ DEFINE_CLOCK(cspi2_clk,  1, CCM_CGR0, 12, get_rate_ipg, NULL);
 DEFINE_CLOCK(ect_clk,    0, CCM_CGR0, 14, get_rate_ipg, NULL);
 DEFINE_CLOCK(edio_clk,   0, CCM_CGR0, 16, NULL, NULL);
 DEFINE_CLOCK(emi_clk,    0, CCM_CGR0, 18, get_rate_ipg, NULL);
-DEFINE_CLOCK(epit1_clk,  0, CCM_CGR0, 20, get_rate_ipg_per, NULL);
-DEFINE_CLOCK(epit2_clk,  1, CCM_CGR0, 22, get_rate_ipg_per, NULL);
+DEFINE_CLOCK(epit1_clk,  0, CCM_CGR0, 20, get_rate_ipg, NULL);
+DEFINE_CLOCK(epit2_clk,  1, CCM_CGR0, 22, get_rate_ipg, NULL);
 DEFINE_CLOCK(esai_clk,   0, CCM_CGR0, 24, NULL, NULL);
 DEFINE_CLOCK(esdhc1_clk, 0, CCM_CGR0, 26, get_rate_sdhc, NULL);
 DEFINE_CLOCK(esdhc2_clk, 1, CCM_CGR0, 28, get_rate_sdhc, NULL);
@@ -451,17 +451,17 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "ata", ata_clk)
        _REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
        _REGISTER_CLOCK("flexcan.1", NULL, can2_clk)
-       _REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
-       _REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
+       _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi1_clk)
+       _REGISTER_CLOCK("imx35-cspi.1", NULL, cspi2_clk)
        _REGISTER_CLOCK(NULL, "ect", ect_clk)
        _REGISTER_CLOCK(NULL, "edio", edio_clk)
        _REGISTER_CLOCK(NULL, "emi", emi_clk)
-       _REGISTER_CLOCK(NULL, "epit", epit1_clk)
-       _REGISTER_CLOCK(NULL, "epit", epit2_clk)
+       _REGISTER_CLOCK("imx-epit.0", NULL, epit1_clk)
+       _REGISTER_CLOCK("imx-epit.1", NULL, epit2_clk)
        _REGISTER_CLOCK(NULL, "esai", esai_clk)
-       _REGISTER_CLOCK(NULL, "sdhc", esdhc1_clk)
-       _REGISTER_CLOCK(NULL, "sdhc", esdhc2_clk)
-       _REGISTER_CLOCK(NULL, "sdhc", esdhc3_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk)
        _REGISTER_CLOCK("fec.0", NULL, fec_clk)
        _REGISTER_CLOCK(NULL, "gpio", gpio1_clk)
        _REGISTER_CLOCK(NULL, "gpio", gpio2_clk)
@@ -482,7 +482,7 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "rtc", rtc_clk)
        _REGISTER_CLOCK(NULL, "rtic", rtic_clk)
        _REGISTER_CLOCK(NULL, "scc", scc_clk)
-       _REGISTER_CLOCK(NULL, "sdma", sdma_clk)
+       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
        _REGISTER_CLOCK(NULL, "spba", spba_clk)
        _REGISTER_CLOCK(NULL, "spdif", spdif_clk)
        _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
@@ -535,8 +535,16 @@ int __init mx35_clocks_init()
        __raw_writel(cgr2, CCM_BASE + CCM_CGR2);
        __raw_writel(cgr3, CCM_BASE + CCM_CGR3);
 
+       clk_enable(&iim_clk);
+       mx35_read_cpu_rev();
+
+#ifdef CONFIG_MXC_USE_EPIT
+       epit_timer_init(&epit1_clk,
+                       MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1);
+#else
        mxc_timer_init(&gpt_clk,
                        MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), MX35_INT_GPT);
+#endif
 
        return 0;
 }
index 861afe0fe3ad6217edfa46fd25d4e9985b5ce1b2..d00a75457812eebc3f23eab759140a057ad6f8f8 100644 (file)
@@ -25,15 +25,15 @@ struct mx3_cpu_type {
 };
 
 static struct mx3_cpu_type mx31_cpu_type[] __initdata = {
-       { .srev = 0x00, .name = "i.MX31(L)", .v = "1.0",  .rev = CHIP_REV_1_0   },
-       { .srev = 0x10, .name = "i.MX31",    .v = "1.1",  .rev = CHIP_REV_1_1   },
-       { .srev = 0x11, .name = "i.MX31L",   .v = "1.1",  .rev = CHIP_REV_1_1   },
-       { .srev = 0x12, .name = "i.MX31",    .v = "1.15", .rev = CHIP_REV_1_1   },
-       { .srev = 0x13, .name = "i.MX31L",   .v = "1.15", .rev = CHIP_REV_1_1   },
-       { .srev = 0x14, .name = "i.MX31",    .v = "1.2",  .rev = CHIP_REV_1_2   },
-       { .srev = 0x15, .name = "i.MX31L",   .v = "1.2",  .rev = CHIP_REV_1_2   },
-       { .srev = 0x28, .name = "i.MX31",    .v = "2.0",  .rev = CHIP_REV_2_0   },
-       { .srev = 0x29, .name = "i.MX31L",   .v = "2.0",  .rev = CHIP_REV_2_0   },
+       { .srev = 0x00, .name = "i.MX31(L)", .v = "1.0",  .rev = MX3x_CHIP_REV_1_0 },
+       { .srev = 0x10, .name = "i.MX31",    .v = "1.1",  .rev = MX3x_CHIP_REV_1_1 },
+       { .srev = 0x11, .name = "i.MX31L",   .v = "1.1",  .rev = MX3x_CHIP_REV_1_1 },
+       { .srev = 0x12, .name = "i.MX31",    .v = "1.15", .rev = MX3x_CHIP_REV_1_1 },
+       { .srev = 0x13, .name = "i.MX31L",   .v = "1.15", .rev = MX3x_CHIP_REV_1_1 },
+       { .srev = 0x14, .name = "i.MX31",    .v = "1.2",  .rev = MX3x_CHIP_REV_1_2 },
+       { .srev = 0x15, .name = "i.MX31L",   .v = "1.2",  .rev = MX3x_CHIP_REV_1_2 },
+       { .srev = 0x28, .name = "i.MX31",    .v = "2.0",  .rev = MX3x_CHIP_REV_2_0 },
+       { .srev = 0x29, .name = "i.MX31L",   .v = "2.0",  .rev = MX3x_CHIP_REV_2_0 },
 };
 
 void __init mx31_read_cpu_rev(void)
@@ -41,7 +41,7 @@ void __init mx31_read_cpu_rev(void)
        u32 i, srev;
 
        /* read SREV register from IIM module */
-       srev = __raw_readl(IO_ADDRESS(IIM_BASE_ADDR + MXC_IIMSREV));
+       srev = __raw_readl(MX31_IO_ADDRESS(MX31_IIM_BASE_ADDR + MXC_IIMSREV));
 
        for (i = 0; i < ARRAY_SIZE(mx31_cpu_type); i++)
                if (srev == mx31_cpu_type[i].srev) {
@@ -55,3 +55,30 @@ void __init mx31_read_cpu_rev(void)
 
        printk(KERN_WARNING "Unknown CPU identifier. srev = %02x\n", srev);
 }
+
+unsigned int mx35_cpu_rev;
+EXPORT_SYMBOL(mx35_cpu_rev);
+
+void __init mx35_read_cpu_rev(void)
+{
+       u32 rev;
+       char *srev = "unknown";
+
+       rev = __raw_readl(MX35_IO_ADDRESS(MX35_IIM_BASE_ADDR + MXC_IIMSREV));
+       switch (rev) {
+       case 0x00:
+               mx35_cpu_rev = MX3x_CHIP_REV_1_0;
+               srev = "1.0";
+               break;
+       case 0x10:
+               mx35_cpu_rev = MX3x_CHIP_REV_2_0;
+               srev = "2.0";
+               break;
+       case 0x11:
+               mx35_cpu_rev = MX3x_CHIP_REV_2_1;
+               srev = "2.1";
+               break;
+       }
+
+       printk(KERN_INFO "CPU identified as i.MX35, silicon rev %s\n", srev);
+}
index 3b1a44a20585560935e34698d3c333659300717e..de9598590eba71e43f83339e5d53a64d1740345c 100644 (file)
@@ -9,30 +9,33 @@
 #include <mach/mx31.h>
 #include <mach/devices-common.h>
 
-#define imx31_add_imx_i2c0(pdata)      \
-       imx_add_imx_i2c(0, MX31_I2C1_BASE_ADDR, SZ_4K, MX31_INT_I2C1, pdata)
-#define imx31_add_imx_i2c1(pdata)      \
-       imx_add_imx_i2c(1, MX31_I2C2_BASE_ADDR, SZ_4K, MX31_INT_I2C2, pdata)
-#define imx31_add_imx_i2c2(pdata)      \
-       imx_add_imx_i2c(2, MX31_I2C3_BASE_ADDR, SZ_4K, MX31_INT_I2C3, pdata)
+extern const struct imx_imx_i2c_data imx31_imx_i2c_data[] __initconst;
+#define imx31_add_imx_i2c(id, pdata)   \
+       imx_add_imx_i2c(&imx31_imx_i2c_data[id], pdata)
+#define imx31_add_imx_i2c0(pdata)      imx31_add_imx_i2c(0, pdata)
+#define imx31_add_imx_i2c1(pdata)      imx31_add_imx_i2c(1, pdata)
+#define imx31_add_imx_i2c2(pdata)      imx31_add_imx_i2c(2, pdata)
 
-#define imx31_add_imx_uart0(pdata)     \
-       imx_add_imx_uart_1irq(0, MX31_UART1_BASE_ADDR, SZ_16K, MX31_INT_UART1, pdata)
-#define imx31_add_imx_uart1(pdata)     \
-       imx_add_imx_uart_1irq(1, MX31_UART2_BASE_ADDR, SZ_16K, MX31_INT_UART2, pdata)
-#define imx31_add_imx_uart2(pdata)     \
-       imx_add_imx_uart_1irq(2, MX31_UART3_BASE_ADDR, SZ_16K, MX31_INT_UART3, pdata)
-#define imx31_add_imx_uart3(pdata)     \
-       imx_add_imx_uart_1irq(3, MX31_UART4_BASE_ADDR, SZ_16K, MX31_INT_UART4, pdata)
-#define imx31_add_imx_uart4(pdata)     \
-       imx_add_imx_uart_1irq(4, MX31_UART5_BASE_ADDR, SZ_16K, MX31_INT_UART5, pdata)
+extern const struct imx_imx_ssi_data imx31_imx_ssi_data[] __initconst;
+#define imx31_add_imx_ssi(id, pdata)    \
+       imx_add_imx_ssi(&imx31_imx_ssi_data[id], pdata)
 
+extern const struct imx_imx_uart_1irq_data imx31_imx_uart_data[] __initconst;
+#define imx31_add_imx_uart(id, pdata)  \
+       imx_add_imx_uart_1irq(&imx31_imx_uart_data[id], pdata)
+#define imx31_add_imx_uart0(pdata)     imx31_add_imx_uart(0, pdata)
+#define imx31_add_imx_uart1(pdata)     imx31_add_imx_uart(1, pdata)
+#define imx31_add_imx_uart2(pdata)     imx31_add_imx_uart(2, pdata)
+#define imx31_add_imx_uart3(pdata)     imx31_add_imx_uart(3, pdata)
+#define imx31_add_imx_uart4(pdata)     imx31_add_imx_uart(4, pdata)
+
+extern const struct imx_mxc_nand_data imx31_mxc_nand_data __initconst;
 #define imx31_add_mxc_nand(pdata)      \
-       imx_add_mxc_nand_v1(MX31_NFC_BASE_ADDR, MX31_INT_NANDFC, pdata)
+       imx_add_mxc_nand(&imx31_mxc_nand_data, pdata)
 
-#define imx31_add_spi_imx0(pdata)      \
-       imx_add_spi_imx(0, MX31_CSPI1_BASE_ADDR, SZ_4K, MX31_INT_CSPI1, pdata)
-#define imx31_add_spi_imx1(pdata)      \
-       imx_add_spi_imx(1, MX31_CSPI2_BASE_ADDR, SZ_4K, MX31_INT_CSPI2, pdata)
-#define imx31_add_spi_imx2(pdata)      \
-       imx_add_spi_imx(2, MX31_CSPI3_BASE_ADDR, SZ_4K, MX31_INT_CSPI3, pdata)
+extern const struct imx_spi_imx_data imx31_cspi_data[] __initconst;
+#define imx31_add_cspi(id, pdata)      \
+       imx_add_spi_imx(&imx31_cspi_data[id], pdata)
+#define imx31_add_spi_imx0(pdata)      imx31_add_cspi(0, pdata)
+#define imx31_add_spi_imx1(pdata)      imx31_add_cspi(1, pdata)
+#define imx31_add_spi_imx2(pdata)      imx31_add_cspi(2, pdata)
index f6a431a4c3d2ebdf45c82ed6f54afcdbaccd73e1..5eb917b638d0b40ea14ef260bdc414298cb17db8 100644 (file)
@@ -9,29 +9,43 @@
 #include <mach/mx35.h>
 #include <mach/devices-common.h>
 
+extern const struct imx_fec_data imx35_fec_data __initconst;
+#define imx35_add_fec(pdata)   \
+       imx_add_fec(&imx35_fec_data, pdata)
+
 #define imx35_add_flexcan0(pdata)      \
        imx_add_flexcan(0, MX35_CAN1_BASE_ADDR, SZ_16K, MX35_INT_CAN1, pdata)
 #define imx35_add_flexcan1(pdata)      \
        imx_add_flexcan(1, MX35_CAN2_BASE_ADDR, SZ_16K, MX35_INT_CAN2, pdata)
 
-#define imx35_add_imx_i2c0(pdata)      \
-       imx_add_imx_i2c(0, MX35_I2C1_BASE_ADDR, SZ_4K, MX35_INT_I2C1, pdata)
-#define imx35_add_imx_i2c1(pdata)      \
-       imx_add_imx_i2c(1, MX35_I2C2_BASE_ADDR, SZ_4K, MX35_INT_I2C2, pdata)
-#define imx35_add_imx_i2c2(pdata)      \
-       imx_add_imx_i2c(2, MX35_I2C3_BASE_ADDR, SZ_4K, MX35_INT_I2C3, pdata)
+extern const struct imx_imx_i2c_data imx35_imx_i2c_data[] __initconst;
+#define imx35_add_imx_i2c(id, pdata)   \
+       imx_add_imx_i2c(&imx35_imx_i2c_data[id], pdata)
+#define imx35_add_imx_i2c0(pdata)      imx35_add_imx_i2c(0, pdata)
+#define imx35_add_imx_i2c1(pdata)      imx35_add_imx_i2c(1, pdata)
+#define imx35_add_imx_i2c2(pdata)      imx35_add_imx_i2c(2, pdata)
+
+extern const struct imx_imx_ssi_data imx35_imx_ssi_data[] __initconst;
+#define imx35_add_imx_ssi(id, pdata)    \
+       imx_add_imx_ssi(&imx35_imx_ssi_data[id], pdata)
 
-#define imx35_add_imx_uart0(pdata)     \
-       imx_add_imx_uart_1irq(0, MX35_UART1_BASE_ADDR, SZ_16K, MX35_INT_UART1, pdata)
-#define imx35_add_imx_uart1(pdata)     \
-       imx_add_imx_uart_1irq(1, MX35_UART2_BASE_ADDR, SZ_16K, MX35_INT_UART2, pdata)
-#define imx35_add_imx_uart2(pdata)     \
-       imx_add_imx_uart_1irq(2, MX35_UART3_BASE_ADDR, SZ_16K, MX35_INT_UART3, pdata)
+extern const struct imx_imx_uart_1irq_data imx35_imx_uart_data[] __initconst;
+#define imx35_add_imx_uart(id, pdata)  \
+       imx_add_imx_uart_1irq(&imx35_imx_uart_data[id], pdata)
+#define imx35_add_imx_uart0(pdata)     imx35_add_imx_uart(0, pdata)
+#define imx35_add_imx_uart1(pdata)     imx35_add_imx_uart(1, pdata)
+#define imx35_add_imx_uart2(pdata)     imx35_add_imx_uart(2, pdata)
 
+extern const struct imx_mxc_nand_data imx35_mxc_nand_data __initconst;
 #define imx35_add_mxc_nand(pdata)      \
-       imx_add_mxc_nand_v21(MX35_NFC_BASE_ADDR, MX35_INT_NANDFC, pdata)
+       imx_add_mxc_nand(&imx35_mxc_nand_data, pdata)
+
+extern const struct imx_spi_imx_data imx35_cspi_data[] __initconst;
+#define imx35_add_cspi(id, pdata)      \
+       imx_add_spi_imx(&imx35_cspi_data[id], pdata)
+#define imx35_add_spi_imx0(pdata)      imx35_add_cspi(0, pdata)
+#define imx35_add_spi_imx1(pdata)      imx35_add_cspi(1, pdata)
 
-#define imx35_add_spi_imx0(pdata)      \
-       imx_add_spi_imx(0, MX35_CSPI1_BASE_ADDR, SZ_4K, MX35_INT_CSPI1, pdata)
-#define imx35_add_spi_imx1(pdata)      \
-       imx_add_spi_imx(1, MX35_CSPI2_BASE_ADDR, SZ_4K, MX35_INT_CSPI2, pdata)
+extern const struct imx_esdhc_imx_data imx35_esdhc_data[] __initconst;
+#define imx35_add_esdhc(id, pdata)     \
+       imx_add_esdhc(&imx35_esdhc_data[id], pdata)
index a4fd1a26fc91982d200d76c7a152eb5c62610a7b..f4dff11aaee7a68aa58fb9a07a43aca9662f6856 100644 (file)
@@ -281,65 +281,6 @@ struct platform_device mxc_usbh2 = {
        .num_resources = ARRAY_SIZE(mxc_usbh2_resources),
 };
 
-#if defined(CONFIG_ARCH_MX35)
-static struct resource mxc_fec_resources[] = {
-       {
-               .start  = MXC_FEC_BASE_ADDR,
-               .end    = MXC_FEC_BASE_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = MXC_INT_FEC,
-               .end    = MXC_INT_FEC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_fec_device = {
-       .name = "fec",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_fec_resources),
-       .resource = mxc_fec_resources,
-};
-#endif
-
-static struct resource imx_ssi_resources0[] = {
-       {
-               .start  = SSI1_BASE_ADDR,
-               .end    = SSI1_BASE_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = MX31_INT_SSI1,
-               .end    = MX31_INT_SSI1,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct resource imx_ssi_resources1[] = {
-       {
-               .start  = SSI2_BASE_ADDR,
-               .end    = SSI2_BASE_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM
-       }, {
-               .start  = MX31_INT_SSI2,
-               .end    = MX31_INT_SSI2,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device imx_ssi_device0 = {
-       .name = "imx-ssi",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(imx_ssi_resources0),
-       .resource = imx_ssi_resources0,
-};
-
-struct platform_device imx_ssi_device1 = {
-       .name = "imx-ssi",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(imx_ssi_resources1),
-       .resource = imx_ssi_resources1,
-};
-
 static struct resource imx_wdt_resources[] = {
        {
                .flags = IORESOURCE_MEM,
@@ -410,10 +351,6 @@ static int __init mx3_devices_init(void)
                mxc_usbh1_resources[0].end = MX35_OTG_BASE_ADDR + 0x5ff;
                mxc_usbh1_resources[1].start = MXC_INT_USBHS;
                mxc_usbh1_resources[1].end = MXC_INT_USBHS;
-               imx_ssi_resources0[1].start = MX35_INT_SSI1;
-               imx_ssi_resources0[1].end = MX35_INT_SSI1;
-               imx_ssi_resources1[1].start = MX35_INT_SSI2;
-               imx_ssi_resources1[1].end = MX35_INT_SSI2;
                imx_wdt_resources[0].start = MX35_WDOG_BASE_ADDR;
                imx_wdt_resources[0].end = MX35_WDOG_BASE_ADDR + 0x3fff;
        }
index e5535234839f5e1ae8159d0513e8bf9c0952d7c7..585f814473d5f7b857426b8f549bf1512002e9da 100644 (file)
@@ -2,7 +2,6 @@ extern struct platform_device mxc_w1_master_device;
 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;
@@ -10,9 +9,6 @@ extern struct platform_device mxc_otg_host;
 extern struct platform_device mxc_usbh1;
 extern struct platform_device mxc_usbh2;
 extern struct platform_device mxc_rnga_device;
-extern struct platform_device imx_ssi_device0;
-extern struct platform_device imx_ssi_device1;
-extern struct platform_device imx_ssi_device1;
 extern struct platform_device imx_wdt_device0;
 extern struct platform_device imx_rtc_device0;
 extern struct platform_device imx_kpp_device;
index f8f15e3ac7a0e82a6cde9f6bd021c85a546bbae7..1abc10d5292217db60b714de87e689491e05a4fe 100644 (file)
 #include <mach/ipu.h>
 #include <mach/mx3fb.h>
 #include <mach/audmux.h>
-#include <mach/ssi.h>
 
 #include "devices-imx35.h"
 #include "devices.h"
 
 static const struct fb_videomode fb_modedb[] = {
        {
-               .name           = "CMO_QVGA",
+               .name           = "CMO-QVGA",
                .refresh        = 60,
                .xres           = 320,
                .yres           = 240,
@@ -65,6 +64,40 @@ static const struct fb_videomode fb_modedb[] = {
                .vmode          = FB_VMODE_NONINTERLACED,
                .flag           = 0,
        },
+       {
+               .name           = "DVI-VGA",
+               .refresh        = 60,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = 32000,
+               .left_margin    = 100,
+               .right_margin   = 100,
+               .upper_margin   = 7,
+               .lower_margin   = 100,
+               .hsync_len      = 7,
+               .vsync_len      = 7,
+               .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT |
+                                 FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT,
+               .vmode          = FB_VMODE_NONINTERLACED,
+               .flag           = 0,
+       },
+       {
+               .name           = "DVI-SVGA",
+               .refresh        = 60,
+               .xres           = 800,
+               .yres           = 600,
+               .pixclock       = 25000,
+               .left_margin    = 75,
+               .right_margin   = 75,
+               .upper_margin   = 7,
+               .lower_margin   = 75,
+               .hsync_len      = 7,
+               .vsync_len      = 7,
+               .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT |
+                                 FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT,
+               .vmode          = FB_VMODE_NONINTERLACED,
+               .flag           = 0,
+       },
 };
 
 static struct ipu_platform_data mx3_ipu_data = {
@@ -73,7 +106,7 @@ static struct ipu_platform_data mx3_ipu_data = {
 
 static struct mx3fb_platform_data mx3fb_pdata = {
        .dma_dev        = &mx3_ipu.dev,
-       .name           = "CMO_QVGA",
+       .name           = "CMO-QVGA",
        .mode           = fb_modedb,
        .num_modes      = ARRAY_SIZE(fb_modedb),
 };
@@ -120,6 +153,16 @@ static struct pad_desc eukrea_mbimxsd_pads[] = {
        MX35_PAD_STXD4__AUDMUX_AUD4_TXD,
        MX35_PAD_SRXD4__AUDMUX_AUD4_RXD,
        MX35_PAD_SCK4__AUDMUX_AUD4_TXC,
+       /* CAN2 */
+       MX35_PAD_TX5_RX0__CAN2_TXCAN,
+       MX35_PAD_TX4_RX1__CAN2_RXCAN,
+       /* SDCARD */
+       MX35_PAD_SD1_CMD__ESDHC1_CMD,
+       MX35_PAD_SD1_CLK__ESDHC1_CLK,
+       MX35_PAD_SD1_DATA0__ESDHC1_DAT0,
+       MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
+       MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
+       MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
 };
 
 #define GPIO_LED1      (2 * 32 + 29)
@@ -206,7 +249,8 @@ static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = {
        },
 };
 
-struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata = {
+static const
+struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = {
        .flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE,
 };
 
@@ -242,7 +286,10 @@ void __init eukrea_mbimxsd35_baseboard_init(void)
        mxc_register_device(&mx3_ipu, &mx3_ipu_data);
        mxc_register_device(&mx3_fb, &mx3fb_pdata);
 
-       mxc_register_device(&imx_ssi_device0, &eukrea_mbimxsd_ssi_pdata);
+       imx35_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata);
+
+       imx35_add_flexcan1(NULL);
+       imx35_add_esdhc(0, NULL);
 
        gpio_request(GPIO_LED1, "LED1");
        gpio_direction_output(GPIO_LED1, 1);
@@ -254,7 +301,7 @@ void __init eukrea_mbimxsd35_baseboard_init(void)
 
        gpio_request(GPIO_LCDPWR, "LCDPWR");
        gpio_direction_output(GPIO_LCDPWR, 1);
-       gpio_free(GPIO_SWITCH1);
+       gpio_free(GPIO_LCDPWR);
 
        i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
                                ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
index 68879c996a55d0db79b84f94952ed8efc6c0cf7a..aaa30fe18f8593639e9f4ffa8752c52b4932de5f 100644 (file)
@@ -571,8 +571,6 @@ static struct sys_timer armadillo5x0_timer = {
 
 MACHINE_START(ARMADILLO5X0, "Armadillo-500")
        /* Maintainer: Alberto Panizzo  */
-       .phys_io        = MX31_AIPS1_BASE_ADDR,
-       .io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx31_map_io,
        .init_irq       = mx31_init_irq,
index 2a4f8b781ba4c60a4d66f554d860953fcafe1cf0..8533bf04284a1fc682db1a7fc15897a097a61e2d 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/usb/otg.h>
 #include <linux/usb/ulpi.h>
 #include <linux/fsl_devices.h>
+#include <linux/i2c-gpio.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -43,7 +44,6 @@
 #include <mach/iomux-mx35.h>
 #include <mach/mxc_nand.h>
 #include <mach/mxc_ehci.h>
-#include <mach/ulpi.h>
 
 #include "devices-imx35.h"
 #include "devices.h"
@@ -53,39 +53,16 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
 };
 
 static const struct imxi2c_platform_data
-eukrea_cpuimx35_i2c0_data __initconst = {
-       .bitrate = 50000,
+               eukrea_cpuimx35_i2c0_data __initconst = {
+       .bitrate =              100000,
 };
 
-#define TSC2007_IRQGPIO                (2 * 32 + 2)
-static int ts_get_pendown_state(void)
-{
-       int val = 0;
-       gpio_free(TSC2007_IRQGPIO);
-       gpio_request(TSC2007_IRQGPIO, NULL);
-       gpio_direction_input(TSC2007_IRQGPIO);
-
-       val = gpio_get_value(TSC2007_IRQGPIO);
-
-       gpio_free(TSC2007_IRQGPIO);
-       gpio_request(TSC2007_IRQGPIO, NULL);
-
-       return val ? 0 : 1;
-}
-
-static int ts_init(void)
-{
-       gpio_request(TSC2007_IRQGPIO, NULL);
-       return 0;
-}
-
 static struct tsc2007_platform_data tsc2007_info = {
        .model                  = 2007,
        .x_plate_ohms           = 180,
-       .get_pendown_state      = ts_get_pendown_state,
-       .init_platform_hw       = ts_init,
 };
 
+#define TSC2007_IRQGPIO                (2 * 32 + 2)
 static struct i2c_board_info eukrea_cpuimx35_i2c_devices[] = {
        {
                I2C_BOARD_INFO("pcf8563", 0x51),
@@ -98,7 +75,6 @@ static struct i2c_board_info eukrea_cpuimx35_i2c_devices[] = {
 };
 
 static struct platform_device *devices[] __initdata = {
-       &mxc_fec_device,
        &imx_wdt_device0,
 };
 
@@ -135,18 +111,18 @@ static struct pad_desc eukrea_cpuimx35_pads[] = {
 };
 
 static const struct mxc_nand_platform_data
-eukrea_cpuimx35_nand_board_info __initconst = {
+               eukrea_cpuimx35_nand_board_info __initconst = {
        .width          = 1,
        .hw_ecc         = 1,
        .flash_bbt      = 1,
 };
 
-static struct mxc_usbh_platform_data otg_pdata = {
+static struct mxc_usbh_platform_data __maybe_unused otg_pdata = {
        .portsc = MXC_EHCI_MODE_UTMI,
        .flags  = MXC_EHCI_INTERFACE_DIFF_UNI,
 };
 
-static struct mxc_usbh_platform_data usbh1_pdata = {
+static struct mxc_usbh_platform_data __maybe_unused usbh1_pdata = {
        .portsc = MXC_EHCI_MODE_SERIAL,
        .flags  = MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY |
                  MXC_EHCI_IPPUE_DOWN,
@@ -180,6 +156,7 @@ static void __init mxc_board_init(void)
        mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx35_pads,
                        ARRAY_SIZE(eukrea_cpuimx35_pads));
 
+       imx35_add_fec(NULL);
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
        imx35_add_imx_uart0(&uart_pdata);
@@ -189,18 +166,13 @@ static void __init mxc_board_init(void)
                        ARRAY_SIZE(eukrea_cpuimx35_i2c_devices));
        imx35_add_imx_i2c0(&eukrea_cpuimx35_i2c0_data);
 
-#if defined(CONFIG_USB_ULPI)
-       if (otg_mode_host) {
-               otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
-                               ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
-
+       if (otg_mode_host)
                mxc_register_device(&mxc_otg_host, &otg_pdata);
-       }
-       mxc_register_device(&mxc_usbh1, &usbh1_pdata);
-#endif
-       if (!otg_mode_host)
+       else
                mxc_register_device(&mxc_otg_udc_device, &otg_device_pdata);
 
+       mxc_register_device(&mxc_usbh1, &usbh1_pdata);
+
 #ifdef CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD
        eukrea_mbimxsd35_baseboard_init();
 #endif
@@ -217,8 +189,6 @@ struct sys_timer eukrea_cpuimx35_timer = {
 
 MACHINE_START(EUKREA_CPUIMX35, "Eukrea CPUIMX35")
        /* Maintainer: Eukrea Electromatique */
-       .phys_io        = MX35_AIPS1_BASE_ADDR,
-       .io_pg_offst    = ((MX35_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx35_map_io,
        .init_irq       = mx35_init_irq,
index 5b23e416d6c704c904385895f4bbf82dabfba56e..042cd5655e17b46d548a39a72b2780881af91bb4 100644 (file)
@@ -274,8 +274,6 @@ static struct sys_timer kzm_timer = {
  * initialize __mach_desc_KZM_ARM11_01 data structure.
  */
 MACHINE_START(KZM_ARM11_01, "Kyoto Microcomputer Co., Ltd. KZM-ARM11-01")
-       .phys_io        = MX31_AIPS1_BASE_ADDR,
-       .io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = kzm_map_io,
        .init_irq       = mx31_init_irq,
index 6fe69e124d30faa27d23a239ba903f0a76cb1c15..5c1d0e86c91e16fd22e0ed2f4d1c190eb87f3a58 100644 (file)
@@ -301,8 +301,6 @@ static struct sys_timer mx31_3ds_timer = {
  */
 MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)")
        /* Maintainer: Freescale Semiconductor, Inc. */
-       .phys_io        = MX31_AIPS1_BASE_ADDR,
-       .io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx31_3ds_map_io,
        .init_irq       = mx31_init_irq,
index 94b3e7c4240408451aa08446c9b991ad179be699..b993b9bf61793c4bfb765abfa1b7ef1caaaa0f42 100644 (file)
 #include <linux/i2c.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/board-mx31ads.h>
 #include <mach/iomux-mx3.h>
 
 #ifdef CONFIG_MACH_MX31ADS_WM1133_EV1
 #include "devices-imx31.h"
 #include "devices.h"
 
-/* Base address of PBC controller */
-#define PBC_BASE_ADDRESS        MX31_CS4_BASE_ADDR_VIRT
-/* Offsets for the PBC Controller register */
-
 /* PBC Board interrupt status register */
 #define PBC_INTSTATUS           0x000016
 
@@ -67,7 +63,6 @@
 #define PBC_INTMASK_CLEAR_REG  (PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS)
 #define EXPIO_PARENT_INT       IOMUX_TO_IRQ(MX31_PIN_GPIO1_4)
 
-#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
 #define MXC_IRQ_TO_EXPIO(irq)  ((irq) - MXC_EXP_IO_BASE)
 
 #define EXPIO_INT_XUART_INTA   (MXC_EXP_IO_BASE + 10)
@@ -517,7 +512,7 @@ static unsigned int ssi_pins[] = {
 
 static void mxc_init_audio(void)
 {
-       mxc_register_device(&imx_ssi_device0, NULL);
+       imx31_add_imx_ssi(0, NULL);
        mxc_iomux_setup_multiple_pins(ssi_pins, ARRAY_SIZE(ssi_pins), "ssi");
 }
 
@@ -574,8 +569,6 @@ static struct sys_timer mx31ads_timer = {
  */
 MACHINE_START(MX31ADS, "Freescale MX31ADS")
        /* Maintainer: Freescale Semiconductor, Inc. */
-       .phys_io        = MX31_AIPS1_BASE_ADDR,
-       .io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx31ads_map_io,
        .init_irq       = mx31ads_init_irq,
index 7c37daabb757351e559a81da063b4f78562cb6db..42f47faa6fd6c7e3aef760e86c948d04b058eccc 100644 (file)
@@ -348,8 +348,6 @@ static struct sys_timer mx31lilly_timer = {
 };
 
 MACHINE_START(LILLY1131, "INCO startec LILLY-1131")
-       .phys_io        = MX31_AIPS1_BASE_ADDR,
-       .io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx31_map_io,
        .init_irq       = mx31_init_irq,
index f66a9576d8c242ed691583f9762d6acaa15b433c..b93895814cdfcc321134be0e4359a01a8d78ffe5 100644 (file)
@@ -282,8 +282,6 @@ struct sys_timer mx31lite_timer = {
 
 MACHINE_START(MX31LITE, "LogicPD i.MX31 SOM")
        /* Maintainer: Freescale Semiconductor, Inc. */
-       .phys_io        = MX31_AIPS1_BASE_ADDR,
-       .io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx31lite_map_io,
        .init_irq       = mx31_init_irq,
index 7a075e8bf2d4767d2eb7b8b724b5e960edde0de1..eb5f426df224b8f1e3ef2e5feaf424be83b6c48a 100644 (file)
@@ -560,8 +560,6 @@ struct sys_timer mx31moboard_timer = {
 
 MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
        /* Maintainer: Valentin Longchamp, EPFL Mobots group */
-       .phys_io        = MX31_AIPS1_BASE_ADDR,
-       .io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx31_map_io,
        .init_irq       = mx31_init_irq,
index 1c30d7212f17901a6703cb33d687ddab926ad3cd..05f628d907250b5118c4e1ecb2df4e2e40a3c33c 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009 Marc Kleine-Budde, Pengutronix
  *
  * Author: Fabio Estevam <fabio.estevam@freescale.com>
  *
@@ -27,6 +28,8 @@
 #include <linux/gpio.h>
 #include <linux/fsl_devices.h>
 
+#include <linux/mtd/physmap.h>
+
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
@@ -35,6 +38,7 @@
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/iomux-mx35.h>
+#include <mach/mxc_ehci.h>
 
 #include "devices-imx35.h"
 #include "devices.h"
@@ -43,8 +47,34 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
+static struct physmap_flash_data mx35pdk_flash_data = {
+       .width  = 2,
+};
+
+static struct resource mx35pdk_flash_resource = {
+       .start  = MX35_CS0_BASE_ADDR,
+       .end    = MX35_CS0_BASE_ADDR + SZ_64M - 1,
+       .flags  = IORESOURCE_MEM,
+};
+
+static struct platform_device mx35pdk_flash = {
+       .name   = "physmap-flash",
+       .id     = 0,
+       .dev    = {
+               .platform_data  = &mx35pdk_flash_data,
+       },
+       .resource = &mx35pdk_flash_resource,
+       .num_resources = 1,
+};
+
+static const struct mxc_nand_platform_data mx35pdk_nand_board_info __initconst = {
+       .width = 1,
+       .hw_ecc = 1,
+       .flash_bbt = 1,
+};
+
 static struct platform_device *devices[] __initdata = {
-       &mxc_fec_device,
+       &mx35pdk_flash,
 };
 
 static struct pad_desc mx35pdk_pads[] = {
@@ -75,14 +105,24 @@ static struct pad_desc mx35pdk_pads[] = {
        /* USBOTG */
        MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR,
        MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC,
+       /* USBH1 */
+       MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR,
+       MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC,
 };
 
 /* OTG config */
-static struct fsl_usb2_platform_data usb_pdata = {
+static struct fsl_usb2_platform_data usb_otg_pdata = {
        .operating_mode = FSL_USB2_DR_DEVICE,
        .phy_mode       = FSL_USB2_PHY_UTMI_WIDE,
 };
 
+/* USB HOST config */
+static struct mxc_usbh_platform_data usb_host_pdata = {
+       .portsc         = MXC_EHCI_MODE_SERIAL,
+       .flags          = MXC_EHCI_INTERFACE_SINGLE_UNI |
+                         MXC_EHCI_INTERNAL_PHY,
+};
+
 /*
  * Board specific initialization.
  */
@@ -90,11 +130,16 @@ static void __init mxc_board_init(void)
 {
        mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads));
 
+       imx35_add_fec(NULL);
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
        imx35_add_imx_uart0(&uart_pdata);
 
-       mxc_register_device(&mxc_otg_udc_device, &usb_pdata);
+       mxc_register_device(&mxc_otg_udc_device, &usb_otg_pdata);
+
+       mxc_register_device(&mxc_usbh1, &usb_host_pdata);
+
+       imx35_add_mxc_nand(&mx35pdk_nand_board_info);
 }
 
 static void __init mx35pdk_timer_init(void)
@@ -108,8 +153,6 @@ struct sys_timer mx35pdk_timer = {
 
 MACHINE_START(MX35_3DS, "Freescale MX35PDK")
        /* Maintainer: Freescale Semiconductor, Inc */
-       .phys_io        = MX35_AIPS1_BASE_ADDR,
-       .io_pg_offst    = ((MX35_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx35_map_io,
        .init_irq       = mx35_init_irq,
index 214de11b20b919ece5a33c0041d8f8a62571f5e9..86e86c1300d5525352ed8d2b3dee50162eef89d9 100644 (file)
@@ -680,8 +680,6 @@ struct sys_timer pcm037_timer = {
 
 MACHINE_START(PCM037, "Phytec Phycore pcm037")
        /* Maintainer: Pengutronix */
-       .phys_io        = MX31_AIPS1_BASE_ADDR,
-       .io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx31_map_io,
        .init_irq       = mx31_init_irq,
index c8b98218efeec9d32882333faa52c41458ce2f37..99e0894e07db320f3e4bbd668768b24803b62f1c 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "pcm037.h"
 #include "devices.h"
+#include "devices-imx31.h"
 
 static unsigned int pcm037_eet_pins[] = {
        /* Reserve and hardwire GPIO 57 high - S6E63D6 chipselect */
@@ -181,7 +182,7 @@ static int eet_init_devices(void)
        /* SPI */
        spi_register_board_info(pcm037_spi_dev, ARRAY_SIZE(pcm037_spi_dev));
 #if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
-       imx35_add_spi_imx0(&pcm037_spi1_pdata);
+       imx31_add_spi_imx0(&pcm037_spi1_pdata);
 #endif
 
        platform_device_register(&pcm037_gpio_keys_device);
index 28886f0e62f97de762c015e5d9db2fdf4f84f400..4e1de87995d48da64c76bb558abf3bbab815919f 100644 (file)
@@ -42,7 +42,6 @@
 #include <mach/mxc_ehci.h>
 #include <mach/ulpi.h>
 #include <mach/audmux.h>
-#include <mach/ssi.h>
 
 #include "devices-imx35.h"
 #include "devices.h"
@@ -141,7 +140,6 @@ static struct i2c_board_info pcm043_i2c_devices[] = {
 
 static struct platform_device *devices[] __initdata = {
        &pcm043_flash,
-       &mxc_fec_device,
        &imx_wdt_device0,
 };
 
@@ -217,6 +215,13 @@ static struct pad_desc pcm043_pads[] = {
        /* CAN2 */
        MX35_PAD_TX5_RX0__CAN2_TXCAN,
        MX35_PAD_TX4_RX1__CAN2_RXCAN,
+       /* esdhc */
+       MX35_PAD_SD1_CMD__ESDHC1_CMD,
+       MX35_PAD_SD1_CLK__ESDHC1_CLK,
+       MX35_PAD_SD1_DATA0__ESDHC1_DAT0,
+       MX35_PAD_SD1_DATA1__ESDHC1_DAT1,
+       MX35_PAD_SD1_DATA2__ESDHC1_DAT2,
+       MX35_PAD_SD1_DATA3__ESDHC1_DAT3,
 };
 
 #define AC97_GPIO_TXFS (1 * 32 + 31)
@@ -293,7 +298,7 @@ err1:
        mdelay(1);
 }
 
-static struct imx_ssi_platform_data pcm043_ssi_pdata = {
+static const struct imx_ssi_platform_data pcm043_ssi_pdata __initconst = {
        .ac97_reset = pcm043_ac97_cold_reset,
        .ac97_warm_reset = pcm043_ac97_warm_reset,
        .flags = IMX_SSI_USE_AC97,
@@ -357,11 +362,12 @@ static void __init mxc_board_init(void)
                        MXC_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */
                        MXC_AUDMUX_V2_PDCR_RXDSEL(3));
 
+       imx35_add_fec(NULL);
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
        imx35_add_imx_uart0(&uart_pdata);
        imx35_add_mxc_nand(&pcm037_nand_board_info);
-       mxc_register_device(&imx_ssi_device0, &pcm043_ssi_pdata);
+       imx35_add_imx_ssi(0, &pcm043_ssi_pdata);
 
        imx35_add_imx_uart1(&uart_pdata);
 
@@ -389,6 +395,7 @@ static void __init mxc_board_init(void)
                mxc_register_device(&mxc_otg_udc_device, &otg_device_pdata);
 
        imx35_add_flexcan1(NULL);
+       imx35_add_esdhc(0, NULL);
 }
 
 static void __init pcm043_timer_init(void)
@@ -402,8 +409,6 @@ struct sys_timer pcm043_timer = {
 
 MACHINE_START(PCM043, "Phytec Phycore pcm043")
        /* Maintainer: Pengutronix */
-       .phys_io        = MX35_AIPS1_BASE_ADDR,
-       .io_pg_offst    = ((MX35_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx35_map_io,
        .init_irq       = mx35_init_irq,
index c8c380eef74c7d9f4ac6d3ef5b4d7dd38343f9eb..fd1050c40964cac1d42d450026f810fd0ae25af4 100644 (file)
@@ -270,8 +270,6 @@ static struct sys_timer qong_timer = {
 
 MACHINE_START(QONG, "Dave/DENX QongEVB-LITE")
        /* Maintainer: DENX Software Engineering GmbH */
-       .phys_io        = MX31_AIPS1_BASE_ADDR,
-       .io_pg_offst    = (MX31_AIPS1_BASE_ADDR_VIRT >> 18) & 0xfffc,
        .boot_params    = MX3x_PHYS_OFFSET + 0x100,
        .map_io         = mx31_map_io,
        .init_irq       = mx31_init_irq,
index 20e48c0195c4f8533c7d43113f0ce3965c0ef143..b4ffc531a82c41894d5eaff063765b0319a08a2e 100644 (file)
@@ -110,6 +110,24 @@ void __init mx35_init_irq(void)
 static int mxc_init_l2x0(void)
 {
        void __iomem *l2x0_base;
+       void __iomem *clkctl_base;
+/*
+ * First of all, we must repair broken chip settings. There are some
+ * i.MX35 CPUs in the wild, comming with bogus L2 cache settings. These
+ * misconfigured CPUs will run amok immediately when the L2 cache gets enabled.
+ * Workaraound is to setup the correct register setting prior enabling the
+ * L2 cache. This should not hurt already working CPUs, as they are using the
+ * same value
+ */
+#define L2_MEM_VAL 0x10
+
+       clkctl_base = ioremap(MX35_CLKCTL_BASE_ADDR, 4096);
+       if (clkctl_base != NULL) {
+               writel(0x00000515, clkctl_base + L2_MEM_VAL);
+               iounmap(clkctl_base);
+       } else {
+               pr_err("L2 cache: Cannot fix timing. Trying to continue without\n");
+       }
 
        l2x0_base = ioremap(L2CC_BASE_ADDR, 4096);
        if (IS_ERR(l2x0_base)) {
index 0848db5dd364dd5bb5b90ae03f3accf6eeb711aa..a2df9ac379964944ca12cd8e81d750d6f2073ddd 100644 (file)
@@ -5,11 +5,14 @@ config ARCH_MX51
        default y
        select MXC_TZIC
        select ARCH_MXC_IOMUX_V3
+       select ARCH_MXC_AUDMUX_V2
 
 comment "MX5 platforms:"
 
 config MACH_MX51_BABBAGE
        bool "Support MX51 BABBAGE platforms"
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
        help
          Include support for MX51 Babbage platform, also known as MX51EVK in
          u-boot. This includes specific configurations for the board and its
@@ -17,6 +20,8 @@ config MACH_MX51_BABBAGE
 
 config MACH_MX51_3DS
        bool "Support MX51PDK (3DS)"
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_SPI_IMX
        select MXC_DEBUG_BOARD
        help
          Include support for MX51PDK (3DS) platform. This includes specific
@@ -24,6 +29,10 @@ config MACH_MX51_3DS
 
 config MACH_EUKREA_CPUIMX51
        bool "Support Eukrea CPUIMX51 module"
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
+       select IMX_HAVE_PLATFORM_SPI_IMX
        help
          Include support for Eukrea CPUIMX51 platform. This includes
          specific configurations for the module and its peripherals.
@@ -36,10 +45,43 @@ choice
 config MACH_EUKREA_MBIMX51_BASEBOARD
        prompt "Eukrea MBIMX51 development board"
        bool
+       select IMX_HAVE_PLATFORM_ESDHC
        help
          This adds board specific devices that can be found on Eukrea's
          MBIMX51 evaluation board.
 
 endchoice
 
+config MACH_EUKREA_CPUIMX51SD
+       bool "Support Eukrea CPUIMX51SD module"
+       select IMX_HAVE_PLATFORM_IMX_I2C
+       select IMX_HAVE_PLATFORM_SPI_IMX
+       select IMX_HAVE_PLATFORM_IMX_UART
+       select IMX_HAVE_PLATFORM_MXC_NAND
+       help
+         Include support for Eukrea CPUIMX51SD platform. This includes
+         specific configurations for the module and its peripherals.
+
+choice
+       prompt "Baseboard"
+       depends on MACH_EUKREA_CPUIMX51SD
+       default MACH_EUKREA_MBIMXSD51_BASEBOARD
+
+config MACH_EUKREA_MBIMXSD51_BASEBOARD
+       prompt "Eukrea MBIMXSD development board"
+       bool
+       select IMX_HAVE_PLATFORM_ESDHC
+       help
+         This adds board specific devices that can be found on Eukrea's
+         MBIMXSD evaluation board.
+
+endchoice
+
+config MACH_MX51_EFIKAMX
+       bool "Support MX51 Genesi Efika MX nettop"
+       select IMX_HAVE_PLATFORM_IMX_UART
+       help
+         Include support for Genesi Efika MX nettop. This includes specific
+         configurations for the board and its peripherals.
+
 endif
index 86c66e7f52f3dc0855509587703e6972de2c483e..1769c161a60d48dc3db84277fb0c80be7d931152 100644 (file)
@@ -9,3 +9,6 @@ obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o
 obj-$(CONFIG_MACH_MX51_3DS) += board-mx51_3ds.o
 obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += board-cpuimx51.o
 obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o
+obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += board-cpuimx51sd.o
+obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd-baseboard.o
+obj-$(CONFIG_MACH_MX51_EFIKAMX) += board-mx51_efikamx.o
index 623607a20f57c19c331629e5761fb23aca7cb842..6a9792fd0a763ed6b2d281e98b5cfc3bf3d67562 100644 (file)
@@ -28,9 +28,7 @@
 #include <mach/eukrea-baseboards.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx51.h>
-#include <mach/i2c.h>
 #include <mach/mxc_ehci.h>
 
 #include <asm/irq.h>
@@ -39,6 +37,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 
+#include "devices-imx51.h"
 #include "devices.h"
 
 #define CPUIMX51_USBH1_STP     (0*32 + 27)
@@ -109,7 +108,6 @@ static struct platform_device serial_device = {
 #endif
 
 static struct platform_device *devices[] __initdata = {
-       &mxc_fec_device,
 #if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
        &serial_device,
 #endif
@@ -148,11 +146,19 @@ static struct pad_desc eukrea_cpuimx51_pads[] = {
        MX51_PAD_USBH1_STP__USBH1_STP,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct mxc_nand_platform_data
+               eukrea_cpuimx51_nand_board_info __initconst = {
+       .width          = 1,
+       .hw_ecc         = 1,
+       .flash_bbt      = 1,
+};
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
-static struct imxi2c_platform_data eukrea_cpuimx51_i2c_data = {
+static const
+struct imxi2c_platform_data eukrea_cpuimx51_i2c_data __initconst = {
        .bitrate = 100000,
 };
 
@@ -239,7 +245,9 @@ static void __init eukrea_cpuimx51_init(void)
        mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51_pads,
                                        ARRAY_SIZE(eukrea_cpuimx51_pads));
 
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
+       imx51_add_imx_uart(0, &uart_pdata);
+       imx51_add_mxc_nand(&eukrea_cpuimx51_nand_board_info);
+
        gpio_request(CPUIMX51_QUARTA_GPIO, "quarta_irq");
        gpio_direction_input(CPUIMX51_QUARTA_GPIO);
        gpio_free(CPUIMX51_QUARTA_GPIO);
@@ -253,9 +261,10 @@ static void __init eukrea_cpuimx51_init(void)
        gpio_direction_input(CPUIMX51_QUARTD_GPIO);
        gpio_free(CPUIMX51_QUARTD_GPIO);
 
+       imx51_add_fec(NULL);
        platform_add_devices(devices, ARRAY_SIZE(devices));
 
-       mxc_register_device(&mxc_i2c_device1, &eukrea_cpuimx51_i2c_data);
+       imx51_add_imx_i2c(1, &eukrea_cpuimx51_i2c_data);
        i2c_register_board_info(1, eukrea_cpuimx51_i2c_devices,
                                ARRAY_SIZE(eukrea_cpuimx51_i2c_devices));
 
@@ -283,8 +292,6 @@ static struct sys_timer mxc_timer = {
 
 MACHINE_START(EUKREA_CPUIMX51, "Eukrea CPUIMX51 Module")
        /* Maintainer: Eric Bénard <eric@eukrea.com> */
-       .phys_io = MX51_AIPS1_BASE_ADDR,
-       .io_pg_offst = ((MX51_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params = PHYS_OFFSET + 0x100,
        .map_io = mx51_map_io,
        .init_irq = mx51_init_irq,
diff --git a/arch/arm/mach-mx5/board-cpuimx51sd.c b/arch/arm/mach-mx5/board-cpuimx51sd.c
new file mode 100644 (file)
index 0000000..4b3a611
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ *
+ * Copyright (C) 2010 Eric Bénard <eric@eukrea.com>
+ *
+ * based on board-mx51_babbage.c which is
+ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.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
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/i2c/tsc2007.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/fsl_devices.h>
+#include <linux/i2c-gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/can/platform/mcp251x.h>
+
+#include <mach/eukrea-baseboards.h>
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/iomux-mx51.h>
+#include <mach/mxc_ehci.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include "devices-imx51.h"
+#include "devices.h"
+
+#define USBH1_RST              (1*32 + 28)
+#define ETH_RST                        (1*32 + 31)
+#define TSC2007_IRQGPIO                (2*32 + 12)
+#define CAN_IRQGPIO            (0*32 + 1)
+#define CAN_RST                        (3*32 + 15)
+#define CAN_NCS                        (3*32 + 24)
+#define CAN_RXOBF              (0*32 + 4)
+#define CAN_RX1BF              (0*32 + 6)
+#define CAN_TXORTS             (0*32 + 7)
+#define CAN_TX1RTS             (0*32 + 8)
+#define CAN_TX2RTS             (0*32 + 9)
+#define I2C_SCL                        (3*32 + 16)
+#define I2C_SDA                        (3*32 + 17)
+
+/* USB_CTRL_1 */
+#define MX51_USB_CTRL_1_OFFSET         0x10
+#define MX51_USB_CTRL_UH1_EXT_CLK_EN   (1 << 25)
+
+#define        MX51_USB_PLLDIV_12_MHZ          0x00
+#define        MX51_USB_PLL_DIV_19_2_MHZ       0x01
+#define        MX51_USB_PLL_DIV_24_MHZ         0x02
+
+#define CPUIMX51SD_GPIO_3_12 IOMUX_PAD(0x57C, 0x194, 3, 0x0, 0, \
+                               MX51_PAD_CTRL_1 | PAD_CTL_PUS_22K_UP)
+
+static struct pad_desc eukrea_cpuimx51sd_pads[] = {
+       /* UART1 */
+       MX51_PAD_UART1_RXD__UART1_RXD,
+       MX51_PAD_UART1_TXD__UART1_TXD,
+       MX51_PAD_UART1_RTS__UART1_RTS,
+       MX51_PAD_UART1_CTS__UART1_CTS,
+
+       /* USB HOST1 */
+       MX51_PAD_USBH1_CLK__USBH1_CLK,
+       MX51_PAD_USBH1_DIR__USBH1_DIR,
+       MX51_PAD_USBH1_NXT__USBH1_NXT,
+       MX51_PAD_USBH1_DATA0__USBH1_DATA0,
+       MX51_PAD_USBH1_DATA1__USBH1_DATA1,
+       MX51_PAD_USBH1_DATA2__USBH1_DATA2,
+       MX51_PAD_USBH1_DATA3__USBH1_DATA3,
+       MX51_PAD_USBH1_DATA4__USBH1_DATA4,
+       MX51_PAD_USBH1_DATA5__USBH1_DATA5,
+       MX51_PAD_USBH1_DATA6__USBH1_DATA6,
+       MX51_PAD_USBH1_DATA7__USBH1_DATA7,
+       MX51_PAD_USBH1_STP__USBH1_STP,
+       MX51_PAD_EIM_CS3__GPIO_2_28,            /* PHY nRESET */
+
+       /* FEC */
+       MX51_PAD_EIM_DTACK__GPIO_2_31,          /* PHY nRESET */
+
+       /* HSI2C */
+       MX51_PAD_I2C1_CLK__GPIO_4_16,
+       MX51_PAD_I2C1_DAT__GPIO_4_17,
+
+       /* CAN */
+       MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI,
+       MX51_PAD_CSPI1_MISO__ECSPI1_MISO,
+       MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK,
+       MX51_PAD_CSPI1_SS0__GPIO_4_24,          /* nCS */
+       MX51_PAD_CSI2_PIXCLK__GPIO_4_15,        /* nReset */
+       MX51_PAD_GPIO_1_1__GPIO_1_1,            /* IRQ */
+       MX51_PAD_GPIO_1_4__GPIO_1_4,            /* Control signals */
+       MX51_PAD_GPIO_1_6__GPIO_1_6,
+       MX51_PAD_GPIO_1_7__GPIO_1_7,
+       MX51_PAD_GPIO_1_8__GPIO_1_8,
+       MX51_PAD_GPIO_1_9__GPIO_1_9,
+
+       /* Touchscreen */
+       CPUIMX51SD_GPIO_3_12,                   /* IRQ */
+};
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static int ts_get_pendown_state(void)
+{
+       return gpio_get_value(TSC2007_IRQGPIO) ? 0 : 1;
+}
+
+static struct tsc2007_platform_data tsc2007_info = {
+       .model                  = 2007,
+       .x_plate_ohms           = 180,
+       .get_pendown_state      = ts_get_pendown_state,
+};
+
+static struct i2c_board_info eukrea_cpuimx51sd_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("pcf8563", 0x51),
+       }, {
+               I2C_BOARD_INFO("tsc2007", 0x49),
+               .type           = "tsc2007",
+               .platform_data  = &tsc2007_info,
+               .irq            = gpio_to_irq(TSC2007_IRQGPIO),
+       },
+};
+
+static const struct mxc_nand_platform_data
+               eukrea_cpuimx51sd_nand_board_info __initconst = {
+       .width          = 1,
+       .hw_ecc         = 1,
+       .flash_bbt      = 1,
+};
+
+/* This function is board specific as the bit mask for the plldiv will also
+be different for other Freescale SoCs, thus a common bitmask is not
+possible and cannot get place in /plat-mxc/ehci.c.*/
+static int initialize_otg_port(struct platform_device *pdev)
+{
+       u32 v;
+       void __iomem *usb_base;
+       void __iomem *usbother_base;
+
+       usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+       usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+       /* Set the PHY clock to 19.2MHz */
+       v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+       v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
+       v |= MX51_USB_PLL_DIV_19_2_MHZ;
+       __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+       iounmap(usb_base);
+       return 0;
+}
+
+static int initialize_usbh1_port(struct platform_device *pdev)
+{
+       u32 v;
+       void __iomem *usb_base;
+       void __iomem *usbother_base;
+
+       usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+       usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
+
+       /* The clock for the USBH1 ULPI port will come from the PHY. */
+       v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET);
+       __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN,
+                       usbother_base + MX51_USB_CTRL_1_OFFSET);
+       iounmap(usb_base);
+       return 0;
+}
+
+static struct mxc_usbh_platform_data dr_utmi_config = {
+       .init           = initialize_otg_port,
+       .portsc = MXC_EHCI_UTMI_16BIT,
+       .flags  = MXC_EHCI_INTERNAL_PHY,
+};
+
+static struct fsl_usb2_platform_data usb_pdata = {
+       .operating_mode = FSL_USB2_DR_DEVICE,
+       .phy_mode       = FSL_USB2_PHY_UTMI_WIDE,
+};
+
+static struct mxc_usbh_platform_data usbh1_config = {
+       .init           = initialize_usbh1_port,
+       .portsc = MXC_EHCI_MODE_ULPI,
+       .flags  = (MXC_EHCI_POWER_PINS_ENABLED | MXC_EHCI_ITC_NO_THRESHOLD),
+};
+
+static int otg_mode_host;
+
+static int __init eukrea_cpuimx51sd_otg_mode(char *options)
+{
+       if (!strcmp(options, "host"))
+               otg_mode_host = 1;
+       else if (!strcmp(options, "device"))
+               otg_mode_host = 0;
+       else
+               pr_info("otg_mode neither \"host\" nor \"device\". "
+                       "Defaulting to device\n");
+       return 0;
+}
+__setup("otg_mode=", eukrea_cpuimx51sd_otg_mode);
+
+static struct i2c_gpio_platform_data pdata = {
+       .sda_pin                = I2C_SDA,
+       .sda_is_open_drain      = 0,
+       .scl_pin                = I2C_SCL,
+       .scl_is_open_drain      = 0,
+       .udelay                 = 2,
+};
+
+static struct platform_device hsi2c_gpio_device = {
+       .name                   = "i2c-gpio",
+       .id                     = 0,
+       .dev.platform_data      = &pdata,
+};
+
+static struct mcp251x_platform_data mcp251x_info = {
+       .oscillator_frequency = 24E6,
+};
+
+static struct spi_board_info cpuimx51sd_spi_device[] = {
+       {
+               .modalias        = "mcp2515",
+               .max_speed_hz    = 6500000,
+               .bus_num         = 0,
+               .mode           = SPI_MODE_0,
+               .chip_select     = 0,
+               .platform_data   = &mcp251x_info,
+               .irq             = gpio_to_irq(0 * 32 + 1)
+       },
+};
+
+static int cpuimx51sd_spi1_cs[] = {
+       CAN_NCS,
+};
+
+static const struct spi_imx_master cpuimx51sd_ecspi1_pdata __initconst = {
+       .chipselect     = cpuimx51sd_spi1_cs,
+       .num_chipselect = ARRAY_SIZE(cpuimx51sd_spi1_cs),
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+       &hsi2c_gpio_device,
+};
+
+static void __init eukrea_cpuimx51sd_init(void)
+{
+       mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51sd_pads,
+                                       ARRAY_SIZE(eukrea_cpuimx51sd_pads));
+
+       imx51_add_imx_uart(0, &uart_pdata);
+       imx51_add_mxc_nand(&eukrea_cpuimx51sd_nand_board_info);
+
+       gpio_request(ETH_RST, "eth_rst");
+       gpio_set_value(ETH_RST, 1);
+       imx51_add_fec(NULL);
+
+       gpio_request(CAN_IRQGPIO, "can_irq");
+       gpio_direction_input(CAN_IRQGPIO);
+       gpio_free(CAN_IRQGPIO);
+       gpio_request(CAN_NCS, "can_ncs");
+       gpio_direction_output(CAN_NCS, 1);
+       gpio_free(CAN_NCS);
+       gpio_request(CAN_RST, "can_rst");
+       gpio_direction_output(CAN_RST, 0);
+       msleep(20);
+       gpio_set_value(CAN_RST, 1);
+       imx51_add_ecspi(0, &cpuimx51sd_ecspi1_pdata);
+       spi_register_board_info(cpuimx51sd_spi_device,
+                               ARRAY_SIZE(cpuimx51sd_spi_device));
+
+       gpio_request(TSC2007_IRQGPIO, "tsc2007_irq");
+       gpio_direction_input(TSC2007_IRQGPIO);
+       gpio_free(TSC2007_IRQGPIO);
+
+       i2c_register_board_info(0, eukrea_cpuimx51sd_i2c_devices,
+                       ARRAY_SIZE(eukrea_cpuimx51sd_i2c_devices));
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+
+       if (otg_mode_host)
+               mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config);
+       else {
+               initialize_otg_port(NULL);
+               mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata);
+       }
+
+       gpio_request(USBH1_RST, "usb_rst");
+       gpio_direction_output(USBH1_RST, 0);
+       msleep(20);
+       gpio_set_value(USBH1_RST, 1);
+       mxc_register_device(&mxc_usbh1_device, &usbh1_config);
+
+#ifdef CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD
+       eukrea_mbimxsd51_baseboard_init();
+#endif
+}
+
+static void __init eukrea_cpuimx51sd_timer_init(void)
+{
+       mx51_clocks_init(32768, 24000000, 22579200, 0);
+}
+
+static struct sys_timer mxc_timer = {
+       .init   = eukrea_cpuimx51sd_timer_init,
+};
+
+MACHINE_START(EUKREA_CPUIMX51SD, "Eukrea CPUIMX51SD")
+       /* Maintainer: Eric Bénard <eric@eukrea.com> */
+       .boot_params = PHYS_OFFSET + 0x100,
+       .map_io = mx51_map_io,
+       .init_irq = mx51_init_irq,
+       .init_machine = eukrea_cpuimx51sd_init,
+       .timer = &mxc_timer,
+MACHINE_END
index f95c2fd94667c25ee97a5be10c95782d26cb5095..79ce8dcf3cda5bd26829be57a7b647c032b3ecad 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/input/matrix_keypad.h>
+#include <linux/spi/spi.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/iomux-mx51.h>
-#include <mach/imx-uart.h>
 #include <mach/3ds_debugboard.h>
 
+#include "devices-imx51.h"
 #include "devices.h"
 
 #define EXPIO_PARENT_INT       (MXC_INTERNAL_IRQS + GPIO_PORTA + 6)
+#define MX51_3DS_ECSPI2_CS     (GPIO_PORTC + 28)
 
 static struct pad_desc mx51_3ds_pads[] = {
        /* UART1 */
@@ -61,19 +63,25 @@ static struct pad_desc mx51_3ds_pads[] = {
        MX51_PAD_KEY_COL3__KEY_COL3,
        MX51_PAD_KEY_COL4__KEY_COL4,
        MX51_PAD_KEY_COL5__KEY_COL5,
+
+       /* eCSPI2 */
+       MX51_PAD_NANDF_RB2__ECSPI2_SCLK,
+       MX51_PAD_NANDF_RB3__ECSPI2_MISO,
+       MX51_PAD_NANDF_D15__ECSPI2_MOSI,
+       MX51_PAD_NANDF_D12__GPIO_3_28,
 };
 
 /* Serial ports */
 #if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
 static inline void mxc_init_imx_uart(void)
 {
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
-       mxc_register_device(&mxc_uart_device1, &uart_pdata);
-       mxc_register_device(&mxc_uart_device2, &uart_pdata);
+       imx51_add_imx_uart(0, &uart_pdata);
+       imx51_add_imx_uart(1, &uart_pdata);
+       imx51_add_imx_uart(2, &uart_pdata);
 }
 #else /* !SERIAL_IMX */
 static inline void mxc_init_imx_uart(void)
@@ -127,6 +135,26 @@ static inline void mxc_init_keypad(void)
 }
 #endif
 
+static int mx51_3ds_spi2_cs[] = {
+       MXC_SPI_CS(0),
+       MX51_3DS_ECSPI2_CS,
+};
+
+static const struct spi_imx_master mx51_3ds_ecspi2_pdata __initconst = {
+       .chipselect     = mx51_3ds_spi2_cs,
+       .num_chipselect = ARRAY_SIZE(mx51_3ds_spi2_cs),
+};
+
+static struct spi_board_info mx51_3ds_spi_nor_device[] = {
+       {
+        .modalias = "m25p80",
+        .max_speed_hz = 25000000,      /* max spi clock (SCK) speed in HZ */
+        .bus_num = 1,
+        .chip_select = 1,
+        .mode = SPI_MODE_0,
+        .platform_data = NULL,},
+};
+
 /*
  * Board specific initialization.
  */
@@ -136,6 +164,10 @@ static void __init mxc_board_init(void)
                                        ARRAY_SIZE(mx51_3ds_pads));
        mxc_init_imx_uart();
 
+       imx51_add_ecspi(1, &mx51_3ds_ecspi2_pdata);
+       spi_register_board_info(mx51_3ds_spi_nor_device,
+                               ARRAY_SIZE(mx51_3ds_spi_nor_device));
+
        if (mxc_expio_init(MX51_CS5_BASE_ADDR, EXPIO_PARENT_INT))
                printk(KERN_WARNING "Init of the debugboard failed, all "
                                    "devices on the board are unusable.\n");
@@ -154,8 +186,6 @@ static struct sys_timer mxc_timer = {
 
 MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board")
        /* Maintainer: Freescale Semiconductor, Inc. */
-       .phys_io = MX51_AIPS1_BASE_ADDR,
-       .io_pg_offst = ((MX51_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params = PHYS_OFFSET + 0x100,
        .map_io = mx51_map_io,
        .init_irq = mx51_init_irq,
index 6e384d92e625d107279c14228964553525aa6c53..0821fe9b3b27c01afe9942a9137e1a0627fe46d9 100644 (file)
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/fsl_devices.h>
+#include <linux/fec.h>
 
 #include <mach/common.h>
 #include <mach/hardware.h>
-#include <mach/imx-uart.h>
 #include <mach/iomux-mx51.h>
-#include <mach/i2c.h>
 #include <mach/mxc_ehci.h>
 
 #include <asm/irq.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 
+#include "devices-imx51.h"
 #include "devices.h"
 
 #define BABBAGE_USB_HUB_RESET  (0*32 + 7)      /* GPIO_1_7 */
 #define BABBAGE_USBH1_STP      (0*32 + 27)     /* GPIO_1_27 */
-#define BABBAGE_PHY_RESET (1*32 +5)    /* GPIO_2_5 */
+#define BABBAGE_PHY_RESET      (1*32 + 5)      /* GPIO_2_5 */
+#define BABBAGE_FEC_PHY_RESET  (1*32 + 14)     /* GPIO_2_14 */
 
 /* USB_CTRL_1 */
 #define MX51_USB_CTRL_1_OFFSET                 0x10
 #define        MX51_USB_PLL_DIV_19_2_MHZ       0x01
 #define        MX51_USB_PLL_DIV_24_MHZ 0x02
 
-static struct platform_device *devices[] __initdata = {
-       &mxc_fec_device,
-};
-
 static struct pad_desc mx51babbage_pads[] = {
        /* UART1 */
        MX51_PAD_UART1_RXD__UART1_RXD,
@@ -93,19 +90,41 @@ static struct pad_desc mx51babbage_pads[] = {
 
        /* USB HUB reset line*/
        MX51_PAD_GPIO_1_7__GPIO_1_7,
+
+       /* FEC */
+       MX51_PAD_EIM_EB2__FEC_MDIO,
+       MX51_PAD_EIM_EB3__FEC_RDAT1,
+       MX51_PAD_EIM_CS2__FEC_RDAT2,
+       MX51_PAD_EIM_CS3__FEC_RDAT3,
+       MX51_PAD_EIM_CS4__FEC_RX_ER,
+       MX51_PAD_EIM_CS5__FEC_CRS,
+       MX51_PAD_NANDF_RB2__FEC_COL,
+       MX51_PAD_NANDF_RB3__FEC_RXCLK,
+       MX51_PAD_NANDF_RB6__FEC_RDAT0,
+       MX51_PAD_NANDF_RB7__FEC_TDAT0,
+       MX51_PAD_NANDF_CS2__FEC_TX_ER,
+       MX51_PAD_NANDF_CS3__FEC_MDC,
+       MX51_PAD_NANDF_CS4__FEC_TDAT1,
+       MX51_PAD_NANDF_CS5__FEC_TDAT2,
+       MX51_PAD_NANDF_CS6__FEC_TDAT3,
+       MX51_PAD_NANDF_CS7__FEC_TX_EN,
+       MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK,
+
+       /* FEC PHY reset line */
+       MX51_PAD_EIM_A20__GPIO_2_14,
 };
 
 /* Serial ports */
 #if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
 static inline void mxc_init_imx_uart(void)
 {
-       mxc_register_device(&mxc_uart_device0, &uart_pdata);
-       mxc_register_device(&mxc_uart_device1, &uart_pdata);
-       mxc_register_device(&mxc_uart_device2, &uart_pdata);
+       imx51_add_imx_uart(0, &uart_pdata);
+       imx51_add_imx_uart(1, &uart_pdata);
+       imx51_add_imx_uart(2, &uart_pdata);
 }
 #else /* !SERIAL_IMX */
 static inline void mxc_init_imx_uart(void)
@@ -113,7 +132,7 @@ static inline void mxc_init_imx_uart(void)
 }
 #endif /* SERIAL_IMX */
 
-static struct imxi2c_platform_data babbage_i2c_data = {
+static const struct imxi2c_platform_data babbage_i2c_data __initconst = {
        .bitrate = 100000,
 };
 
@@ -171,6 +190,22 @@ static inline void babbage_usbhub_reset(void)
        gpio_set_value(BABBAGE_USB_HUB_RESET, 1);
 }
 
+static inline void babbage_fec_reset(void)
+{
+       int ret;
+
+       /* reset FEC PHY */
+       ret = gpio_request(BABBAGE_FEC_PHY_RESET, "fec-phy-reset");
+       if (ret) {
+               printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret);
+               return;
+       }
+       gpio_direction_output(BABBAGE_FEC_PHY_RESET, 0);
+       gpio_set_value(BABBAGE_FEC_PHY_RESET, 0);
+       msleep(1);
+       gpio_set_value(BABBAGE_FEC_PHY_RESET, 1);
+}
+
 /* This function is board specific as the bit mask for the plldiv will also
 be different for other Freescale SoCs, thus a common bitmask is not
 possible and cannot get place in /plat-mxc/ehci.c.*/
@@ -178,7 +213,7 @@ static int initialize_otg_port(struct platform_device *pdev)
 {
        u32 v;
        void __iomem *usb_base;
-       u32 usbother_base;
+       void __iomem *usbother_base;
 
        usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
        usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
@@ -196,7 +231,7 @@ static int initialize_usbh1_port(struct platform_device *pdev)
 {
        u32 v;
        void __iomem *usb_base;
-       u32 usbother_base;
+       void __iomem *usbother_base;
 
        usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
        usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET;
@@ -250,10 +285,11 @@ static void __init mxc_board_init(void)
        mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads,
                                        ARRAY_SIZE(mx51babbage_pads));
        mxc_init_imx_uart();
-       platform_add_devices(devices, ARRAY_SIZE(devices));
+       babbage_fec_reset();
+       imx51_add_fec(NULL);
 
-       mxc_register_device(&mxc_i2c_device0, &babbage_i2c_data);
-       mxc_register_device(&mxc_i2c_device1, &babbage_i2c_data);
+       imx51_add_imx_i2c(0, &babbage_i2c_data);
+       imx51_add_imx_i2c(1, &babbage_i2c_data);
        mxc_register_device(&mxc_hsi2c_device, &babbage_hsi2c_data);
 
        if (otg_mode_host)
@@ -281,9 +317,7 @@ static struct sys_timer mxc_timer = {
 
 MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board")
        /* Maintainer: Amit Kucheria <amit.kucheria@canonical.com> */
-       .phys_io = MX51_AIPS1_BASE_ADDR,
-       .io_pg_offst = ((MX51_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
-       .boot_params = PHYS_OFFSET + 0x100,
+       .boot_params = MX51_PHYS_OFFSET + 0x100,
        .map_io = mx51_map_io,
        .init_irq = mx51_init_irq,
        .init_machine = mxc_board_init,
diff --git a/arch/arm/mach-mx5/board-mx51_efikamx.c b/arch/arm/mach-mx5/board-mx51_efikamx.c
new file mode 100644 (file)
index 0000000..6e623bd
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2010 Linaro Limited
+ *
+ * based on code from the following
+ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2009-2010 Pegatron Corporation. All Rights Reserved.
+ * Copyright 2009-2010 Genesi USA, 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/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/fsl_devices.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/iomux-mx51.h>
+#include <mach/i2c.h>
+#include <mach/mxc_ehci.h>
+
+#include <asm/irq.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include "devices-imx51.h"
+#include "devices.h"
+
+#define        MX51_USB_PLL_DIV_24_MHZ 0x01
+
+static struct pad_desc mx51efikamx_pads[] = {
+       /* UART1 */
+       MX51_PAD_UART1_RXD__UART1_RXD,
+       MX51_PAD_UART1_TXD__UART1_TXD,
+       MX51_PAD_UART1_RTS__UART1_RTS,
+       MX51_PAD_UART1_CTS__UART1_CTS,
+};
+
+/* Serial ports */
+#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
+static const struct imxuart_platform_data uart_pdata = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static inline void mxc_init_imx_uart(void)
+{
+       imx51_add_imx_uart(0, &uart_pdata);
+       imx51_add_imx_uart(1, &uart_pdata);
+       imx51_add_imx_uart(2, &uart_pdata);
+}
+#else /* !SERIAL_IMX */
+static inline void mxc_init_imx_uart(void)
+{
+}
+#endif /* SERIAL_IMX */
+
+/* This function is board specific as the bit mask for the plldiv will also
+ * be different for other Freescale SoCs, thus a common bitmask is not
+ * possible and cannot get place in /plat-mxc/ehci.c.
+ */
+static int initialize_otg_port(struct platform_device *pdev)
+{
+       u32 v;
+       void __iomem *usb_base;
+       void __iomem *usbother_base;
+       usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
+       usbother_base = (void __iomem *)(usb_base + MX5_USBOTHER_REGS_OFFSET);
+
+       /* Set the PHY clock to 19.2MHz */
+       v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+       v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK;
+       v |= MX51_USB_PLL_DIV_24_MHZ;
+       __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET);
+       iounmap(usb_base);
+       return 0;
+}
+
+static struct mxc_usbh_platform_data dr_utmi_config = {
+       .init   = initialize_otg_port,
+       .portsc = MXC_EHCI_UTMI_16BIT,
+       .flags  = MXC_EHCI_INTERNAL_PHY,
+};
+
+static void __init mxc_board_init(void)
+{
+       mxc_iomux_v3_setup_multiple_pads(mx51efikamx_pads,
+                                       ARRAY_SIZE(mx51efikamx_pads));
+       mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config);
+       mxc_init_imx_uart();
+}
+
+static void __init mx51_efikamx_timer_init(void)
+{
+       mx51_clocks_init(32768, 24000000, 22579200, 24576000);
+}
+
+static struct sys_timer mxc_timer = {
+       .init   = mx51_efikamx_timer_init,
+};
+
+MACHINE_START(MX51_EFIKAMX, "Genesi EfikaMX nettop")
+       /* Maintainer: Amit Kucheria <amit.kucheria@linaro.org> */
+       .boot_params = MX51_PHYS_OFFSET + 0x100,
+       .map_io = mx51_map_io,
+       .init_irq = mx51_init_irq,
+       .init_machine =  mxc_board_init,
+       .timer = &mxc_timer,
+MACHINE_END
index 57c10a9926cc5056668645ff39fe3ac07fed9969..f2aae92cf0e261992c1a8afb4bc3de15f0014c88 100644 (file)
@@ -41,34 +41,66 @@ static struct clk usboh3_clk;
 
 #define MAX_DPLL_WAIT_TRIES    1000 /* 1000 * udelay(1) = 1ms */
 
-static int _clk_ccgr_enable(struct clk *clk)
+/* calculate best pre and post dividers to get the required divider */
+static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post,
+       u32 max_pre, u32 max_post)
 {
-       u32 reg;
+       if (div >= max_pre * max_post) {
+               *pre = max_pre;
+               *post = max_post;
+       } else if (div >= max_pre) {
+               u32 min_pre, temp_pre, old_err, err;
+               min_pre = DIV_ROUND_UP(div, max_post);
+               old_err = max_pre;
+               for (temp_pre = max_pre; temp_pre >= min_pre; temp_pre--) {
+                       err = div % temp_pre;
+                       if (err == 0) {
+                               *pre = temp_pre;
+                               break;
+                       }
+                       err = temp_pre - err;
+                       if (err < old_err) {
+                               old_err = err;
+                               *pre = temp_pre;
+                       }
+               }
+               *post = DIV_ROUND_UP(div, *pre);
+       } else {
+               *pre = div;
+               *post = 1;
+       }
+}
+
+static void _clk_ccgr_setclk(struct clk *clk, unsigned mode)
+{
+       u32 reg = __raw_readl(clk->enable_reg);
+
+       reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
+       reg |= mode << clk->enable_shift;
 
-       reg = __raw_readl(clk->enable_reg);
-       reg |= MXC_CCM_CCGRx_MOD_ON << clk->enable_shift;
        __raw_writel(reg, clk->enable_reg);
+}
 
+static int _clk_ccgr_enable(struct clk *clk)
+{
+       _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_ON);
        return 0;
 }
 
 static void _clk_ccgr_disable(struct clk *clk)
 {
-       u32 reg;
-       reg = __raw_readl(clk->enable_reg);
-       reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
-       __raw_writel(reg, clk->enable_reg);
+       _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_OFF);
+}
 
+static int _clk_ccgr_enable_inrun(struct clk *clk)
+{
+       _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE);
+       return 0;
 }
 
 static void _clk_ccgr_disable_inwait(struct clk *clk)
 {
-       u32 reg;
-
-       reg = __raw_readl(clk->enable_reg);
-       reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift);
-       reg |= MXC_CCM_CCGRx_MOD_IDLE << clk->enable_shift;
-       __raw_writel(reg, clk->enable_reg);
+       _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE);
 }
 
 /*
@@ -542,60 +574,60 @@ static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent)
        return 0;
 }
 
-static unsigned long clk_uart_get_rate(struct clk *clk)
-{
-       u32 reg, prediv, podf;
-       unsigned long parent_rate;
+#define clk_nfc_set_parent     NULL
 
-       parent_rate = clk_get_rate(clk->parent);
-
-       reg = __raw_readl(MXC_CCM_CSCDR1);
-       prediv = ((reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
-                 MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) + 1;
-       podf = ((reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
-               MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET) + 1;
+static unsigned long clk_nfc_get_rate(struct clk *clk)
+{
+       unsigned long rate;
+       u32 reg, div;
 
-       return parent_rate / (prediv * podf);
+       reg = __raw_readl(MXC_CCM_CBCDR);
+       div = ((reg & MXC_CCM_CBCDR_NFC_PODF_MASK) >>
+              MXC_CCM_CBCDR_NFC_PODF_OFFSET) + 1;
+       rate = clk_get_rate(clk->parent) / div;
+       WARN_ON(rate == 0);
+       return rate;
 }
 
-static int _clk_uart_set_parent(struct clk *clk, struct clk *parent)
+static unsigned long clk_nfc_round_rate(struct clk *clk,
+                                               unsigned long rate)
 {
-       u32 reg, mux;
+       u32 div;
+       unsigned long parent_rate = clk_get_rate(clk->parent);
 
-       mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk,
-                      &lp_apm_clk);
-       reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_UART_CLK_SEL_MASK;
-       reg |= mux << MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET;
-       __raw_writel(reg, MXC_CCM_CSCMR1);
+       if (!rate)
+               return -EINVAL;
 
-       return 0;
-}
+       div = parent_rate / rate;
 
-static unsigned long clk_usboh3_get_rate(struct clk *clk)
-{
-       u32 reg, prediv, podf;
-       unsigned long parent_rate;
+       if (parent_rate % rate)
+               div++;
 
-       parent_rate = clk_get_rate(clk->parent);
+       if (div > 8)
+               return -EINVAL;
 
-       reg = __raw_readl(MXC_CCM_CSCDR1);
-       prediv = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK) >>
-                 MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET) + 1;
-       podf = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK) >>
-               MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET) + 1;
+       return parent_rate / div;
 
-       return parent_rate / (prediv * podf);
 }
 
-static int _clk_usboh3_set_parent(struct clk *clk, struct clk *parent)
+static int clk_nfc_set_rate(struct clk *clk, unsigned long rate)
 {
-       u32 reg, mux;
+       u32 reg, div;
+
+       div = clk_get_rate(clk->parent) / rate;
+       if (div == 0)
+               div++;
+       if (((clk_get_rate(clk->parent) / div) != rate) || (div > 8))
+               return -EINVAL;
+
+       reg = __raw_readl(MXC_CCM_CBCDR);
+       reg &= ~MXC_CCM_CBCDR_NFC_PODF_MASK;
+       reg |= (div - 1) << MXC_CCM_CBCDR_NFC_PODF_OFFSET;
+       __raw_writel(reg, MXC_CCM_CBCDR);
 
-       mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk,
-                      &lp_apm_clk);
-       reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK;
-       reg |= mux << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET;
-       __raw_writel(reg, MXC_CCM_CSCMR1);
+       while (__raw_readl(MXC_CCM_CDHIPR) &
+                       MXC_CCM_CDHIPR_NFC_IPG_INT_MEM_PODF_BUSY){
+       }
 
        return 0;
 }
@@ -620,6 +652,17 @@ static unsigned long get_ckih2_reference_clock_rate(struct clk *clk)
        return ckih2_reference;
 }
 
+static unsigned long clk_emi_slow_get_rate(struct clk *clk)
+{
+       u32 reg, div;
+
+       reg = __raw_readl(MXC_CCM_CBCDR);
+       div = ((reg & MXC_CCM_CBCDR_EMI_PODF_MASK) >>
+              MXC_CCM_CBCDR_EMI_PODF_OFFSET) + 1;
+
+       return clk_get_rate(clk->parent) / div;
+}
+
 /* External high frequency clock */
 static struct clk ckih_clk = {
        .get_rate = get_high_reference_clock_rate,
@@ -715,18 +758,6 @@ static struct clk ipg_perclk = {
        .set_parent = _clk_ipg_per_set_parent,
 };
 
-static struct clk uart_root_clk = {
-       .parent = &pll2_sw_clk,
-       .get_rate = clk_uart_get_rate,
-       .set_parent = _clk_uart_set_parent,
-};
-
-static struct clk usboh3_clk = {
-       .parent = &pll2_sw_clk,
-       .get_rate = clk_usboh3_get_rate,
-       .set_parent = _clk_usboh3_set_parent,
-};
-
 static struct clk ahb_max_clk = {
        .parent = &ahb_clk,
        .enable_reg = MXC_CCM_CCGR0,
@@ -762,45 +793,183 @@ static struct clk kpp_clk = {
        .id = 0,
 };
 
-#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s)    \
+static struct clk emi_slow_clk = {
+       .parent = &pll2_sw_clk,
+       .enable_reg = MXC_CCM_CCGR5,
+       .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET,
+       .enable = _clk_ccgr_enable,
+       .disable = _clk_ccgr_disable_inwait,
+       .get_rate = clk_emi_slow_get_rate,
+};
+
+#define DEFINE_CLOCK_CCGR(name, i, er, es, pfx, p, s)  \
        static struct clk name = {                      \
                .id             = i,                    \
                .enable_reg     = er,                   \
                .enable_shift   = es,                   \
-               .get_rate       = gr,                   \
-               .set_rate       = sr,                   \
+               .get_rate       = pfx##_get_rate,       \
+               .set_rate       = pfx##_set_rate,       \
+               .round_rate     = pfx##_round_rate,     \
+               .set_parent     = pfx##_set_parent,     \
                .enable         = _clk_ccgr_enable,     \
                .disable        = _clk_ccgr_disable,    \
                .parent         = p,                    \
                .secondary      = s,                    \
        }
 
-/* DEFINE_CLOCK(name, id, enable_reg, enable_shift,
-   get_rate, set_rate, parent, secondary); */
+#define DEFINE_CLOCK_MAX(name, i, er, es, pfx, p, s)   \
+       static struct clk name = {                      \
+               .id             = i,                    \
+               .enable_reg     = er,                   \
+               .enable_shift   = es,                   \
+               .get_rate       = pfx##_get_rate,       \
+               .set_rate       = pfx##_set_rate,       \
+               .set_parent     = pfx##_set_parent,     \
+               .enable         = _clk_max_enable,      \
+               .disable        = _clk_max_disable,     \
+               .parent         = p,                    \
+               .secondary      = s,                    \
+       }
+
+#define CLK_GET_RATE(name, nr, bitsname)                               \
+static unsigned long clk_##name##_get_rate(struct clk *clk)            \
+{                                                                      \
+       u32 reg, pred, podf;                                            \
+                                                                       \
+       reg = __raw_readl(MXC_CCM_CSCDR##nr);                           \
+       pred = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK)   \
+               >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET;    \
+       podf = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK)   \
+               >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET;    \
+                                                                       \
+       return DIV_ROUND_CLOSEST(clk_get_rate(clk->parent),             \
+                       (pred + 1) * (podf + 1));                       \
+}
+
+#define CLK_SET_PARENT(name, nr, bitsname)                             \
+static int clk_##name##_set_parent(struct clk *clk, struct clk *parent)        \
+{                                                                      \
+       u32 reg, mux;                                                   \
+                                                                       \
+       mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk,              \
+                       &pll3_sw_clk, &lp_apm_clk);                     \
+       reg = __raw_readl(MXC_CCM_CSCMR##nr) &                          \
+               ~MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_MASK;         \
+       reg |= mux << MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_OFFSET;  \
+       __raw_writel(reg, MXC_CCM_CSCMR##nr);                           \
+                                                                       \
+       return 0;                                                       \
+}
+
+#define CLK_SET_RATE(name, nr, bitsname)                               \
+static int clk_##name##_set_rate(struct clk *clk, unsigned long rate)  \
+{                                                                      \
+       u32 reg, div, parent_rate;                                      \
+       u32 pre = 0, post = 0;                                          \
+                                                                       \
+       parent_rate = clk_get_rate(clk->parent);                        \
+       div = parent_rate / rate;                                       \
+                                                                       \
+       if ((parent_rate / div) != rate)                                \
+               return -EINVAL;                                         \
+                                                                       \
+       __calc_pre_post_dividers(div, &pre, &post,                      \
+               (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK >>      \
+               MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET) + 1,  \
+               (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK >>      \
+               MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET) + 1);\
+                                                                       \
+       /* Set sdhc1 clock divider */                                   \
+       reg = __raw_readl(MXC_CCM_CSCDR##nr) &                          \
+               ~(MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK        \
+               | MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK);      \
+       reg |= (post - 1) <<                                            \
+               MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET;       \
+       reg |= (pre - 1) <<                                             \
+               MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET;       \
+       __raw_writel(reg, MXC_CCM_CSCDR##nr);                           \
+                                                                       \
+       return 0;                                                       \
+}
+
+/* UART */
+CLK_GET_RATE(uart, 1, UART)
+CLK_SET_PARENT(uart, 1, UART)
+
+static struct clk uart_root_clk = {
+       .parent = &pll2_sw_clk,
+       .get_rate = clk_uart_get_rate,
+       .set_parent = clk_uart_set_parent,
+};
+
+/* USBOH3 */
+CLK_GET_RATE(usboh3, 1, USBOH3)
+CLK_SET_PARENT(usboh3, 1, USBOH3)
+
+static struct clk usboh3_clk = {
+       .parent = &pll2_sw_clk,
+       .get_rate = clk_usboh3_get_rate,
+       .set_parent = clk_usboh3_set_parent,
+};
+
+/* eCSPI */
+CLK_GET_RATE(ecspi, 2, CSPI)
+CLK_SET_PARENT(ecspi, 1, CSPI)
+
+static struct clk ecspi_main_clk = {
+       .parent = &pll3_sw_clk,
+       .get_rate = clk_ecspi_get_rate,
+       .set_parent = clk_ecspi_set_parent,
+};
+
+/* eSDHC */
+CLK_GET_RATE(esdhc1, 1, ESDHC1_MSHC1)
+CLK_SET_PARENT(esdhc1, 1, ESDHC1_MSHC1)
+CLK_SET_RATE(esdhc1, 1, ESDHC1_MSHC1)
+
+CLK_GET_RATE(esdhc2, 1, ESDHC2_MSHC2)
+CLK_SET_PARENT(esdhc2, 1, ESDHC2_MSHC2)
+CLK_SET_RATE(esdhc2, 1, ESDHC2_MSHC2)
+
+#define DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, e, d, p, s)         \
+       static struct clk name = {                                      \
+               .id             = i,                                    \
+               .enable_reg     = er,                                   \
+               .enable_shift   = es,                                   \
+               .get_rate       = gr,                                   \
+               .set_rate       = sr,                                   \
+               .enable         = e,                                    \
+               .disable        = d,                                    \
+               .parent         = p,                                    \
+               .secondary      = s,                                    \
+       }
+
+#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s)                    \
+       DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, _clk_ccgr_enable, _clk_ccgr_disable, p, s)
 
 /* Shared peripheral bus arbiter */
 DEFINE_CLOCK(spba_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG0_OFFSET,
        NULL,  NULL, &ipg_clk, NULL);
 
 /* UART */
-DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG4_OFFSET,
-       NULL,  NULL, &uart_root_clk, NULL);
-DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG6_OFFSET,
-       NULL,  NULL, &uart_root_clk, NULL);
-DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG8_OFFSET,
-       NULL,  NULL, &uart_root_clk, NULL);
 DEFINE_CLOCK(uart1_ipg_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG3_OFFSET,
        NULL,  NULL, &ipg_clk, &aips_tz1_clk);
 DEFINE_CLOCK(uart2_ipg_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG5_OFFSET,
        NULL,  NULL, &ipg_clk, &aips_tz1_clk);
 DEFINE_CLOCK(uart3_ipg_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG7_OFFSET,
        NULL,  NULL, &ipg_clk, &spba_clk);
+DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG4_OFFSET,
+       NULL,  NULL, &uart_root_clk, &uart1_ipg_clk);
+DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG6_OFFSET,
+       NULL,  NULL, &uart_root_clk, &uart2_ipg_clk);
+DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG8_OFFSET,
+       NULL,  NULL, &uart_root_clk, &uart3_ipg_clk);
 
 /* GPT */
-DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET,
-       NULL,  NULL, &ipg_clk, NULL);
 DEFINE_CLOCK(gpt_ipg_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG10_OFFSET,
        NULL,  NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET,
+       NULL,  NULL, &ipg_clk, &gpt_ipg_clk);
 
 /* I2C */
 DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG9_OFFSET,
@@ -814,6 +983,52 @@ DEFINE_CLOCK(hsi2c_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET,
 DEFINE_CLOCK(fec_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG12_OFFSET,
        NULL,  NULL, &ipg_clk, NULL);
 
+/* NFC */
+DEFINE_CLOCK_CCGR(nfc_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG10_OFFSET,
+       clk_nfc, &emi_slow_clk, NULL);
+
+/* SSI */
+DEFINE_CLOCK(ssi1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG8_OFFSET,
+       NULL, NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(ssi1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG9_OFFSET,
+       NULL, NULL, &pll3_sw_clk, &ssi1_ipg_clk);
+DEFINE_CLOCK(ssi2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG10_OFFSET,
+       NULL, NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(ssi2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG11_OFFSET,
+       NULL, NULL, &pll3_sw_clk, &ssi2_ipg_clk);
+
+/* eCSPI */
+DEFINE_CLOCK_FULL(ecspi1_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG9_OFFSET,
+               NULL, NULL, _clk_ccgr_enable_inrun, _clk_ccgr_disable,
+               &ipg_clk, &spba_clk);
+DEFINE_CLOCK(ecspi1_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG10_OFFSET,
+               NULL, NULL, &ecspi_main_clk, &ecspi1_ipg_clk);
+DEFINE_CLOCK_FULL(ecspi2_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG11_OFFSET,
+               NULL, NULL, _clk_ccgr_enable_inrun, _clk_ccgr_disable,
+               &ipg_clk, &aips_tz2_clk);
+DEFINE_CLOCK(ecspi2_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG12_OFFSET,
+               NULL, NULL, &ecspi_main_clk, &ecspi2_ipg_clk);
+
+/* CSPI */
+DEFINE_CLOCK(cspi_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG9_OFFSET,
+               NULL, NULL, &ipg_clk, &aips_tz2_clk);
+DEFINE_CLOCK(cspi_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG13_OFFSET,
+               NULL, NULL, &ipg_clk, &cspi_ipg_clk);
+
+/* SDMA */
+DEFINE_CLOCK(sdma_clk, 1, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG15_OFFSET,
+               NULL, NULL, &ahb_clk, NULL);
+
+/* eSDHC */
+DEFINE_CLOCK_FULL(esdhc1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG0_OFFSET,
+       NULL,  NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL);
+DEFINE_CLOCK_MAX(esdhc1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG1_OFFSET,
+       clk_esdhc1, &pll2_sw_clk, &esdhc1_ipg_clk);
+DEFINE_CLOCK_FULL(esdhc2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG2_OFFSET,
+       NULL,  NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL);
+DEFINE_CLOCK_MAX(esdhc2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG3_OFFSET,
+       clk_esdhc2, &pll2_sw_clk, &esdhc2_ipg_clk);
+
 #define _REGISTER_CLOCK(d, n, c) \
        { \
                .dev_id = d, \
@@ -837,6 +1052,18 @@ static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk)
        _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk)
        _REGISTER_CLOCK("imx-keypad.0", NULL, kpp_clk)
+       _REGISTER_CLOCK("mxc_nand", NULL, nfc_clk)
+       _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
+       _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
+       _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk)
+       _REGISTER_CLOCK(NULL, "ckih", ckih_clk)
+       _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk)
+       _REGISTER_CLOCK(NULL, "gpt_32k", gpt_32k_clk)
+       _REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk)
+       _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk)
+       _REGISTER_CLOCK("imx51-cspi.0", NULL, cspi_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
+       _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
 };
 
 static void clk_tree_init(void)
@@ -880,6 +1107,14 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc,
        /* set the usboh3_clk parent to pll2_sw_clk */
        clk_set_parent(&usboh3_clk, &pll2_sw_clk);
 
+       /* Set SDHC parents to be PLL2 */
+       clk_set_parent(&esdhc1_clk, &pll2_sw_clk);
+       clk_set_parent(&esdhc2_clk, &pll2_sw_clk);
+
+       /* set SDHC root clock as 166.25MHZ*/
+       clk_set_rate(&esdhc1_clk, 166250000);
+       clk_set_rate(&esdhc2_clk, 166250000);
+
        /* System timer */
        mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR),
                MX51_MXC_INT_GPT);
index 2d37785e3857d32575a5948f36574e4770a0b917..eaacb6e9b5d0b417d0b78d56a8ebb406cb8ee9cd 100644 (file)
@@ -70,6 +70,25 @@ int mx51_revision(void)
 }
 EXPORT_SYMBOL(mx51_revision);
 
+#ifdef CONFIG_NEON
+
+/*
+ * All versions of the silicon before Rev. 3 have broken NEON implementations.
+ * Dependent on link order - so the assumption is that vfp_init is called
+ * before us.
+ */
+static int __init mx51_neon_fixup(void)
+{
+       if (mx51_revision() < MX51_CHIP_REV_3_0 && (elf_hwcap & HWCAP_NEON)) {
+               elf_hwcap &= ~HWCAP_NEON;
+               pr_info("Turning off NEON support, detected broken NEON implementation\n");
+       }
+       return 0;
+}
+
+late_initcall(mx51_neon_fixup);
+#endif
+
 static int __init post_cpu_init(void)
 {
        unsigned int reg;
diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h
new file mode 100644 (file)
index 0000000..5cc910e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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 <mach/mx51.h>
+#include <mach/devices-common.h>
+
+extern const struct imx_fec_data imx51_fec_data __initconst;
+#define imx51_add_fec(pdata)   \
+       imx_add_fec(&imx51_fec_data, pdata)
+
+extern const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst;
+#define imx51_add_imx_i2c(id, pdata)   \
+       imx_add_imx_i2c(&imx51_imx_i2c_data[id], pdata)
+
+extern const struct imx_imx_ssi_data imx51_imx_ssi_data[] __initconst;
+#define imx51_add_imx_ssi(id, pdata)   \
+       imx_add_imx_ssi(&imx51_imx_ssi_data[id], pdata)
+
+extern const struct imx_imx_uart_1irq_data imx51_imx_uart_data[] __initconst;
+#define imx51_add_imx_uart(id, pdata)  \
+       imx_add_imx_uart_1irq(&imx51_imx_uart_data[id], pdata)
+
+extern const struct imx_mxc_nand_data imx51_mxc_nand_data __initconst;
+#define imx51_add_mxc_nand(pdata)      \
+       imx_add_mxc_nand(&imx51_mxc_nand_data, pdata)
+
+extern const struct imx_spi_imx_data imx51_cspi_data __initconst;
+#define imx51_add_cspi(pdata)  \
+       imx_add_spi_imx(&imx51_cspi_data, pdata)
+
+extern const struct imx_spi_imx_data imx51_ecspi_data[] __initconst;
+#define imx51_add_ecspi(id, pdata)     \
+       imx_add_spi_imx(&imx51_ecspi_data[id], pdata)
+
+extern const struct imx_esdhc_imx_data imx51_esdhc_data[] __initconst;
+#define imx51_add_esdhc(id, pdata)     \
+       imx_add_esdhc(&imx51_esdhc_data[id], pdata)
index 1920ff4963b211376822d2021d4e4bded6b268f1..4c7be87a7c9d17e57857e0376ce2ddc9fd53a6e7 100644 (file)
 #include <mach/imx-uart.h>
 #include <mach/irqs.h>
 
-static struct resource uart0[] = {
-       {
-               .start = MX51_UART1_BASE_ADDR,
-               .end = MX51_UART1_BASE_ADDR + 0xfff,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX51_MXC_INT_UART1,
-               .end = MX51_MXC_INT_UART1,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device0 = {
-       .name = "imx-uart",
-       .id = 0,
-       .resource = uart0,
-       .num_resources = ARRAY_SIZE(uart0),
-};
-
-static struct resource uart1[] = {
-       {
-               .start = MX51_UART2_BASE_ADDR,
-               .end = MX51_UART2_BASE_ADDR + 0xfff,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX51_MXC_INT_UART2,
-               .end = MX51_MXC_INT_UART2,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device1 = {
-       .name = "imx-uart",
-       .id = 1,
-       .resource = uart1,
-       .num_resources = ARRAY_SIZE(uart1),
-};
-
-static struct resource uart2[] = {
-       {
-               .start = MX51_UART3_BASE_ADDR,
-               .end = MX51_UART3_BASE_ADDR + 0xfff,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX51_MXC_INT_UART3,
-               .end = MX51_MXC_INT_UART3,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_uart_device2 = {
-       .name = "imx-uart",
-       .id = 2,
-       .resource = uart2,
-       .num_resources = ARRAY_SIZE(uart2),
-};
-
-static struct resource mxc_fec_resources[] = {
-       {
-               .start  = MX51_MXC_FEC_BASE_ADDR,
-               .end    = MX51_MXC_FEC_BASE_ADDR + 0xfff,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = MX51_MXC_INT_FEC,
-               .end    = MX51_MXC_INT_FEC,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_fec_device = {
-       .name = "fec",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_fec_resources),
-       .resource = mxc_fec_resources,
-};
-
-static struct resource mxc_i2c0_resources[] = {
-       {
-               .start = MX51_I2C1_BASE_ADDR,
-               .end = MX51_I2C1_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX51_MXC_INT_I2C1,
-               .end = MX51_MXC_INT_I2C1,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_i2c_device0 = {
-       .name = "imx-i2c",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_i2c0_resources),
-       .resource = mxc_i2c0_resources,
-};
-
-static struct resource mxc_i2c1_resources[] = {
-       {
-               .start = MX51_I2C2_BASE_ADDR,
-               .end = MX51_I2C2_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MX51_MXC_INT_I2C2,
-               .end = MX51_MXC_INT_I2C2,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-struct platform_device mxc_i2c_device1 = {
-       .name = "imx-i2c",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(mxc_i2c1_resources),
-       .resource = mxc_i2c1_resources,
-};
-
 static struct resource mxc_hsi2c_resources[] = {
        {
                .start = MX51_HSI2C_DMA_BASE_ADDR,
index e509cfaad1d466b4209fd36a5b01d9b4464a3d1a..af1d07c0bbc171822034146034eb1720015e0d3d 100644 (file)
@@ -1,12 +1,6 @@
-extern struct platform_device mxc_uart_device0;
-extern struct platform_device mxc_uart_device1;
-extern struct platform_device mxc_uart_device2;
-extern struct platform_device mxc_fec_device;
 extern struct platform_device mxc_usbdr_host_device;
 extern struct platform_device mxc_usbh1_device;
 extern struct platform_device mxc_usbdr_udc_device;
 extern struct platform_device mxc_wdt;
-extern struct platform_device mxc_i2c_device0;
-extern struct platform_device mxc_i2c_device1;
 extern struct platform_device mxc_hsi2c_device;
 extern struct platform_device mxc_keypad_device;
index ffa93d1d6ef8e30eca983fc2d11f7487ce570c61..a2e6e8c39d257da751549f67f110979c29fdde29 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <asm/mach/arch.h>
 
+#include "devices-imx51.h"
 #include "devices.h"
 
 #define MBIMX51_TSC2007_GPIO   (2*32 + 30)
@@ -112,9 +113,25 @@ static struct pad_desc mbimx51_pads[] = {
        MX51_PAD_KEY_COL1__KEY_COL1,
        MX51_PAD_KEY_COL2__KEY_COL2,
        MX51_PAD_KEY_COL3__KEY_COL3,
+
+       /* SD 1 */
+       MX51_PAD_SD1_CMD__SD1_CMD,
+       MX51_PAD_SD1_CLK__SD1_CLK,
+       MX51_PAD_SD1_DATA0__SD1_DATA0,
+       MX51_PAD_SD1_DATA1__SD1_DATA1,
+       MX51_PAD_SD1_DATA2__SD1_DATA2,
+       MX51_PAD_SD1_DATA3__SD1_DATA3,
+
+       /* SD 2 */
+       MX51_PAD_SD2_CMD__SD2_CMD,
+       MX51_PAD_SD2_CLK__SD2_CLK,
+       MX51_PAD_SD2_DATA0__SD2_DATA0,
+       MX51_PAD_SD2_DATA1__SD2_DATA1,
+       MX51_PAD_SD2_DATA2__SD2_DATA2,
+       MX51_PAD_SD2_DATA3__SD2_DATA3,
 };
 
-static struct imxuart_platform_data uart_pdata = {
+static const struct imxuart_platform_data uart_pdata __initconst = {
        .flags = IMXUART_HAVE_RTSCTS,
 };
 
@@ -158,9 +175,11 @@ struct tsc2007_platform_data tsc2007_data = {
 
 static struct i2c_board_info mbimx51_i2c_devices[] = {
        {
-               I2C_BOARD_INFO("tsc2007", 0x48),
+               I2C_BOARD_INFO("tsc2007", 0x49),
                .irq  = MBIMX51_TSC2007_IRQ,
                .platform_data = &tsc2007_data,
+       }, {
+               I2C_BOARD_INFO("tlv320aic23", 0x1a),
        },
 };
 
@@ -172,8 +191,8 @@ void __init eukrea_mbimx51_baseboard_init(void)
        mxc_iomux_v3_setup_multiple_pads(mbimx51_pads,
                                        ARRAY_SIZE(mbimx51_pads));
 
-       mxc_register_device(&mxc_uart_device1, NULL);
-       mxc_register_device(&mxc_uart_device2, &uart_pdata);
+       imx51_add_imx_uart(1, NULL);
+       imx51_add_imx_uart(2, &uart_pdata);
 
        gpio_request(MBIMX51_LED0, "LED0");
        gpio_direction_output(MBIMX51_LED0, 1);
@@ -197,4 +216,7 @@ void __init eukrea_mbimx51_baseboard_init(void)
        set_irq_type(MBIMX51_TSC2007_IRQ, IRQF_TRIGGER_FALLING);
        i2c_register_board_info(1, mbimx51_i2c_devices,
                                ARRAY_SIZE(mbimx51_i2c_devices));
+
+       imx51_add_esdhc(0, NULL);
+       imx51_add_esdhc(1, NULL);
 }
diff --git a/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c
new file mode 100644 (file)
index 0000000..2b48f51
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2010 Eric Benard - eric@eukrea.com
+ *
+ * Based on pcm970-baseboard.c which is :
+ * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.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/types.h>
+#include <linux/init.h>
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/i2c.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-mx51.h>
+#include <mach/audmux.h>
+
+#include "devices-imx51.h"
+#include "devices.h"
+
+#define MBIMXSD_GPIO_3_31 IOMUX_PAD(0x554, 0x16C, 3, 0x0, 0, \
+                               MX51_PAD_CTRL_1 | PAD_CTL_PUS_22K_UP)
+
+static struct pad_desc eukrea_mbimxsd_pads[] = {
+       /* LED */
+       MX51_PAD_NANDF_D10__GPIO_3_30,
+       /* SWITCH */
+       MBIMXSD_GPIO_3_31,
+       /* UART2 */
+       MX51_PAD_UART2_RXD__UART2_RXD,
+       MX51_PAD_UART2_TXD__UART2_TXD,
+       /* UART 3 */
+       MX51_PAD_UART3_RXD__UART3_RXD,
+       MX51_PAD_UART3_TXD__UART3_TXD,
+       MX51_PAD_KEY_COL4__UART3_RTS,
+       MX51_PAD_KEY_COL5__UART3_CTS,
+       /* SD */
+       MX51_PAD_SD1_CMD__SD1_CMD,
+       MX51_PAD_SD1_CLK__SD1_CLK,
+       MX51_PAD_SD1_DATA0__SD1_DATA0,
+       MX51_PAD_SD1_DATA1__SD1_DATA1,
+       MX51_PAD_SD1_DATA2__SD1_DATA2,
+       MX51_PAD_SD1_DATA3__SD1_DATA3,
+};
+
+#define GPIO_LED1      (2 * 32 + 30)
+#define GPIO_SWITCH1   (2 * 32 + 31)
+
+static struct gpio_led eukrea_mbimxsd_leds[] = {
+       {
+               .name                   = "led1",
+               .default_trigger        = "heartbeat",
+               .active_low             = 1,
+               .gpio                   = GPIO_LED1,
+       },
+};
+
+static struct gpio_led_platform_data eukrea_mbimxsd_led_info = {
+       .leds           = eukrea_mbimxsd_leds,
+       .num_leds       = ARRAY_SIZE(eukrea_mbimxsd_leds),
+};
+
+static struct platform_device eukrea_mbimxsd_leds_gpio = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &eukrea_mbimxsd_led_info,
+       },
+};
+
+static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
+       {
+               .gpio           = GPIO_SWITCH1,
+               .code           = BTN_0,
+               .desc           = "BP1",
+               .active_low     = 1,
+               .wakeup         = 1,
+       },
+};
+
+static struct gpio_keys_platform_data eukrea_mbimxsd_button_data = {
+       .buttons        = eukrea_mbimxsd_gpio_buttons,
+       .nbuttons       = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons),
+};
+
+static struct platform_device eukrea_mbimxsd_button_device = {
+       .name           = "gpio-keys",
+       .id             = -1,
+       .num_resources  = 0,
+       .dev            = {
+               .platform_data  = &eukrea_mbimxsd_button_data,
+       }
+};
+
+static struct platform_device *platform_devices[] __initdata = {
+       &eukrea_mbimxsd_leds_gpio,
+       &eukrea_mbimxsd_button_device,
+};
+
+static const struct imxuart_platform_data uart_pdata __initconst = {
+       .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = {
+       {
+               I2C_BOARD_INFO("tlv320aic23", 0x1a),
+       },
+};
+
+/*
+ * system init for baseboard usage. Will be called by cpuimx51sd init.
+ *
+ * Add platform devices present on this baseboard and init
+ * them from CPU side as far as required to use them later on
+ */
+void __init eukrea_mbimxsd51_baseboard_init(void)
+{
+       if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads,
+                       ARRAY_SIZE(eukrea_mbimxsd_pads)))
+               printk(KERN_ERR "error setting mbimxsd pads !\n");
+
+       imx51_add_imx_uart(1, NULL);
+       imx51_add_imx_uart(2, &uart_pdata);
+
+       imx51_add_esdhc(0, NULL);
+
+       gpio_request(GPIO_LED1, "LED1");
+       gpio_direction_output(GPIO_LED1, 1);
+       gpio_free(GPIO_LED1);
+
+       gpio_request(GPIO_SWITCH1, "SWITCH1");
+       gpio_direction_input(GPIO_SWITCH1);
+       gpio_free(GPIO_SWITCH1);
+
+       i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices,
+                               ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
+
+       platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+}
index 69816ba82930edcab94de16580d9d62c30610b33..395d83be8c98ed9b90590051f0744789d7a74778 100644 (file)
@@ -53,8 +53,6 @@ struct sys_timer zn5_timer = {
 };
 
 MACHINE_START(MAGX_ZN5, "Motorola Zn5")
-       .phys_io        = MXC91231_AIPS1_BASE_ADDR,
-       .io_pg_offst    = ((MXC91231_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
        .boot_params    = MXC91231_PHYS_OFFSET + 0x100,
        .map_io         = mxc91231_map_io,
        .init_irq       = mxc91231_init_irq,
index e96339e71d88fec6cbf56e72f08ba9d0dd4d9008..56a9152281801fd7f0e32ccbd2c61895f69db4be 100644 (file)
 
 #include "hardware.h"
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #0x00100000                @ physical
-               movne   \rx, #io_p2v(0x00100000)        @ virtual
-               orr     \rx, \rx, #0x00000a00
+               .macro  addruart, rp, rv
+               mov     \rp, #0x00000a00
+               orr     \rv, \rp, #io_p2v(0x00100000)   @ virtual
+               orr     \rp, \rp, #0x00100000           @ physical
                .endm
 
                .macro  senduart,rd,rx
index 25d5cc676e0fbfa9bbe701f34f925d39ddfe43a2..7cca3574308f0403a07c93edf6e427e6d29f0299 100644 (file)
@@ -16,4 +16,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000
index c9b174bc8ccfa12b6146eb6a522dc0e7f5b74484..ca8b203a3c99d3f9ffab9e686c5c0c9958154c74 100644 (file)
@@ -200,8 +200,6 @@ static void __init nxdb500_init(void)
 }
 
 MACHINE_START(NXDB500, "Hilscher nxdb500")
-       .phys_io        = 0x00100000,
-       .io_pg_offst    = (io_p2v(0x00100000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = netx_map_io,
        .init_irq       = netx_init_irq,
index 15b54c62d60f88e6b1348d1be80b2c0365932ed8..d775cbe072780bef9d12f4dc01bc3b1c1eb63bc5 100644 (file)
@@ -93,8 +93,6 @@ static void __init nxdkn_init(void)
 }
 
 MACHINE_START(NXDKN, "Hilscher nxdkn")
-       .phys_io        = 0x00100000,
-       .io_pg_offst    = (io_p2v(0x00100000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = netx_map_io,
        .init_irq       = netx_init_irq,
index 1061c01ff679d4d660fff96f2f43670465b7ab54..de369cd1dcbed9ec667adfec8edd700081fc753f 100644 (file)
@@ -177,8 +177,6 @@ static void __init nxeb500hmi_init(void)
 }
 
 MACHINE_START(NXEB500HMI, "Hilscher nxeb500hmi")
-       .phys_io        = 0x00100000,
-       .io_pg_offst    = (io_p2v(0x00100000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = netx_map_io,
        .init_irq       = netx_init_irq,
index 841d459ad59db6480f18ef4cffba44fee640a8db..139930350d939289c729fdde62339873aa2989bd 100644 (file)
@@ -276,8 +276,6 @@ static void __init nhk8815_platform_init(void)
 
 MACHINE_START(NOMADIK, "NHK8815")
        /* Maintainer: ST MicroElectronics */
-       .phys_io        = NOMADIK_UART0_BASE,
-       .io_pg_offst    = (IO_ADDRESS(NOMADIK_UART0_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x100,
        .map_io         = cpu8815_map_io,
        .init_irq       = cpu8815_init_irq,
index 4f92acfba9545aaf5f9043925b51d8fcd1334ac0..e7151b4b88896f8a8426d6c7c7eb8db4ae79860f 100644 (file)
  *
 */
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #0x10000000        @ physical base address
-               movne   \rx, #0xf0000000        @ virtual base
-               add     \rx, \rx, #0x00100000
-               add     \rx, \rx, #0x000fb000
+               .macro  addruart, rp, rv
+               mov     \rp, #0x00100000
+               add     \rp, \rp, #0x000fb000
+               add     \rv, \rp, #0xf0000000   @ virtual base
+               add     \rp, \rp, #0x10000000   @ physical base address
                .endm
 
 #include <asm/hardware/debug-pl01x.S>
index 5c934bdb71583e037c59fdadc3490e43838ff425..5a2acbdc3d679f2563aab0a8a24b4988b26431aa 100644 (file)
 
 #include <mach/regs-board-a9m9750dev.h>
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1
-               ldreq   \rx, =NS9XXX_CSxSTAT_PHYS(0)
-               ldrne   \rx, =io_p2v(NS9XXX_CSxSTAT_PHYS(0))
+               .macro  addruart, rp, rv
+               ldr     \rp, =NS9XXX_CSxSTAT_PHYS(0)
+               ldr     \rv, =io_p2v(NS9XXX_CSxSTAT_PHYS(0))
                .endm
 
 #define UART_SHIFT     2
index 9f79266f08e247dd7c4051773253e9cf7c68e11d..d702570424809fce752734e4f503881c818d5ba8 100644 (file)
@@ -35,8 +35,6 @@ static void __init nuc932evb_init(void)
 
 MACHINE_START(NUC932EVB, "NUC932EVB")
        /* Maintainer: Wan ZongShun */
-       .phys_io        = NUC93X_PA_UART,
-       .io_pg_offst    = (((u32)NUC93X_VA_UART) >> 18) & 0xfffc,
        .boot_params    = 0,
        .map_io         = nuc932evb_map_io,
        .init_irq       = nuc93x_init_irq,
index 41992ab71961ce6b1448ac0df659ced75ed94684..73c86392fcd3ac1e147bcc7e25d64eb5f91daedf 100644 (file)
@@ -297,8 +297,6 @@ static void __init ams_delta_map_io(void)
 
 MACHINE_START(AMS_DELTA, "Amstrad E3 (Delta)")
        /* Maintainer: Jonathan McDowell <noodles@earth.li> */
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = ams_delta_map_io,
        .reserve        = omap_reserve,
index 180ce79e5eacf9cae09583e568b2bc232d155a00..149fdd32e127338caf6d6ab6898a3b78289ec712 100644 (file)
@@ -386,8 +386,6 @@ static void __init omap_fsample_map_io(void)
 
 MACHINE_START(OMAP_FSAMPLE, "OMAP730 F-Sample")
 /* Maintainer: Brian Swetland <swetland@google.com> */
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_fsample_map_io,
        .reserve        = omap_reserve,
index 93b9ab8fc3be092d82d00ec8ef5cc934a0ac3cd0..23f4ab9e265128bcc9ee0846b56789e2beadade4 100644 (file)
@@ -94,8 +94,6 @@ static void __init omap_generic_map_io(void)
 
 MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
        /* Maintainer: Tony Lindgren <tony@atomide.com> */
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_generic_map_io,
        .reserve        = omap_reserve,
index d2cda58bcc480873c9befbd9806366f358283779..197adb49dc5a49b2c706cb35369ac1bd997a5aac 100644 (file)
@@ -458,8 +458,6 @@ static void __init h2_map_io(void)
 
 MACHINE_START(OMAP_H2, "TI-H2")
        /* Maintainer: Imre Deak <imre.deak@nokia.com> */
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = h2_map_io,
        .reserve        = omap_reserve,
index c2ef4ff846c74608adbc3f5041d1ab53aa8e6eb4..9126e3e37b4a7d90b9f7fd75e4a2746ba6f29e0f 100644 (file)
@@ -446,8 +446,6 @@ static void __init h3_map_io(void)
 
 MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
        /* Maintainer: Texas Instruments, Inc. */
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = h3_map_io,
        .reserve        = omap_reserve,
index 311899ff5ffcdfee5425f2f949cd1828863eea2b..86afb29522259e63efecc5d1758ee4ce007d55c9 100644 (file)
@@ -300,8 +300,6 @@ static void __init htcherald_init_irq(void)
 MACHINE_START(HERALD, "HTC Herald")
        /* Maintainer: Cory Maccarrone <darkstar6262@gmail.com> */
        /* Maintainer: wing-linux.sourceforge.net */
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = htcherald_map_io,
        .reserve        = omap_reserve,
index 3daf87ad25765813f2aabe95090954df565bc132..dc2b86fd66c12312119ab3d9770667030886fe30 100644 (file)
@@ -459,8 +459,6 @@ static void __init innovator_map_io(void)
 
 MACHINE_START(OMAP_INNOVATOR, "TI-Innovator")
        /* Maintainer: MontaVista Software, Inc. */
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = innovator_map_io,
        .reserve        = omap_reserve,
index 51a4539aecf54ba1a7046227a695d2014610ce30..aa8375b2a0a3df0778f8ba9680f32d80d61482dd 100644 (file)
@@ -262,8 +262,6 @@ static void __init omap_nokia770_map_io(void)
 }
 
 MACHINE_START(NOKIA770, "Nokia 770")
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_nokia770_map_io,
        .reserve        = omap_reserve,
index 679740cc1e9020e8ea0200524215c31f92827178..e9dd79149a8e5744c4d2f1a79f30762e4f657196 100644 (file)
@@ -580,8 +580,6 @@ static void __init osk_map_io(void)
 
 MACHINE_START(OMAP_OSK, "TI-OSK")
        /* Maintainer: Dirk Behme <dirk.behme@de.bosch.com> */
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = osk_map_io,
        .reserve        = omap_reserve,
index 782bb257a85d9a901b4478eaf4923abe877e849d..f32738b1eb6bcce83a8e20fcb9d9121270a876a9 100644 (file)
@@ -285,8 +285,6 @@ static void __init omap_palmte_map_io(void)
 }
 
 MACHINE_START(OMAP_PALMTE, "OMAP310 based Palm Tungsten E")
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_palmte_map_io,
        .reserve        = omap_reserve,
index 0b35ef54a64fa47f47bc4d369e450034b03543b9..ed1400a67f7572ba90605a222f15ccaa565f14c9 100644 (file)
@@ -317,8 +317,6 @@ static void __init omap_palmtt_map_io(void)
 }
 
 MACHINE_START(OMAP_PALMTT, "OMAP1510 based Palm Tungsten|T")
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_palmtt_map_io,
        .reserve        = omap_reserve,
index 66362903b6e238ec1646e336e74377488a4ccea7..d7a245cef9a426ba180708b222c16efbcfce1cdd 100644 (file)
@@ -338,8 +338,6 @@ omap_palmz71_map_io(void)
 }
 
 MACHINE_START(OMAP_PALMZ71, "OMAP310 based Palm Zire71")
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_palmz71_map_io,
        .reserve        = omap_reserve,
index 34ab354758b0b5f835d1b97607f5286884d13eda..a8d16a255c1866daedf2af778aad68b4fc0e6ff0 100644 (file)
@@ -347,8 +347,6 @@ static void __init omap_perseus2_map_io(void)
 
 MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
        /* Maintainer: Kevin Hilman <kjh@hilman.org> */
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_perseus2_map_io,
        .reserve        = omap_reserve,
index 2eb148b8de937aa5f8e839ea7ba07d85806c0869..d25f59e5a7733ca79c23b18662bf701aa49f936b 100644 (file)
@@ -419,8 +419,6 @@ static void __init omap_sx1_map_io(void)
 }
 
 MACHINE_START(SX1, "OMAP310 based Siemens SX1")
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = omap_sx1_map_io,
        .reserve        = omap_reserve,
index 6b3cf14bc7572e8884366db6ffa8cc4e4c0ef6ed..f5992c239bcd18b3a773b732fc6787b804acd7e3 100644 (file)
@@ -283,8 +283,6 @@ EXPORT_SYMBOL(voiceblue_wdt_ping);
 
 MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
        /* Maintainer: Ladislav Michl <michl@2n.cz> */
-       .phys_io        = 0xfff00000,
-       .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = voiceblue_map_io,
        .reserve        = omap_reserve,
index 671408eb4ab42f8d0128f125c546a8b2405bc9d0..6a0fa04623650237d7f496a045eb8e498ded221e 100644 (file)
@@ -28,56 +28,58 @@ omap_uart_virt:     .word   0x0
                 * the desired UART phys and virt addresses temporarily into
                 * the omap_uart_phys and omap_uart_virt above.
                 */
-               .macro  addruart, rx, tmp
+               .macro  addruart, rp, rv
 
                /* Use omap_uart_phys/virt if already configured */
-9:             mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               ldreq   \rx, =__virt_to_phys(omap_uart_phys)    @ physical base address
-               ldrne   \rx, =omap_uart_virt    @ virtual base
-               ldr     \rx, [\rx, #0]
-               cmp     \rx, #0                 @ is port configured?
+9:             mrc     p15, 0, \rp, c1, c0
+               tst     \rp, #1                 @ MMU enabled?
+               ldreq   \rp, =__virt_to_phys(omap_uart_phys)    @ MMU not enabled
+               ldrne   \rp, =omap_uart_phys    @ MMU enabled
+               add     \rv, \rp, #4            @ omap_uart_virt
+               ldr     \rp, [\rp, #0]
+               ldr     \rv, [\rv, #0]
+               cmp     \rp, #0                 @ is port configured?
+               cmpne   \rv, #0
                bne     99f                     @ already configured
 
                /* Check the debug UART configuration set in uncompress.h */
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               ldreq   \rx, =OMAP_UART_INFO
-               ldrne   \rx, =__phys_to_virt(OMAP_UART_INFO)
-               ldr     \rx, [\rx, #0]
+               mrc     p15, 0, \rp, c1, c0
+               tst     \rp, #1                 @ MMU enabled?
+               ldreq   \rp, =OMAP_UART_INFO    @ MMU not enabled
+               ldrne   \rp, =__phys_to_virt(OMAP_UART_INFO)    @ MMU enabled
+               ldr     \rp, [\rp, #0]
 
                /* Select the UART to use based on the UART1 scratchpad value */
-10:            cmp     \rx, #0                 @ no port configured?
+10:            cmp     \rp, #0                 @ no port configured?
                beq     11f                     @ if none, try to use UART1
-               cmp     \rx, #OMAP1UART1
+               cmp     \rp, #OMAP1UART1
                beq     11f                     @ configure OMAP1UART1
-               cmp     \rx, #OMAP1UART2
+               cmp     \rp, #OMAP1UART2
                beq     12f                     @ configure OMAP1UART2
-               cmp     \rx, #OMAP1UART3
+               cmp     \rp, #OMAP1UART3
                beq     13f                     @ configure OMAP2UART3
 
                /* Configure the UART offset from the phys/virt base */
-11:            mov     \rx, #0x00fb0000        @ OMAP1UART1
+11:            mov     \rp, #0x00fb0000        @ OMAP1UART1
                b       98f
-12:            mov     \rx, #0x00fb0000        @ OMAP1UART1
-               orr     \rx, \rx, #0x00000800   @ OMAP1UART2
+12:            mov     \rp, #0x00fb0000        @ OMAP1UART1
+               orr     \rp, \rp, #0x00000800   @ OMAP1UART2
                b       98f
-13:            mov     \rx, #0x00fb0000        @ OMAP1UART1
-               orr     \rx, \rx, #0x00000800   @ OMAP1UART2
-               orr     \rx, \rx, #0x00009000   @ OMAP1UART3
+13:            mov     \rp, #0x00fb0000        @ OMAP1UART1
+               orr     \rp, \rp, #0x00000800   @ OMAP1UART2
+               orr     \rp, \rp, #0x00009000   @ OMAP1UART3
 
                /* Store both phys and virt address for the uart */
-98:            add     \rx, \rx, #0xff000000   @ phys base
-               mrc     p15, 0, \tmp, c1, c0
-               tst     \tmp, #1                @ MMU enabled?
-               ldreq   \tmp, =__virt_to_phys(omap_uart_phys)
-               ldrne   \tmp, =omap_uart_phys
-               str     \rx, [\tmp, #0]
-               sub     \rx, \rx, #0xff000000   @ phys base
-               add     \rx, \rx, #0xfe000000   @ virt base
-               ldreq   \tmp, =__virt_to_phys(omap_uart_virt)
-               ldrne   \tmp, =omap_uart_virt
-               str     \rx, [\tmp, #0]
+98:            add     \rp, \rp, #0xff000000   @ phys base
+               mrc     p15, 0, \rv, c1, c0
+               tst     \rv, #1                 @ MMU enabled?
+               ldreq   \rv, =__virt_to_phys(omap_uart_phys)    @ MMU not enabled
+               ldrne   \rv, =omap_uart_phys    @ MMU enabled
+               str     \rp, [\rv, #0]
+               sub     \rp, \rp, #0xff000000   @ phys base
+               add     \rp, \rp, #0xfe000000   @ virt base
+               add     \rv, \rv, #4            @ omap_uart_lsr
+               str     \rp, [\rv, #0]
                b       9b
 99:
                .endm
index 1b2af14df151627b06c2459af6ddb603b7f95094..b001f67d695b28e3ff6f10f16fd1842d7f3742fc 100644 (file)
@@ -17,4 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-#define VMALLOC_END    (PAGE_OFFSET + 0x18000000)
+#define VMALLOC_END    0xd8000000
index 8538e4131d27670de9b7f0c4a2a32c075f6cf27b..b857ce48451068cd24e4e5ae8125d7680ec73621 100644 (file)
@@ -253,8 +253,6 @@ static void __init omap_2430sdp_map_io(void)
 
 MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board")
        /* Maintainer: Syed Khasim - Texas Instruments Inc */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_2430sdp_map_io,
        .reserve        = omap_reserve,
index 67b95b5f1a2f62d8270a92a5a5cf1d7bcee57b0e..a5b095cf2adcdd67a14690e7eb0c8d99244f6167 100644 (file)
@@ -817,8 +817,6 @@ static void __init omap_3430sdp_init(void)
 
 MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
        /* Maintainer: Syed Khasim - Texas Instruments Inc */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index b359c3f7bb399b9608ddc315226f263ae76d8ec0..fd27ac0860b0c6b6d217f0d46b61c65a4574c36b 100644 (file)
@@ -217,8 +217,6 @@ static void __init omap_sdp_init(void)
 }
 
 MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index 9447644774c234435667a548e409bb0b4df76163..0b6a65f3a10a2adf508d209c7daeccfc51fea68c 100644 (file)
@@ -458,8 +458,6 @@ static void __init omap_4430sdp_map_io(void)
 
 MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board")
        /* Maintainer: Santosh Shilimkar - Texas Instruments Inc */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_4430sdp_map_io,
        .reserve        = omap_reserve,
index 4d0f58592864972429c0a19fb3d5e2ff9ecc0d27..f85c8da17e8bb8bcf69bbf208b2030277c3879be 100644 (file)
@@ -462,8 +462,6 @@ static void __init am3517_evm_init(void)
 }
 
 MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index c6421a72514a2a4e776aab63a2e1107434c3ffc2..68f07f5f441a65887e9d7783173b30916ccb0461 100644 (file)
@@ -356,8 +356,6 @@ static void __init omap_apollon_map_io(void)
 
 MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon")
        /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_apollon_map_io,
        .reserve        = omap_reserve,
index e10bc109415c4d3793b89b3e6e6ac1580311645a..934d9380c372e5ec31710fb47f6f4aa58714c60e 100644 (file)
@@ -809,8 +809,6 @@ static void __init cm_t35_init(void)
 }
 
 MACHINE_START(CM_T35, "Compulab CM-T35")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index a07086d6a0b26b6cb7d7fbe7d810ea330bcdae28..2205c20a4cdb61cf17ea11dd199b752baacafc65 100644 (file)
@@ -800,8 +800,6 @@ static void __init devkit8000_init(void)
 }
 
 MACHINE_START(DEVKIT8000, "OMAP3 Devkit8000")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index 3482b99e8c8653c4e72240d263692a436674afdc..69064b1c6a75da991e7a229296be750eb68c4649 100644 (file)
@@ -54,8 +54,6 @@ static void __init omap_generic_map_io(void)
 
 MACHINE_START(OMAP_GENERIC, "Generic OMAP24xx")
        /* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_generic_map_io,
        .reserve        = omap_reserve,
index e09bd686389f32dc385da26db744efbecc7fe5a7..cc39fc866524bfa1def1a0e7ec727a346f592196 100644 (file)
@@ -376,8 +376,6 @@ static void __init omap_h4_map_io(void)
 
 MACHINE_START(OMAP_H4, "OMAP2420 H4 board")
        /* Maintainer: Paul Mundt <paul.mundt@nokia.com> */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap_h4_map_io,
        .reserve        = omap_reserve,
index 175f043397612df6bc764a668338789d301e69c2..b62a68ba069bae2e198af22e76b7cf1500ae9ec9 100644 (file)
@@ -533,8 +533,6 @@ static void __init igep2_init(void)
 }
 
 MACHINE_START(IGEP0020, "IGEP v2 board")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index 00d9b13b01c5938e0118ced2a8801595dede232f..f28fd77bceb322f476b142f5cb5496b6a9dcf2db 100644 (file)
@@ -442,8 +442,6 @@ static void __init omap_ldp_init(void)
 }
 
 MACHINE_START(OMAP_LDP, "OMAP LDP board")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index a3e2b49aa39f001046c0994b09c64aa14cd10581..3f796687350771fe4334fc8ee0646f0405079e98 100644 (file)
@@ -674,8 +674,6 @@ static void __init n8x0_init_machine(void)
 }
 
 MACHINE_START(NOKIA_N800, "Nokia N800")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
        .reserve        = omap_reserve,
@@ -685,8 +683,6 @@ MACHINE_START(NOKIA_N800, "Nokia N800")
 MACHINE_END
 
 MACHINE_START(NOKIA_N810, "Nokia N810")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
        .reserve        = omap_reserve,
@@ -696,8 +692,6 @@ MACHINE_START(NOKIA_N810, "Nokia N810")
 MACHINE_END
 
 MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
        .reserve        = omap_reserve,
index 87969c7df652885ff6210519f3043cb7bb4f055e..9d9f5b881ee872137407901b3e5300921bc0cf0c 100644 (file)
@@ -487,8 +487,6 @@ static void __init omap3_beagle_init(void)
 
 MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
        /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index f76d9c0a47a1e83c8220977d75908c181899d53c..8936e4fba334796c2de6a68a96efe1330a0e2b15 100644 (file)
@@ -714,8 +714,6 @@ static void __init omap3_evm_init(void)
 
 MACHINE_START(OMAP3EVM, "OMAP3 EVM")
        /* Maintainer: Syed Mohammed Khasim - Texas Instruments */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index dd3af2be13be2a79e14a52360088c8cbb9db575b..b7d6df4e3cf95aa3f553a126087ba59353c1c5b3 100644 (file)
@@ -717,8 +717,6 @@ static void __init omap3pandora_init(void)
 }
 
 MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index bcd01d278c656f0b09a742a31370e5e278b1fb9e..bc5ac83bd4cf19824a432b8135357999577a6431 100644 (file)
@@ -654,8 +654,6 @@ static void __init omap3_stalker_init(void)
 
 MACHINE_START(SBC3530, "OMAP3 STALKER")
        /* Maintainer: Jason Lam -lzg@ema-tech.com */
-       .phys_io                = 0x48000000,
-       .io_pg_offst            = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params            = 0x80000100,
        .map_io                 = omap3_map_io,
        .init_irq               = omap3_stalker_init_irq,
index 663c62d271e8bfa0fcdec35bd9f03333ac0af87c..0e99ce584dbfc518f68ec87c75af1a5e9e3562e1 100644 (file)
@@ -538,8 +538,6 @@ static void __init omap3_touchbook_init(void)
 
 MACHINE_START(TOUCHBOOK, "OMAP3 touchbook Board")
        /* Maintainer: Gregoire Gentil - http://www.alwaysinnovating.com */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xd8000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index c03d1d56db562b1d4ef9f6fb86ce3da44d7d360e..db69bcadf4c7400e60cba20659d73ddfaf893e49 100644 (file)
@@ -294,8 +294,6 @@ static void __init omap4_panda_map_io(void)
 
 MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board")
        /* Maintainer: David Anders - Texas Instruments Inc */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap4_panda_map_io,
        .init_irq       = omap4_panda_init_irq,
index 4c484361835063d17de2df8fe27c7fb28be7984f..5e528ca015a1a38b69a7b4cf89661c173e868497 100644 (file)
@@ -501,8 +501,6 @@ static void __init overo_init(void)
 }
 
 MACHINE_START(OVERO, "Gumstix Overo")
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index a58e8cb1a7fc9abf639225bed3fa5de8cc3187c9..36f2cf4efd57630b593bf42ca28965891c14f906 100644 (file)
@@ -150,8 +150,6 @@ static void __init rx51_map_io(void)
 
 MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
        /* Maintainer: Lauri Leukkunen <lauri.leukkunen@nokia.com> */
-       .phys_io        = 0x48000000,
-       .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = rx51_map_io,
        .reserve        = omap_reserve,
index 3ad9ecf7f5e2b32d2361ae1df84aaa54b63013f8..24bbd0def64ff4b3e6617dc01910c491a7b557c8 100644 (file)
@@ -141,8 +141,6 @@ static void __init omap_zoom2_init(void)
 }
 
 MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
-       .phys_io        = ZOOM_UART_BASE,
-       .io_pg_offst    = (ZOOM_UART_VIRT >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index 6ca0b8341615efcbe628648bfe478bf9c1e91b35..b2bb3ff971ac9c940a73d6f093350c45126cc6f8 100644 (file)
@@ -123,8 +123,6 @@ static void __init omap_zoom_init(void)
 }
 
 MACHINE_START(OMAP_ZOOM3, "OMAP Zoom3 board")
-       .phys_io        = ZOOM_UART_BASE,
-       .io_pg_offst    = (ZOOM_UART_VIRT >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = omap3_map_io,
        .reserve        = omap_reserve,
index 09331bbbda52b66e267756b58cf8294472a010bb..6a4d4136002ed9999fa401e61c3776b74abe7581 100644 (file)
@@ -31,95 +31,94 @@ omap_uart_lsr:      .word   0
                 * the desired UART phys and virt addresses temporarily into
                 * the omap_uart_phys and omap_uart_virt above.
                 */
-               .macro  addruart, rx, tmp
+               .macro  addruart, rp, rv
 
                /* Use omap_uart_phys/virt if already configured */
-10:            mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               ldreq   \rx, =__virt_to_phys(omap_uart_phys)    @ physical base address
-               ldrne   \rx, =omap_uart_virt    @ virtual base address
-               ldr     \rx, [\rx, #0]
-               cmp     \rx, #0                 @ is port configured?
+10:            mrc     p15, 0, \rp, c1, c0
+               tst     \rp, #1                 @ MMU enabled?
+               ldreq   \rp, =__virt_to_phys(omap_uart_phys)    @ MMU not enabled
+               ldrne   \rp, =omap_uart_phys    @ MMU enabled
+               add     \rv, \rp, #4            @ omap_uart_virt
+               ldr     \rp, [\rp, #0]
+               ldr     \rv, [\rv, #0]
+               cmp     \rp, #0                 @ is port configured?
+               cmpne   \rv, #0
                bne     99f                     @ already configured
 
                /* Check the debug UART configuration set in uncompress.h */
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               ldreq   \rx, =OMAP_UART_INFO
-               ldrne   \rx, =__phys_to_virt(OMAP_UART_INFO)
-               ldr     \rx, [\rx, #0]
+               mrc     p15, 0, \rp, c1, c0
+               tst     \rp, #1                 @ MMU enabled?
+               ldreq   \rp, =OMAP_UART_INFO    @ MMU not enabled
+               ldrne   \rp, =__phys_to_virt(OMAP_UART_INFO)    @ MMU enabled
+               ldr     \rp, [\rp, #0]
 
                /* Select the UART to use based on the UART1 scratchpad value */
-               cmp     \rx, #0                 @ no port configured?
+               cmp     \rp, #0                 @ no port configured?
                beq     21f                     @ if none, try to use UART1
-               cmp     \rx, #OMAP2UART1        @ OMAP2/3/4UART1
+               cmp     \rp, #OMAP2UART1        @ OMAP2/3/4UART1
                beq     21f                     @ configure OMAP2/3/4UART1
-               cmp     \rx, #OMAP2UART2        @ OMAP2/3/4UART2
+               cmp     \rp, #OMAP2UART2        @ OMAP2/3/4UART2
                beq     22f                     @ configure OMAP2/3/4UART2
-               cmp     \rx, #OMAP2UART3        @ only on 24xx
+               cmp     \rp, #OMAP2UART3        @ only on 24xx
                beq     23f                     @ configure OMAP2UART3
-               cmp     \rx, #OMAP3UART3        @ only on 34xx
+               cmp     \rp, #OMAP3UART3        @ only on 34xx
                beq     33f                     @ configure OMAP3UART3
-               cmp     \rx, #OMAP4UART3        @ only on 44xx
+               cmp     \rp, #OMAP4UART3        @ only on 44xx
                beq     43f                     @ configure OMAP4UART3
-               cmp     \rx, #OMAP3UART4        @ only on 36xx
+               cmp     \rp, #OMAP3UART4        @ only on 36xx
                beq     34f                     @ configure OMAP3UART4
-               cmp     \rx, #OMAP4UART4        @ only on 44xx
+               cmp     \rp, #OMAP4UART4        @ only on 44xx
                beq     44f                     @ configure OMAP4UART4
-               cmp     \rx, #ZOOM_UART         @ only on zoom2/3
+               cmp     \rp, #ZOOM_UART         @ only on zoom2/3
                beq     95f                     @ configure ZOOM_UART
 
                /* Configure the UART offset from the phys/virt base */
-21:            mov     \rx, #UART_OFFSET(OMAP2_UART1_BASE)     @ omap2/3/4
+21:            mov     \rp, #UART_OFFSET(OMAP2_UART1_BASE)     @ omap2/3/4
                b       98f
-22:            mov     \rx, #UART_OFFSET(OMAP2_UART2_BASE)     @ omap2/3/4
+22:            mov     \rp, #UART_OFFSET(OMAP2_UART2_BASE)     @ omap2/3/4
                b       98f
-23:            mov     \rx, #UART_OFFSET(OMAP2_UART3_BASE)
+23:            mov     \rp, #UART_OFFSET(OMAP2_UART3_BASE)
                b       98f
-33:            mov     \rx, #UART_OFFSET(OMAP3_UART1_BASE)
-               add     \rx, \rx, #0x00fb0000
-               add     \rx, \rx, #0x00006000           @ OMAP3_UART3_BASE
+33:            mov     \rp, #UART_OFFSET(OMAP3_UART1_BASE)
+               add     \rp, \rp, #0x00fb0000
+               add     \rp, \rp, #0x00006000           @ OMAP3_UART3_BASE
                b       98f
-34:            mov     \rx, #UART_OFFSET(OMAP3_UART1_BASE)
-               add     \rx, \rx, #0x00fb0000
-               add     \rx, \rx, #0x00028000           @ OMAP3_UART4_BASE
+34:            mov     \rp, #UART_OFFSET(OMAP3_UART1_BASE)
+               add     \rp, \rp, #0x00fb0000
+               add     \rp, \rp, #0x00028000           @ OMAP3_UART4_BASE
                b       98f
-43:            mov     \rx, #UART_OFFSET(OMAP4_UART3_BASE)
+43:            mov     \rp, #UART_OFFSET(OMAP4_UART3_BASE)
                b       98f
-44:            mov     \rx, #UART_OFFSET(OMAP4_UART4_BASE)
+44:            mov     \rp, #UART_OFFSET(OMAP4_UART4_BASE)
                b       98f
-95:            ldr     \rx, =ZOOM_UART_BASE
-               mrc     p15, 0, \tmp, c1, c0
-               tst     \tmp, #1                @ MMU enabled?
-               ldreq   \tmp, =__virt_to_phys(omap_uart_phys)
-               ldrne   \tmp, =omap_uart_phys
-               str     \rx, [\tmp, #0]
-               ldr     \rx, =ZOOM_UART_VIRT
-               ldreq   \tmp, =__virt_to_phys(omap_uart_virt)
-               ldrne   \tmp, =omap_uart_virt
-               str     \rx, [\tmp, #0]
-               mov     \rx, #(UART_LSR << ZOOM_PORT_SHIFT)
-               ldreq   \tmp, =__virt_to_phys(omap_uart_lsr)
-               ldrne   \tmp, =omap_uart_lsr
-               str     \rx, [\tmp, #0]
+95:            ldr     \rp, =ZOOM_UART_BASE
+               mrc     p15, 0, \rv, c1, c0
+               tst     \rv, #1                 @ MMU enabled?
+               ldreq   \rv, =__virt_to_phys(omap_uart_phys)    @ MMU not enabled
+               ldrne   \rv, =omap_uart_phys    @ MMU enabled
+               str     \rp, [\rv, #0]
+               ldr     \rp, =ZOOM_UART_VIRT
+               add     \rv, \rv, #4            @ omap_uart_virt
+               str     \rp, [\rv, #0]
+               mov     \rp, #(UART_LSR << ZOOM_PORT_SHIFT)
+               add     \rv, \rv, #4            @ omap_uart_lsr
+               str     \rp, [\rv, #0]
                b       10b
 
                /* Store both phys and virt address for the uart */
-98:            add     \rx, \rx, #0x48000000   @ phys base
-               mrc     p15, 0, \tmp, c1, c0
-               tst     \tmp, #1                @ MMU enabled?
-               ldreq   \tmp, =__virt_to_phys(omap_uart_phys)
-               ldrne   \tmp, =omap_uart_phys
-               str     \rx, [\tmp, #0]
-               sub     \rx, \rx, #0x48000000   @ phys base
-               add     \rx, \rx, #0xfa000000   @ virt base
-               ldreq   \tmp, =__virt_to_phys(omap_uart_virt)
-               ldrne   \tmp, =omap_uart_virt
-               str     \rx, [\tmp, #0]
-               mov     \rx, #(UART_LSR << OMAP_PORT_SHIFT)
-               ldreq   \tmp, =__virt_to_phys(omap_uart_lsr)
-               ldrne   \tmp, =omap_uart_lsr
-               str     \rx, [\tmp, #0]
+98:            add     \rp, \rp, #0x48000000   @ phys base
+               mrc     p15, 0, \rv, c1, c0
+               tst     \rv, #1                 @ MMU enabled?
+               ldreq   \rv, =__virt_to_phys(omap_uart_phys)    @ MMU not enabled
+               ldrne   \rv, =omap_uart_phys    @ MMU enabled
+               str     \rp, [\rv, #0]
+               sub     \rp, \rp, #0x48000000   @ phys base
+               add     \rp, \rp, #0xfa000000   @ virt base
+               add     \rv, \rv, #4            @ omap_uart_virt
+               str     \rp, [\rv, #0]
+               mov     \rp, #(UART_LSR << OMAP_PORT_SHIFT)
+               add     \rv, \rv, #4            @ omap_uart_lsr
+               str     \rp, [\rv, #0]
 
                b       10b
 99:
@@ -131,9 +130,9 @@ omap_uart_lsr:      .word   0
 
                .macro  busyuart,rd,rx
 1001:          mrc     p15, 0, \rd, c1, c0
-               tst     \rd, #1         @ MMU enabled?
-               ldreq   \rd, =__virt_to_phys(omap_uart_lsr)
-               ldrne   \rd, =omap_uart_lsr
+               tst     \rd, #1                 @ MMU enabled?
+               ldreq   \rd, =__virt_to_phys(omap_uart_lsr)     @ MMU not enabled
+               ldrne   \rd, =omap_uart_lsr     @ MMU enabled
                ldr     \rd, [\rd, #0]
                ldrb    \rd, [\rx, \rd]
                and     \rd, \rd, #(UART_LSR_TEMT | UART_LSR_THRE)
index 9ce9b6e8ad23c6df97167845a85b51e95bf0d23c..4da31e997efead8da47b602699a210f9127231b7 100644 (file)
@@ -17,4 +17,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-#define VMALLOC_END      (PAGE_OFFSET + 0x38000000)
+#define VMALLOC_END      0xf8000000
index 7130904ad9998e28c8a0bd5eb884f7bc5649f329..b1c451f5ee27e56b23f46969bb4917010a1b2f31 100644 (file)
@@ -336,8 +336,6 @@ static void __init d2net_init(void)
 
 #ifdef CONFIG_MACH_D2NET
 MACHINE_START(D2NET, "LaCie d2 Network")
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = d2net_init,
        .map_io         = orion5x_map_io,
@@ -349,8 +347,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_BIGDISK
 MACHINE_START(BIGDISK, "LaCie Big Disk Network")
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = d2net_init,
        .map_io         = orion5x_map_io,
index d318bea2af91bbb5e9ec46a57813d6ef5add40e7..df1083f5b6eba92e32c044bebde773551bfd67f0 100644 (file)
@@ -358,8 +358,6 @@ static void __init db88f5281_init(void)
 
 MACHINE_START(DB88F5281, "Marvell Orion-2 Development Board")
        /* Maintainer: Tzachi Perelstein <tzachi@marvell.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .init_machine   = db88f5281_init,
        .map_io         = orion5x_map_io,
index a47100d46a4e88a9f3f41b4d1705ddc397cfe622..3a7bc0e36982bff6e9e73863960277ac01249cdb 100644 (file)
@@ -730,8 +730,6 @@ static void __init dns323_init(void)
 /* Warning: D-Link uses a wrong mach-type (=526) in their bootloader */
 MACHINE_START(DNS323, "D-Link DNS-323")
        /* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = dns323_init,
        .map_io         = orion5x_map_io,
index b24ee0c2cd618ab35f5e0b21cf06ab50b11d148d..ba98459f44b08d9084208d732f1e7f27fa6b80ad 100644 (file)
@@ -251,8 +251,6 @@ static void __init edmini_v2_init(void)
 /* Warning: LaCie use a wrong mach-type (0x20e=526) in their bootloader. */
 MACHINE_START(EDMINI_V2, "LaCie Ethernet Disk mini V2")
        /* Maintainer: Christopher Moore <moore@free.fr> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = edmini_v2_init,
        .map_io         = orion5x_map_io,
index 91e0e39bb23f1602a98068234c28268f262e455c..5e3bf5b68aecae6da23e23fdd4f204a3602e991d 100644 (file)
 
 #include <mach/orion5x.h>
 
-       .macro  addruart, rx, tmp
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                                 @ MMU enabled?
-       ldreq   \rx, =ORION5X_REGS_PHYS_BASE
-       ldrne   \rx, =ORION5X_REGS_VIRT_BASE
-       orr     \rx, \rx, #0x00012000
+       .macro  addruart, rp, rv
+       ldr     \rp, =ORION5X_REGS_PHYS_BASE
+       ldr     \rv, =ORION5X_REGS_VIRT_BASE
+       orr     \rp, \rp, #0x00012000
+       orr     \rv, \rv, #0x00012000
        .endm
 
 #define UART_SHIFT     2
index dfbb68df7b0986de42918ef5a6222eb0e337e940..4be9aa08de6996372391516c857e17802f0bf5f4 100644 (file)
@@ -379,8 +379,6 @@ static void __init kurobox_pro_init(void)
 #ifdef CONFIG_MACH_KUROBOX_PRO
 MACHINE_START(KUROBOX_PRO, "Buffalo/Revogear Kurobox Pro")
        /* Maintainer: Ronen Shitrit <rshitrit@marvell.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = kurobox_pro_init,
        .map_io         = orion5x_map_io,
@@ -393,8 +391,6 @@ MACHINE_END
 #ifdef CONFIG_MACH_LINKSTATION_PRO
 MACHINE_START(LINKSTATION_PRO, "Buffalo Linkstation Pro/Live")
        /* Maintainer: Byron Bradley <byron.bbradley@gmail.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = kurobox_pro_init,
        .map_io         = orion5x_map_io,
index 8e569be6e2c7f4bc75f275660a83360cd1ccb20f..437364b7168ec9f4060725904df90b23772f10e5 100644 (file)
@@ -265,8 +265,6 @@ static void __init ls_hgl_init(void)
 
 MACHINE_START(LINKSTATION_LS_HGL, "Buffalo Linkstation LS-HGL")
        /* Maintainer: Zhu Qingsen <zhuqs@cn.fujistu.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = ls_hgl_init,
        .map_io         = orion5x_map_io,
index c704f056de1e165bfad370c32b6f4bc2659592fa..ab9b0cf0a90b116ab3f607a0e05014a46a161136 100644 (file)
@@ -267,8 +267,6 @@ static void __init lsmini_init(void)
 #ifdef CONFIG_MACH_LINKSTATION_MINI
 MACHINE_START(LINKSTATION_MINI, "Buffalo Linkstation Mini")
        /* Maintainer: Alexey Kopytko <alexey@kopytko.ru> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = lsmini_init,
        .map_io         = orion5x_map_io,
index 61c086b66723d96296a51d38363f8d3584523cea..2f0e16cd7e8164d79bb3814fed13ccbab8a8bfd6 100644 (file)
@@ -261,8 +261,6 @@ static void __init mss2_init(void)
 
 MACHINE_START(MSS2, "Maxtor Shared Storage II")
        /* Maintainer: Sylver Bruneau <sylver.bruneau@googlemail.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = mss2_init,
        .map_io         = orion5x_map_io,
index 97c9ccb2ac60f7713bc076e38b3b23b8dff94c04..b3d90f25de9f1119235e4f5e46d9e58fa0846313 100644 (file)
@@ -229,8 +229,6 @@ static void __init mv2120_init(void)
 /* Warning: HP uses a wrong mach-type (=526) in their bootloader */
 MACHINE_START(MV2120, "HP Media Vault mv2120")
        /* Maintainer: Martin Michlmayr <tbm@cyrius.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = mv2120_init,
        .map_io         = orion5x_map_io,
index 7bd6283476f9e46017ca0be56ad06d16ae670ce8..d6665b31665fc4f41eac9fd612af5b3d6c6688a7 100644 (file)
@@ -419,8 +419,6 @@ static void __init net2big_init(void)
 
 /* Warning: LaCie use a wrong mach-type (0x20e=526) in their bootloader. */
 MACHINE_START(NET2BIG, "LaCie 2Big Network")
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = net2big_init,
        .map_io         = orion5x_map_io,
index 9c1ca41730ba4fc00d248029dedfb0d7bc8d8417..f4c26fd731f4f4f923a3c2a71c2442d3043a2b6c 100644 (file)
@@ -169,8 +169,6 @@ subsys_initcall(rd88f5181l_fxo_pci_init);
 
 MACHINE_START(RD88F5181L_FXO, "Marvell Orion-VoIP FXO Reference Design")
        /* Maintainer: Nicolas Pitre <nico@marvell.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = rd88f5181l_fxo_init,
        .map_io         = orion5x_map_io,
index ee1399ff0cedbe38aab1f8a4ff82dbdb921158be..b5942909bab07b72405cf73df452d4a01e7365e0 100644 (file)
@@ -181,8 +181,6 @@ subsys_initcall(rd88f5181l_ge_pci_init);
 
 MACHINE_START(RD88F5181L_GE, "Marvell Orion-VoIP GE Reference Design")
        /* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = rd88f5181l_ge_init,
        .map_io         = orion5x_map_io,
index a04f9e4b633a409a10a80cfb5c63da32f4ce3793..165ed87029b2c77705e68443ef84e427fa3e1e3c 100644 (file)
@@ -305,8 +305,6 @@ static void __init rd88f5182_init(void)
 
 MACHINE_START(RD88F5182, "Marvell Orion-NAS Reference Design")
        /* Maintainer: Ronen Shitrit <rshitrit@marvell.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = rd88f5182_init,
        .map_io         = orion5x_map_io,
index 7737cf9a8f5046a80911cd80b70a3f506d6fc057..02ff45f3e2e3f20420ee2922f527302e3d2b90f4 100644 (file)
@@ -123,8 +123,6 @@ subsys_initcall(rd88f6183ap_ge_pci_init);
 
 MACHINE_START(RD88F6183AP_GE, "Marvell Orion-1-90 AP GE Reference Design")
        /* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = rd88f6183ap_ge_init,
        .map_io         = orion5x_map_io,
index 0b101d7d41c2caa089fd8f4234a1e3b184f5432b..4403fae5ab0e8a0c843718a1b28ad30da073428f 100644 (file)
@@ -358,8 +358,6 @@ static void __init tsp2_init(void)
 
 MACHINE_START(TERASTATION_PRO2, "Buffalo Terastation Pro II/Live")
        /* Maintainer:  Sylver Bruneau <sylver.bruneau@googlemail.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = tsp2_init,
        .map_io         = orion5x_map_io,
index 9d6890514199759919b211859e8a864f4a6db7e8..1e196129d763785e0ec8047b2d462fde1826e651 100644 (file)
@@ -322,8 +322,6 @@ static void __init qnap_ts209_init(void)
 
 MACHINE_START(TS209, "QNAP TS-109/TS-209")
        /* Maintainer: Byron Bradley <byron.bbradley@gmail.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = qnap_ts209_init,
        .map_io         = orion5x_map_io,
index d85588ac7ef8f53ac141c695bee18ed37f7700b9..428af2046e36ded13192b5009fa05aa94061c933 100644 (file)
@@ -311,8 +311,6 @@ static void __init qnap_ts409_init(void)
 
 MACHINE_START(TS409, "QNAP TS-409")
        /* Maintainer:  Sylver Bruneau <sylver.bruneau@gmail.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = qnap_ts409_init,
        .map_io         = orion5x_map_io,
index 696b1a97f9e2eaf5b7c88735a2f41fa17262ba97..16f1bd5324bebb94b01ec5af9db5eb82d4e3509f 100644 (file)
@@ -550,8 +550,6 @@ static void __init ts78xx_init(void)
 
 MACHINE_START(TS78XX, "Technologic Systems TS-78xx SBC")
        /* Maintainer: Alexander Clouter <alex@digriz.org.uk> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = ts78xx_init,
        .map_io         = ts78xx_map_io,
index 69208217b22037096e4c467c2cc4508fb75dd9e5..7994d6ec08a87b7ad058a41e35e0111e1df906da 100644 (file)
@@ -172,8 +172,6 @@ subsys_initcall(wnr854t_pci_init);
 
 MACHINE_START(WNR854T, "Netgear WNR854T")
        /* Maintainer: Imre Kaloz <kaloz@openwrt.org> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = wnr854t_init,
        .map_io         = orion5x_map_io,
index f9f222ebb7ed0c5b12064cebddfe63c9399b3846..a5989b7eb53ee36526d0bef1f26f680deb044e13 100644 (file)
@@ -260,8 +260,6 @@ subsys_initcall(wrt350n_v2_pci_init);
 
 MACHINE_START(WRT350N_V2, "Linksys WRT350N v2")
        /* Maintainer: Lennert Buytenhek <buytenh@marvell.com> */
-       .phys_io        = ORION5X_REGS_PHYS_BASE,
-       .io_pg_offst    = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC,
        .boot_params    = 0x00000100,
        .init_machine   = wrt350n_v2_init,
        .map_io         = orion5x_map_io,
index 45734bb880a88477d7221760291f4c6f399883f8..63399755f199dd91202f89917fbb04a1b0c44adc 100644 (file)
@@ -264,8 +264,6 @@ extern struct sys_timer pnx4008_timer;
 
 MACHINE_START(PNX4008, "Philips PNX4008")
        /* Maintainer: MontaVista Software Inc. */
-       .phys_io                = 0x40090000,
-       .io_pg_offst            = (0xf4090000 >> 18) & 0xfffc,
        .boot_params            = 0x80000100,
        .map_io                 = pnx4008_map_io,
        .init_irq               = pnx4008_init_irq,
index 6ca8bd30bf46f32dd0e55c9284b0962242596dff..931afebaf06439fc78dc4192ce8f58f416d0a2b1 100644 (file)
  *
 */
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               mov     \rx, #0x00090000
-               addeq   \rx, \rx, #0x40000000
-               addne   \rx, \rx, #0xf4000000
+               .macro  addruart, rp, rv
+               mov     \rp, #0x00090000
+               add     \rv, \rp, #0xf4000000   @ virtual
+               add     \rp, \rp, #0x40000000   @ physical
                .endm
 
 #define UART_SHIFT     2
index 2ad398378aed3241e47bf9dc14237f9acf63bd95..31b65ee07b0b17f498e9796c2704ff6f427f5662 100644 (file)
@@ -17,4 +17,4 @@
  * The vmalloc() routines leaves a hole of 4kB between each vmalloced
  * area for the same reason. ;)
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000
index 7aefb90748527ae5b68550b7e311d1244b55639d..dd235ecc9d6c5946d6610bb7adef42cb57476210 100644 (file)
@@ -8,19 +8,16 @@ config ARCH_LUBBOCK
        bool "Intel DBPXA250 Development Platform (aka Lubbock)"
        select PXA25x
        select SA1111
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_MAINSTONE
        bool "Intel HCDDBBVA0 Development Platform (aka Mainstone)"
        select PXA27x
        select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_ZYLONITE
        bool
        select PXA3xx
        select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_ZYLONITE300
        bool "PXA3xx Development Platform (aka Zylonite) PXA300/310"
@@ -44,6 +41,10 @@ config MACH_TAVOREVB
        select PXA3xx
        select CPU_PXA930
 
+config MACH_TAVOREVB3
+       bool "PXA95x Development Platform (aka TavorEVB III)"
+       select CPU_PXA950
+
 config MACH_SAAR
        bool "PXA930 Handheld Platform (aka SAAR)"
        select PXA3xx
@@ -61,7 +62,6 @@ config ARCH_VIPER
        select ISA
        select I2C_GPIO
        select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
        select PXA_HAVE_ISA_IRQS
        select ARCOM_PCMCIA
 
@@ -69,7 +69,6 @@ config MACH_ARCOM_ZEUS
        bool "Arcom/Eurotech ZEUS SBC"
        select PXA27x
        select ISA
-       select PXA_HAVE_BOARD_IRQS
        select PXA_HAVE_ISA_IRQS
        select ARCOM_PCMCIA
 
@@ -77,7 +76,6 @@ config MACH_BALLOON3
        bool "Balloon 3 board"
        select PXA27x
        select IWMMXT
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_CSB726
        bool "Enable Cogent CSB726 System On a Module"
@@ -140,13 +138,11 @@ config MACH_INTELMOTE2
        bool "Intel Mote 2 Platform"
        select PXA27x
        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 MACH_XCEP
        bool "Iskratel Electronics XCEP"
@@ -206,13 +202,11 @@ config MACH_LOGICPD_PXA270
        bool "LogicPD PXA270 Card Engine Development Platform"
        select PXA27x
        select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_PCM027
        bool "Phytec phyCORE-PXA270 CPU module (PCM-027)"
        select PXA27x
        select IWMMXT
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_PCM990_BASEBOARD
        bool "PHYTEC PCM-990 development board"
@@ -247,7 +241,6 @@ config MACH_COLIBRI_PXA270_INCOME
        depends on MACH_COLIBRI
        select PXA27x
        select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_COLIBRI300
        bool "Toradex Colibri PXA300/310"
@@ -274,7 +267,6 @@ config MACH_H4700
        select PXA27x
        select IWMMXT
        select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_H5000
        bool "HP iPAQ h5000"
@@ -289,7 +281,6 @@ config MACH_MAGICIAN
        select PXA27x
        select IWMMXT
        select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_MIOA701
        bool "Mitac Mio A701 Support"
@@ -307,7 +298,6 @@ config PXA_EZX
        select PXA27x
        select IWMMXT
        select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_EZX_A780
        bool "Motorola EZX A780"
@@ -478,7 +468,6 @@ config MACH_POODLE
        depends on PXA_SHARPSL
        select PXA25x
        select SHARP_LOCOMO
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_CORGI
        bool "Enable Sharp SL-C700 (Corgi) Support"
@@ -523,7 +512,6 @@ config MACH_TOSA
        bool "Enable Sharp SL-6000x (Tosa) Support"
        depends on PXA_SHARPSL
        select PXA25x
-       select PXA_HAVE_BOARD_IRQS
 
 config TOSA_BT
        tristate "Control the state of built-in bluetooth chip on Sharp SL-6000"
@@ -552,7 +540,6 @@ config MACH_ICONTROL
 config ARCH_PXA_ESERIES
        bool "PXA based Toshiba e-series PDAs"
        select PXA25x
-       select PXA_HAVE_BOARD_IRQS
 
 config MACH_E330
        bool "Toshiba e330"
@@ -606,7 +593,6 @@ config MACH_ZIPIT2
        bool "Zipit Z2 Handheld"
        select PXA27x
        select HAVE_PWM
-       select PXA_HAVE_BOARD_IRQS
 
 endmenu
 
@@ -643,6 +629,7 @@ config CPU_PXA300
 config CPU_PXA310
        bool
        select CPU_PXA300
+       select PXA310_ULPI if USB_ULPI
        help
          PXA310 (codename Monahans-LV)
 
@@ -692,10 +679,10 @@ config SHARPSL_PM_MAX1111
        select HWMON
        select SENSORS_MAX1111
 
-config PXA_HAVE_BOARD_IRQS
+config PXA_HAVE_ISA_IRQS
        bool
 
-config PXA_HAVE_ISA_IRQS
+config PXA310_ULPI
        bool
 
 endif
index 85c7fb324dbb88ee68ce1d0da0cf0f9c0e92035c..e2f89c2c6f4962ea38a98ea9adb6e3dca8e63ed9 100644 (file)
@@ -18,7 +18,7 @@ endif
 # SoC-specific code
 obj-$(CONFIG_PXA25x)           += mfp-pxa2xx.o pxa2xx.o pxa25x.o
 obj-$(CONFIG_PXA27x)           += mfp-pxa2xx.o pxa2xx.o pxa27x.o
-obj-$(CONFIG_PXA3xx)           += mfp-pxa3xx.o pxa3xx.o smemc.o
+obj-$(CONFIG_PXA3xx)           += mfp-pxa3xx.o pxa3xx.o smemc.o pxa3xx-ulpi.o
 obj-$(CONFIG_CPU_PXA300)       += pxa300.o
 obj-$(CONFIG_CPU_PXA320)       += pxa320.o
 obj-$(CONFIG_CPU_PXA930)       += pxa930.o
@@ -32,6 +32,7 @@ obj-$(CONFIG_MACH_ZYLONITE300)        += zylonite.o zylonite_pxa300.o
 obj-$(CONFIG_MACH_ZYLONITE320) += zylonite.o zylonite_pxa320.o
 obj-$(CONFIG_MACH_LITTLETON)   += littleton.o
 obj-$(CONFIG_MACH_TAVOREVB)    += tavorevb.o
+obj-$(CONFIG_MACH_TAVOREVB3)   += tavorevb3.o
 obj-$(CONFIG_MACH_SAAR)                += saar.o
 
 # 3rd Party Dev Platforms
index 9041340fee1db17cdb6aa670ba43a2457a8193bf..21e188901935fc4f5e4c6b56b58161ed40ac5ab9 100644 (file)
@@ -68,42 +68,6 @@ static unsigned long balloon3_pin_config[] __initdata = {
 
        /* Reset, configured as GPIO wakeup source */
        GPIO1_GPIO | WAKEUP_ON_EDGE_BOTH,
-
-       /* LEDs */
-       GPIO9_GPIO,     /* NAND activity LED */
-       GPIO10_GPIO,    /* Heartbeat LED */
-
-       /* AC97 */
-       GPIO28_AC97_BITCLK,
-       GPIO29_AC97_SDATA_IN_0,
-       GPIO30_AC97_SDATA_OUT,
-       GPIO31_AC97_SYNC,
-       GPIO113_AC97_nRESET,
-       GPIO95_GPIO,
-
-       /* MMC */
-       GPIO32_MMC_CLK,
-       GPIO92_MMC_DAT_0,
-       GPIO109_MMC_DAT_1,
-       GPIO110_MMC_DAT_2,
-       GPIO111_MMC_DAT_3,
-       GPIO112_MMC_CMD,
-
-       /* USB Host */
-       GPIO88_USBH1_PWR,
-       GPIO89_USBH1_PEN,
-
-       /* PC Card */
-       GPIO48_nPOE,
-       GPIO49_nPWE,
-       GPIO50_nPIOR,
-       GPIO51_nPIOW,
-       GPIO85_nPCE_1,
-       GPIO54_nPCE_2,
-       GPIO79_PSKTSEL,
-       GPIO55_nPREG,
-       GPIO56_nPWAIT,
-       GPIO57_nIOIS16,
 };
 
 /******************************************************************************
@@ -131,6 +95,34 @@ int __init parse_balloon3_features(char *arg)
 }
 early_param("balloon3_features", parse_balloon3_features);
 
+/******************************************************************************
+ * Compact Flash slot
+ ******************************************************************************/
+#if    defined(CONFIG_PCMCIA_PXA2XX) || defined(CONFIG_PCMCIA_PXA2XX_MODULE)
+static unsigned long balloon3_cf_pin_config[] __initdata = {
+       GPIO48_nPOE,
+       GPIO49_nPWE,
+       GPIO50_nPIOR,
+       GPIO51_nPIOW,
+       GPIO85_nPCE_1,
+       GPIO54_nPCE_2,
+       GPIO79_PSKTSEL,
+       GPIO55_nPREG,
+       GPIO56_nPWAIT,
+       GPIO57_nIOIS16,
+};
+
+static void __init balloon3_cf_init(void)
+{
+       if (!balloon3_has(BALLOON3_FEATURE_CF))
+               return;
+
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_cf_pin_config));
+}
+#else
+static inline void balloon3_cf_init(void) {}
+#endif
+
 /******************************************************************************
  * NOR Flash
  ******************************************************************************/
@@ -179,6 +171,15 @@ static inline void balloon3_nor_init(void) {}
  ******************************************************************************/
 #if    defined(CONFIG_TOUCHSCREEN_UCB1400) || \
        defined(CONFIG_TOUCHSCREEN_UCB1400_MODULE)
+static unsigned long balloon3_ac97_pin_config[] __initdata = {
+       GPIO28_AC97_BITCLK,
+       GPIO29_AC97_SDATA_IN_0,
+       GPIO30_AC97_SDATA_OUT,
+       GPIO31_AC97_SYNC,
+       GPIO113_AC97_nRESET,
+       GPIO95_GPIO,
+};
+
 static struct ucb1400_pdata vpac270_ucb1400_pdata = {
        .irq            = IRQ_GPIO(BALLOON3_GPIO_CODEC_IRQ),
 };
@@ -197,6 +198,7 @@ static void __init balloon3_ts_init(void)
        if (!balloon3_has(BALLOON3_FEATURE_AUDIO))
                return;
 
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_ac97_pin_config));
        pxa_set_ac97_info(NULL);
        platform_device_register(&balloon3_ucb1400_device);
 }
@@ -208,6 +210,11 @@ static inline void balloon3_ts_init(void) {}
  * Framebuffer
  ******************************************************************************/
 #if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
+static unsigned long balloon3_lcd_pin_config[] __initdata = {
+       GPIOxx_LCD_TFT_16BPP,
+       GPIO99_GPIO,
+};
+
 static struct pxafb_mode_info balloon3_lcd_modes[] = {
        {
                .pixclock               = 38000,
@@ -242,6 +249,8 @@ static void __init balloon3_lcd_init(void)
        if (!balloon3_has(BALLOON3_FEATURE_TOPPOLY))
                return;
 
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_lcd_pin_config));
+
        ret = gpio_request(BALLOON3_GPIO_RUN_BACKLIGHT, "BKL-ON");
        if (ret) {
                pr_err("Requesting BKL-ON GPIO failed!\n");
@@ -271,6 +280,15 @@ static inline void balloon3_lcd_init(void) {}
  * SD/MMC card controller
  ******************************************************************************/
 #if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
+static unsigned long balloon3_mmc_pin_config[] __initdata = {
+       GPIO32_MMC_CLK,
+       GPIO92_MMC_DAT_0,
+       GPIO109_MMC_DAT_1,
+       GPIO110_MMC_DAT_2,
+       GPIO111_MMC_DAT_3,
+       GPIO112_MMC_CMD,
+};
+
 static struct pxamci_platform_data balloon3_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
        .gpio_card_detect       = -1,
@@ -281,6 +299,7 @@ static struct pxamci_platform_data balloon3_mci_platform_data = {
 
 static void __init balloon3_mmc_init(void)
 {
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_mmc_pin_config));
        pxa_set_mci_info(&balloon3_mci_platform_data);
 }
 #else
@@ -339,6 +358,11 @@ static inline void balloon3_irda_init(void) {}
  * USB Host
  ******************************************************************************/
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static unsigned long balloon3_uhc_pin_config[] __initdata = {
+       GPIO88_USBH1_PWR,
+       GPIO89_USBH1_PEN,
+};
+
 static struct pxaohci_platform_data balloon3_ohci_info = {
        .port_mode      = PMM_PERPORT_MODE,
        .flags          = ENABLE_PORT_ALL | POWER_CONTROL_LOW | POWER_SENSE_LOW,
@@ -348,6 +372,7 @@ static void __init balloon3_uhc_init(void)
 {
        if (!balloon3_has(BALLOON3_FEATURE_OHCI))
                return;
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_uhc_pin_config));
        pxa_set_ohci_info(&balloon3_ohci_info);
 }
 #else
@@ -358,6 +383,11 @@ static inline void balloon3_uhc_init(void) {}
  * LEDs
  ******************************************************************************/
 #if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
+static unsigned long balloon3_led_pin_config[] __initdata = {
+       GPIO9_GPIO,     /* NAND activity LED */
+       GPIO10_GPIO,    /* Heartbeat LED */
+};
+
 struct gpio_led balloon3_gpio_leds[] = {
        {
                .name                   = "balloon3:green:idle",
@@ -436,6 +466,7 @@ static struct platform_device balloon3_pcf_leds = {
 
 static void __init balloon3_leds_init(void)
 {
+       pxa2xx_mfp_config(ARRAY_AND_SIZE(balloon3_led_pin_config));
        platform_device_register(&balloon3_leds);
        platform_device_register(&balloon3_pcf_leds);
 }
@@ -757,6 +788,7 @@ static void __init balloon3_init(void)
        balloon3_ts_init();
        balloon3_udc_init();
        balloon3_uhc_init();
+       balloon3_cf_init();
 }
 
 static struct map_desc balloon3_io_desc[] __initdata = {
@@ -776,9 +808,8 @@ static void __init balloon3_map_io(void)
 
 MACHINE_START(BALLOON3, "Balloon3")
        /* Maintainer: Nick Bane. */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = balloon3_map_io,
+       .nr_irqs        = BALLOON3_NR_IRQS,
        .init_irq       = balloon3_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = balloon3_init,
index aae544631a8bf223522b1d645637a1a391828ac7..4bd7a3cda48c12b07932a36ffcaa473919f56224 100644 (file)
@@ -148,9 +148,7 @@ static void __init capc7117_init(void)
 
 MACHINE_START(CAPC7117,
              "Embedian CAPC-7117 evaluation kit based on the MXM-8x10 CoM")
-       .phys_io = 0x40000000,
        .boot_params = 0xa0000100,
-       .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io = pxa_map_io,
        .init_irq = pxa3xx_init_irq,
        .timer = &pxa_timer,
index bff6e78f033d250d803c9a9bc82474ac3804b317..ac5598ce97241f7d29947ee434d539c5c2109fe6 100644 (file)
@@ -33,6 +33,9 @@
 extern void cmx255_init(void);
 extern void cmx270_init(void);
 
+/* reserve IRQs for IT8152 */
+#define CMX2XX_NR_IRQS         (IRQ_BOARD_START + 40)
+
 /* virtual addresses for statically mapped regions */
 #define CMX2XX_VIRT_BASE       (0xe8000000)
 #define CMX2XX_IT8152_VIRT     (CMX2XX_VIRT_BASE)
@@ -511,9 +514,8 @@ static void __init cmx2xx_map_io(void)
 
 MACHINE_START(ARMCORE, "Compulab CM-X2XX")
        .boot_params    = 0xa0000100,
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = cmx2xx_map_io,
+       .nr_irqs        = CMX2XX_NR_IRQS,
        .init_irq       = cmx2xx_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = cmx2xx_init,
index c70e6c2f4e7c47daf9c8a595bf6fafd11f2971d7..922b1075b9de75ea38d2070cbedaf4f0a16a5d2b 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 
 #include <linux/gpio.h>
 #include <linux/dm9000.h>
@@ -50,6 +51,7 @@
 #include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
 #include <mach/audio.h>
+#include <mach/pxa3xx-u2d.h>
 
 #include <asm/mach/map.h>
 
@@ -68,6 +70,8 @@
 #define GPIO97_RTC_RD          (97)
 #define GPIO98_RTC_IO          (98)
 
+#define GPIO_ULPI_PHY_RST      (127)
+
 static mfp_cfg_t cm_x3xx_mfp_cfg[] __initdata = {
        /* LCD */
        GPIO54_LCD_LDD_0,
@@ -472,6 +476,78 @@ static void __init cm_x300_init_mmc(void)
 static inline void cm_x300_init_mmc(void) {}
 #endif
 
+#if defined(CONFIG_PXA310_ULPI)
+static struct clk *pout_clk;
+
+static int cm_x300_ulpi_phy_reset(void)
+{
+       int err;
+
+       /* reset the PHY */
+       err = gpio_request(GPIO_ULPI_PHY_RST, "ulpi reset");
+       if (err) {
+               pr_err("%s: failed to request ULPI reset GPIO: %d\n",
+                      __func__, err);
+               return err;
+       }
+
+       gpio_direction_output(GPIO_ULPI_PHY_RST, 0);
+       msleep(10);
+       gpio_set_value(GPIO_ULPI_PHY_RST, 1);
+       msleep(10);
+
+       gpio_free(GPIO_ULPI_PHY_RST);
+
+       return 0;
+}
+
+static inline int cm_x300_u2d_init(struct device *dev)
+{
+       int err = 0;
+
+       if (cpu_is_pxa310()) {
+               /* CLK_POUT is connected to the ULPI PHY */
+               pout_clk = clk_get(NULL, "CLK_POUT");
+               if (IS_ERR(pout_clk)) {
+                       err = PTR_ERR(pout_clk);
+                       pr_err("%s: failed to get CLK_POUT: %d\n",
+                              __func__, err);
+                       return err;
+               }
+               clk_enable(pout_clk);
+
+               err = cm_x300_ulpi_phy_reset();
+               if (err) {
+                       clk_disable(pout_clk);
+                       clk_put(pout_clk);
+               }
+       }
+
+       return err;
+}
+
+static void cm_x300_u2d_exit(struct device *dev)
+{
+       if (cpu_is_pxa310()) {
+               clk_disable(pout_clk);
+               clk_put(pout_clk);
+       }
+}
+
+static struct pxa3xx_u2d_platform_data cm_x300_u2d_platform_data = {
+       .ulpi_mode      = ULPI_SER_6PIN,
+       .init           = cm_x300_u2d_init,
+       .exit           = cm_x300_u2d_exit,
+};
+
+static void cm_x300_init_u2d(void)
+{
+       pxa3xx_set_u2d_info(&cm_x300_u2d_platform_data);
+}
+#else
+static inline void cm_x300_init_u2d(void) {}
+#endif
+
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
 static int cm_x300_ohci_init(struct device *dev)
 {
@@ -754,6 +830,7 @@ static void __init cm_x300_init(void)
        cm_x300_init_da9030();
        cm_x300_init_dm9000();
        cm_x300_init_lcd();
+       cm_x300_init_u2d();
        cm_x300_init_ohci();
        cm_x300_init_mmc();
        cm_x300_init_nand();
@@ -779,9 +856,7 @@ static void __init cm_x300_fixup(struct machine_desc *mdesc, struct tag *tags,
 }
 
 MACHINE_START(CM_X300, "CM-X300 module")
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
        .init_irq       = pxa3xx_init_irq,
        .timer          = &pxa_timer,
index 98673ac6efd0d74f66dc270a67e97e7c874ecf97..bc045100ec159927cdcd1afe84b954c103537742 100644 (file)
@@ -207,8 +207,6 @@ static void __init colibri_pxa270_income_init(void)
 }
 
 MACHINE_START(COLIBRI, "Toradex Colibri PXA270")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = COLIBRI_SDRAM_BASE + 0x100,
        .init_machine   = colibri_pxa270_init,
        .map_io         = pxa_map_io,
@@ -217,8 +215,6 @@ MACHINE_START(COLIBRI, "Toradex Colibri PXA270")
 MACHINE_END
 
 MACHINE_START(INCOME, "Income s.r.o. SH-Dmaster PXA270 SBC")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .init_machine   = colibri_pxa270_income_init,
        .map_io         = pxa_map_io,
index 40b6ac2de876cf8dcc4c0328b72b086e15253eb8..a70b256591e673414f0499c3bbe6a0b9e64b923e 100644 (file)
@@ -186,8 +186,6 @@ void __init colibri_pxa300_init(void)
 }
 
 MACHINE_START(COLIBRI300, "Toradex Colibri PXA300")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = COLIBRI_SDRAM_BASE + 0x100,
        .init_machine   = colibri_pxa300_init,
        .map_io         = pxa_map_io,
index 99e850d847103eab977badf1d7a2491df942f687..ca5f29e2e9cd412fcb3ca010603ffd3019898190 100644 (file)
@@ -255,8 +255,6 @@ void __init colibri_pxa320_init(void)
 }
 
 MACHINE_START(COLIBRI320, "Toradex Colibri PXA320")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = COLIBRI_SDRAM_BASE + 0x100,
        .init_machine   = colibri_pxa320_init,
        .map_io         = pxa_map_io,
index 3fb0fc09908076b24ed5f7b0200da4afcda12788..821229acabe6333ff3787b14ac9e8892c1c6811c 100644 (file)
@@ -720,8 +720,6 @@ static void __init fixup_corgi(struct machine_desc *desc,
 
 #ifdef CONFIG_MACH_CORGI
 MACHINE_START(CORGI, "SHARP Corgi")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_corgi,
        .map_io         = pxa_map_io,
        .init_irq       = pxa25x_init_irq,
@@ -732,8 +730,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_SHEPHERD
 MACHINE_START(SHEPHERD, "SHARP Shepherd")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_corgi,
        .map_io         = pxa_map_io,
        .init_irq       = pxa25x_init_irq,
@@ -744,8 +740,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_HUSKY
 MACHINE_START(HUSKY, "SHARP Husky")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_corgi,
        .map_io         = pxa_map_io,
        .init_irq       = pxa25x_init_irq,
index 0a0d0fe99220d7f450e61dc04495d8dfe4492be3..88fbec05ec50f09e1724e431e761b1b9b4f1a261 100644 (file)
@@ -159,7 +159,7 @@ static int pxa3xx_cpufreq_verify(struct cpufreq_policy *policy)
 
 static unsigned int pxa3xx_cpufreq_get(unsigned int cpu)
 {
-       return get_clk_frequency_khz(0);
+       return pxa3xx_get_clk_frequency_khz(0);
 }
 
 static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy,
@@ -212,7 +212,8 @@ static int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)
        policy->cpuinfo.min_freq = 104000;
        policy->cpuinfo.max_freq = (cpu_is_pxa320()) ? 806000 : 624000;
        policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
-       policy->cur = policy->min = policy->max = get_clk_frequency_khz(0);
+       policy->max = pxa3xx_get_clk_frequency_khz(0);
+       policy->cur = policy->min = policy->max;
 
        if (cpu_is_pxa300() || cpu_is_pxa310())
                ret = setup_freqs_table(policy, ARRAY_AND_SIZE(pxa300_freqs));
index 91fd4fea6a5417fc515ff1beecdfc7a6b545823b..57cacaff194db96ea3f83590517e9339efd6002e 100644 (file)
@@ -272,9 +272,7 @@ static void __init csb726_init(void)
 }
 
 MACHINE_START(CSB726, "Cogent CSB726")
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
        .init_machine   = csb726_init,
index 65447dc736c2fd5b3f0fd4e3ce4c46c3c9711dc3..08b410343870ae2518afb4303110d5807dfc12d1 100644 (file)
@@ -6,11 +6,12 @@
 
 #include <asm/pmu.h>
 #include <mach/udc.h>
+#include <mach/pxa3xx-u2d.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/pxa2xx_spi.h>
 #include <mach/camera.h>
 #include <mach/audio.h>
@@ -134,6 +135,33 @@ struct platform_device pxa27x_device_udc = {
        }
 };
 
+#ifdef CONFIG_PXA3xx
+static struct resource pxa3xx_u2d_resources[] = {
+       [0] = {
+               .start  = 0x54100000,
+               .end    = 0x54100fff,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_USB2,
+               .end    = IRQ_USB2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device pxa3xx_device_u2d = {
+       .name           = "pxa3xx-u2d",
+       .id             = -1,
+       .resource       = pxa3xx_u2d_resources,
+       .num_resources  = ARRAY_SIZE(pxa3xx_u2d_resources),
+};
+
+void __init pxa3xx_set_u2d_info(struct pxa3xx_u2d_platform_data *info)
+{
+       pxa_register_device(&pxa3xx_device_u2d, info);
+}
+#endif /* CONFIG_PXA3xx */
+
 static struct resource pxafb_resources[] = {
        [0] = {
                .start  = 0x44000000,
index 50353ea49ba455bc856d371f1e6170861337f8c4..715e8bd02e248930e449c4e6c2c169054c837c6e 100644 (file)
@@ -4,6 +4,7 @@ extern struct platform_device pxa3xx_device_mci2;
 extern struct platform_device pxa3xx_device_mci3;
 extern struct platform_device pxa25x_device_udc;
 extern struct platform_device pxa27x_device_udc;
+extern struct platform_device pxa3xx_device_u2d;
 extern struct platform_device pxa_device_fb;
 extern struct platform_device pxa_device_ffuart;
 extern struct platform_device pxa_device_btuart;
index 0517c17978f3103d96e51954237801fbf34088a0..ab48bb81b570d518f8a84f419ed2e85a857e3c13 100644 (file)
@@ -43,7 +43,7 @@
 #include <mach/pxafb.h>
 #include <mach/ohci.h>
 #include <mach/mmc.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <plat/i2c.h>
 #include <mach/camera.h>
 #include <mach/pxa2xx_spi.h>
@@ -1301,8 +1301,6 @@ static void __init em_x270_init(void)
 
 MACHINE_START(EM_X270, "Compulab EM-X270")
        .boot_params    = 0xa0000100,
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
@@ -1311,8 +1309,6 @@ MACHINE_END
 
 MACHINE_START(EXEDA, "Compulab eXeda")
        .boot_params    = 0xa0000100,
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
index 349212a1cbd3ab741a60412c431ab43fd1b17330..b25690ccadc4baeebb7da03985bcbf69d66ae3e4 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <mach/pxa25x.h>
 #include <mach/eseries-gpio.h>
+#include <mach/eseries-irq.h>
 #include <mach/audio.h>
 #include <mach/pxafb.h>
 #include <mach/udc.h>
@@ -179,10 +180,9 @@ static void __init e330_init(void)
 
 MACHINE_START(E330, "Toshiba e330")
        /* Maintainer: Ian Molton (spyro@f2s.com) */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = ESERIES_NR_IRQS,
        .init_irq       = pxa25x_init_irq,
        .fixup          = eseries_fixup,
        .init_machine   = e330_init,
@@ -229,10 +229,9 @@ static void __init e350_init(void)
 
 MACHINE_START(E350, "Toshiba e350")
        /* Maintainer: Ian Molton (spyro@f2s.com) */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = ESERIES_NR_IRQS,
        .init_irq       = pxa25x_init_irq,
        .fixup          = eseries_fixup,
        .init_machine   = e350_init,
@@ -352,10 +351,9 @@ static void __init e400_init(void)
 
 MACHINE_START(E400, "Toshiba e400")
        /* Maintainer: Ian Molton (spyro@f2s.com) */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = ESERIES_NR_IRQS,
        .init_irq       = pxa25x_init_irq,
        .fixup          = eseries_fixup,
        .init_machine   = e400_init,
@@ -541,10 +539,9 @@ static void __init e740_init(void)
 
 MACHINE_START(E740, "Toshiba e740")
        /* Maintainer: Ian Molton (spyro@f2s.com) */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = ESERIES_NR_IRQS,
        .init_irq       = pxa25x_init_irq,
        .fixup          = eseries_fixup,
        .init_machine   = e740_init,
@@ -733,10 +730,9 @@ static void __init e750_init(void)
 
 MACHINE_START(E750, "Toshiba e750")
        /* Maintainer: Ian Molton (spyro@f2s.com) */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = ESERIES_NR_IRQS,
        .init_irq       = pxa25x_init_irq,
        .fixup          = eseries_fixup,
        .init_machine   = e750_init,
@@ -929,10 +925,9 @@ static void __init e800_init(void)
 
 MACHINE_START(E800, "Toshiba e800")
        /* Maintainer: Ian Molton (spyro@f2s.com) */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = ESERIES_NR_IRQS,
        .init_irq       = pxa25x_init_irq,
        .fixup          = eseries_fixup,
        .init_machine   = e800_init,
index 626c82b1397031bef376ddf1acbfd5feb8a9fe41..80a9352d43f31017c26a079d29849bb0840beff7 100644 (file)
 #include <mach/ohci.h>
 #include <plat/i2c.h>
 #include <mach/hardware.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/camera.h>
 
 #include "devices.h"
 #include "generic.h"
 
+#define EZX_NR_IRQS                    (IRQ_BOARD_START + 24)
+
 #define GPIO12_A780_FLIP_LID           12
 #define GPIO15_A1200_FLIP_LID          15
 #define GPIO15_A910_FLIP_LID           15
@@ -796,10 +798,9 @@ static void __init a780_init(void)
 }
 
 MACHINE_START(EZX_A780, "Motorola EZX A780")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = EZX_NR_IRQS,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = a780_init,
@@ -862,10 +863,9 @@ static void __init e680_init(void)
 }
 
 MACHINE_START(EZX_E680, "Motorola EZX E680")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = EZX_NR_IRQS,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = e680_init,
@@ -928,10 +928,9 @@ static void __init a1200_init(void)
 }
 
 MACHINE_START(EZX_A1200, "Motorola EZX A1200")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = EZX_NR_IRQS,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = a1200_init,
@@ -1120,10 +1119,9 @@ static void __init a910_init(void)
 }
 
 MACHINE_START(EZX_A910, "Motorola EZX A910")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = EZX_NR_IRQS,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = a910_init,
@@ -1186,10 +1184,9 @@ static void __init e6_init(void)
 }
 
 MACHINE_START(EZX_E6, "Motorola EZX E6")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = EZX_NR_IRQS,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = e6_init,
@@ -1226,10 +1223,9 @@ static void __init e2_init(void)
 }
 
 MACHINE_START(EZX_E2, "Motorola EZX E2")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
+       .nr_irqs        = EZX_NR_IRQS,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = e2_init,
index baabb3ce088e842669bfd70e3a60e56489fcbe00..6451e9c3a93fba45a7a1b1d39693dc98f94a40d2 100644 (file)
@@ -66,8 +66,7 @@ unsigned int get_clk_frequency_khz(int info)
                return pxa25x_get_clk_frequency_khz(info);
        else if (cpu_is_pxa27x())
                return pxa27x_get_clk_frequency_khz(info);
-       else
-               return pxa3xx_get_clk_frequency_khz(info);
+       return 0;
 }
 EXPORT_SYMBOL(get_clk_frequency_khz);
 
@@ -80,8 +79,7 @@ unsigned int get_memclk_frequency_10khz(void)
                return pxa25x_get_memclk_frequency_10khz();
        else if (cpu_is_pxa27x())
                return pxa27x_get_memclk_frequency_10khz();
-       else
-               return pxa3xx_get_memclk_frequency_10khz();
+       return 0;
 }
 EXPORT_SYMBOL(get_memclk_frequency_10khz);
 
index c6305c5b8a72c1497ee05aee42d7795b07513c94..4b1ad2769ed70387fad13ba9e9a775f6e1ce2466 100644 (file)
@@ -54,11 +54,9 @@ static inline void pxa2xx_clear_reset_status(unsigned int mask) {}
 
 #ifdef CONFIG_PXA3xx
 extern unsigned pxa3xx_get_clk_frequency_khz(int);
-extern unsigned pxa3xx_get_memclk_frequency_10khz(void);
 extern void pxa3xx_clear_reset_status(unsigned int);
 #else
 #define pxa3xx_get_clk_frequency_khz(x)                (0)
-#define pxa3xx_get_memclk_frequency_10khz()    (0)
 static inline void pxa3xx_clear_reset_status(unsigned int mask) {}
 #endif
 
index 96c3451291358f74ef6fcf288dc9d489a397ef0a..1e2a9a13aec143bbb34cdf783bbc8a1a82a5571a 100644 (file)
@@ -224,9 +224,7 @@ static void __init gumstix_init(void)
 }
 
 MACHINE_START(GUMSTIX, "Gumstix")
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100, /* match u-boot bi_boot_params */
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
        .init_irq       = pxa25x_init_irq,
        .timer          = &pxa_timer,
index c1cab0871c996de961920257a3f5140f2af98a0e..7057a1f46db4ed9a35094563216137c80708ade4 100644 (file)
@@ -201,8 +201,6 @@ static void __init h5000_init(void)
 }
 
 MACHINE_START(H5400, "HP iPAQ H5000")
-       .phys_io = 0x40000000,
-       .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params = 0xa0000100,
        .map_io = pxa_map_io,
        .init_irq = pxa25x_init_irq,
index f9a2e4b0f090aa3661b701bb70ef1f93e176ff04..01b7f07ebad291d96ceb12cbbf4a5b8cdd9ac77b 100644 (file)
@@ -159,8 +159,6 @@ static void __init himalaya_init(void)
 
 
 MACHINE_START(HIMALAYA, "HTC Himalaya")
-       .phys_io = 0x40000000,
-       .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params = 0xa0000100,
        .map_io = pxa_map_io,
        .init_irq = pxa25x_init_irq,
index 848c861dd23f20acbbd121d32a9e0721acbee45c..76d93a25bab62fa33d09cb48965ba1f6267e59a4 100644 (file)
@@ -870,10 +870,9 @@ static void __init hx4700_init(void)
 }
 
 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,
+       .nr_irqs      = HX4700_NR_IRQS,
        .init_irq     = pxa27x_init_irq,
        .init_machine = hx4700_init,
        .timer        = &pxa_timer,
index 5ccb0ceff6c4160f153d795b1bbcfcf4e035facb..d51ee3d25e7027c8386635940f93a56f89fc7cbf 100644 (file)
@@ -191,9 +191,7 @@ static void __init icontrol_init(void)
 }
 
 MACHINE_START(ICONTROL, "iControl/SafeTcam boards using Embedian MXM-8x10 CoM")
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
        .init_irq       = pxa3xx_init_irq,
        .timer          = &pxa_timer,
index bc78c4dc0c66d601d79e796bd1c998544677b5b6..e773dceeabc6c8fdc3f5f627147f236118d8a6fd 100644 (file)
@@ -194,8 +194,6 @@ static void __init idp_map_io(void)
 
 MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
        /* Maintainer: Vibren Technologies */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = idp_map_io,
        .init_irq       = pxa25x_init_irq,
        .timer          = &pxa_timer,
index eec92e6fd7cf804f3ba611325cdbc491da3dcf96..561562b4360b7b22477373c8d7fab7a6eb715478 100644 (file)
@@ -174,6 +174,8 @@ enum balloon3_features {
 #define BALLOON3_CODEC_IRQ     IRQ_GPIO(BALLOON3_GPIO_CODEC_IRQ)
 #define BALLOON3_S0_CD_IRQ     IRQ_GPIO(BALLOON3_GPIO_S0_CD)
 
+#define BALLOON3_NR_IRQS       (IRQ_BOARD_START + 4)
+
 extern int balloon3_has(enum balloon3_features feature);
 
 #endif
index 01cf81393fe2d5e25787ea87b375aa510e754f2c..7d5c75125d658cd6dcb26e11ed6640254ee13382 100644 (file)
 
 #include "hardware.h"
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #0x40000000                @ physical
-               movne   \rx, #io_p2v(0x40000000)        @ virtual
-               orr     \rx, \rx, #0x00100000
+               .macro  addruart, rp, rv
+               mov     \rp, #0x00100000
+               orr     \rv, \rp, #io_p2v(0x40000000)   @ virtual
+               orr     \rp, \rp, #0x40000000           @ physical
                .endm
 
 #define UART_SHIFT     2
index f2a93d5e31d303034074425b2735e71f37227bf1..de292b269c63ead3a54c29acc920d5cab1786582 100644 (file)
@@ -25,3 +25,4 @@
 #define TMIO_SD_IRQ     IRQ_TMIO(1)
 #define TMIO_USB_IRQ    IRQ_TMIO(2)
 
+#define ESERIES_NR_IRQS        (IRQ_BOARD_START + 16)
index 9eaeed1f87f1fad6f8754dfa736473ecf113f33a..37408449ec25e023264ae8852fc3bec9feb381a6 100644 (file)
@@ -17,6 +17,7 @@
 
 #define HX4700_ASIC3_GPIO_BASE NR_BUILTIN_GPIO
 #define HX4700_EGPIO_BASE      (HX4700_ASIC3_GPIO_BASE + ASIC3_NUM_GPIOS)
+#define HX4700_NR_IRQS         (IRQ_BOARD_START + 70)
 
 /*
  * PXA GPIOs
index ffc8314520f2e109b5db96bfebdfb97096f90d90..d372caa75dc737d4ca51f4ddcc34c64ac530bd43 100644 (file)
 /*
  * 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.  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.
+ * these.
+ * By default, no board IRQ is reserved. It should be finished in
+ * custom board since sparse IRQ is already enabled.
  */
 #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)
-#elif defined(CONFIG_PXA_EZX)
-#define IRQ_BOARD_END          (IRQ_BOARD_START + 23)
-#else
-#define IRQ_BOARD_END          (IRQ_BOARD_START + 16)
-#endif
-
-/*
- * Figure out the MAX IRQ number.
- *
- * If we have an SA1111, the max IRQ is S1_BVD1_STSCHG+1.
- * If we have an LoCoMo, the max IRQ is IRQ_LOCOMO_SPI_TEND+1
- * Otherwise, we have the standard IRQs only.
- */
-#ifdef CONFIG_SA1111
-#define NR_IRQS                        (IRQ_BOARD_END + 55)
-#elif defined(CONFIG_PXA_HAVE_BOARD_IRQS)
-#define NR_IRQS                        (IRQ_BOARD_END)
-#else
 #define NR_IRQS                        (IRQ_BOARD_START)
-#endif
-
-/* add IT8152 IRQs beyond BOARD_END */
-#ifdef CONFIG_PCI_HOST_ITE8152
-#define IT8152_LAST_IRQ         (IRQ_BOARD_END + 40)
-
-#if NR_IRQS < (IT8152_LAST_IRQ+1)
-#undef NR_IRQS
-#define NR_IRQS (IT8152_LAST_IRQ+1)
-#endif
-
-#endif /* CONFIG_PCI_HOST_ITE8152 */
 
 #endif /* __ASM_MACH_IRQS_H */
index 6c9b21c5132254dad261aa1dba4097293248684d..2a5726c15e0e446f855f857d4e773a6785ba8486 100644 (file)
@@ -10,4 +10,6 @@
 #define EXT0_GPIO_BASE (NR_BUILTIN_GPIO)
 #define EXT0_GPIO(x)   (EXT0_GPIO_BASE + (x))
 
+#define LITTLETON_NR_IRQS      (IRQ_BOARD_START + 8)
+
 #endif /* __ASM_ARCH_LITTLETON_H */
index 0e6440c81683d0c18548bdd863016fa9444fe64e..cd070092b6eb708b1397fa82ba3e2e05b6104bf0 100644 (file)
@@ -38,5 +38,6 @@
 #define LPD270_USBC_IRQ                LPD270_IRQ(2)
 #define LPD270_ETHERNET_IRQ    LPD270_IRQ(3)
 #define LPD270_AC97_IRQ                LPD270_IRQ(4)
+#define LPD270_NR_IRQS         (IRQ_BOARD_START + 5)
 
 #endif
index a0d4247f08fc56aedcb845bb1c8403d64f64d11b..2a086e8373eb7bf1104892784aba7a5236a3bd5b 100644 (file)
@@ -45,6 +45,9 @@
 #define LUBBOCK_USB_DISC_IRQ   LUBBOCK_IRQ(6)  /* usb disconnect */
 #define LUBBOCK_LAST_IRQ       LUBBOCK_IRQ(6)
 
+#define LUBBOCK_SA1111_IRQ_BASE        (IRQ_BOARD_START + 16)
+#define LUBBOCK_NR_IRQS                (IRQ_BOARD_START + 16 + 55)
+
 #ifndef __ASSEMBLY__
 extern void lubbock_set_misc_wr(unsigned int mask, unsigned int set);
 #endif
index 20ef37d4a9a75b2567e73791d1ba8ee5056ae563..0a2efcf7947c5c4da26e7140f4256387f3387769 100644 (file)
@@ -71,6 +71,8 @@
 #define IRQ_MAGICIAN_BT                (IRQ_BOARD_START + 2)
 #define IRQ_MAGICIAN_VBUS      (IRQ_BOARD_START + 3)
 
+#define MAGICIAN_NR_IRQS       (IRQ_BOARD_START + 8)
+
 /*
  * CPLD EGPIOs
  */
index 86e623abd64d6404e3d39848d5fee8b1a50682d4..4c2d11cd824dda4415d1ad74af1a368ffdd9b439 100644 (file)
 #define MAINSTONE_S1_STSCHG_IRQ        MAINSTONE_IRQ(14)
 #define MAINSTONE_S1_IRQ       MAINSTONE_IRQ(15)
 
+#define MAINSTONE_NR_IRQS      (IRQ_BOARD_START + 16)
+
 #endif
index 0d119d3b922143211b12350244c3087209ba3cbd..04f7c97044f3bf4c1a8798b87bf4e86b31086975 100644 (file)
@@ -69,6 +69,7 @@
 #define nBE0_GPIO_60           MFP_CFG(nBE0, AF0)
 #define nBE1_GPIO_61           MFP_CFG(nBE1, AF0)
 #define RDY_GPIO_62            MFP_CFG(RDY, AF0)
+#define PMIC_INT_GPIO83                MFP_CFG_LPM(PMIC_INT, AF0, PULL_HIGH)
 
 /* Chip Select */
 #define DF_nCS0_nCS2           MFP_CFG_LPM(DF_nCS0, AF3, PULL_HIGH)
@@ -92,6 +93,9 @@
 #define GPIO63_CI2C_SCL                MFP_CFG_LPM(GPIO63, AF4, PULL_HIGH)
 #define GPIO64_CI2C_SDA                MFP_CFG_LPM(GPIO64, AF4, PULL_HIGH)
 
+#define GPIO73_CI2C_SCL                MFP_CFG_LPM(GPIO73, AF1, PULL_HIGH)
+#define GPIO74_CI2C_SDA                MFP_CFG_LPM(GPIO74, AF1, PULL_HIGH)
+
 #define GPIO77_CI2C_SCL                MFP_CFG_LPM(GPIO77, AF2, PULL_HIGH)
 #define GPIO78_CI2C_SDA                MFP_CFG_LPM(GPIO78, AF2, PULL_HIGH)
 
 #define GPIO69_UART1_CTS       MFP_CFG(GPIO69, AF2)
 #define GPIO70_UART1_RTS       MFP_CFG(GPIO70, AF2)
 
+#define GPIO53_UART1_TXD       MFP_CFG(GPIO53, AF2)
+#define GPIO54_UART1_RXD       MFP_CFG(GPIO54, AF2)
+
 /* UART2 - BTUART */
 #define GPIO91_UART2_RXD       MFP_CFG(GPIO91, AF1)
 #define GPIO92_UART2_TXD       MFP_CFG(GPIO92, AF1)
index 04083263167ed5ad0ab84a014cc14420c4175ffd..4bac588478a898ee6dae6107a9cd44fc7d365c69 100644 (file)
@@ -30,6 +30,8 @@
 #define PCM027_MMCDET_IRQ      PCM027_IRQ(2)
 #define PCM027_PM_5V_IRQ       PCM027_IRQ(3)
 
+#define PCM027_NR_IRQS         (IRQ_BOARD_START + 32)
+
 /* I2C RTC */
 #define PCM027_RTC_IRQ_GPIO    0
 #define PCM027_RTC_IRQ         IRQ_GPIO(PCM027_RTC_IRQ_GPIO)
index 0b3e6d051c6425d86238473ab31f25702cd29c92..83d1cfd00fc9f7d05e75c4a0c94383c479407179 100644 (file)
@@ -85,6 +85,8 @@
 #define POODLE_LOCOMO_GPIO_232VCC_ON   LOCOMO_GPIO(12)
 #define POODLE_LOCOMO_GPIO_JK_B        LOCOMO_GPIO(13)
 
+#define POODLE_NR_IRQS         (IRQ_BOARD_START + 4)   /* 4 for LoCoMo */
+
 extern struct platform_device poodle_locomo_device;
 
 #endif /* __ASM_ARCH_POODLE_H  */
diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h b/arch/arm/mach-pxa/include/mach/pxa3xx-u2d.h
new file mode 100644 (file)
index 0000000..9d82cb6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * PXA3xx U2D header
+ *
+ * Copyright (C) 2010 CompuLab Ltd.
+ *
+ * Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __PXA310_U2D__
+#define __PXA310_U2D__
+
+#include <linux/usb/ulpi.h>
+
+struct pxa3xx_u2d_platform_data {
+
+#define ULPI_SER_6PIN  (1 << 0)
+#define ULPI_SER_3PIN  (1 << 1)
+       unsigned int ulpi_mode;
+
+       int (*init)(struct device *);
+       void (*exit)(struct device *);
+};
+
+
+/* Start PXA3xx U2D host */
+int pxa3xx_u2d_start_hc(struct usb_bus *host);
+/* Stop PXA3xx U2D host */
+void pxa3xx_u2d_stop_hc(struct usb_bus *host);
+
+extern void pxa3xx_set_u2d_info(struct pxa3xx_u2d_platform_data *info);
+
+#endif /* __PXA310_U2D__ */
index 1bbd1f2e4beb3065ff75d4204d375ac88dc10847..1272c4b56ceb8de05875e75310df11b86b377982 100644 (file)
@@ -20,6 +20,7 @@
 /* Jacket Scoop */
 #define TOSA_SCOOP_PHYS        (PXA_CS5_PHYS + 0x00800000)
 
+#define TOSA_NR_IRQS           (IRQ_BOARD_START + TC6393XB_NR_IRQS)
 /*
  * SCOOP2 internal GPIOs
  */
index 6e119976003e72979af443fb07e2b82c9441f74f..faa408ab7ad72f38c6951849008c86397b866c99 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef _MACH_ZEUS_H
 #define _MACH_ZEUS_H
 
+#define ZEUS_NR_IRQS           (IRQ_BOARD_START + 48)
+
 /* Physical addresses */
 #define ZEUS_FLASH_PHYS                PXA_CS0_PHYS
 #define ZEUS_ETH0_PHYS         PXA_CS1_PHYS
index 9edf645368d65989376ca144a2d49a1fbc2d0f74..ea24998b923c27aed8b13d7aa091368b2f47a7ef 100644 (file)
@@ -5,6 +5,8 @@
 
 #define EXT_GPIO(x)            (128 + (x))
 
+#define ZYLONITE_NR_IRQS       (IRQ_BOARD_START + 32)
+
 /* the following variables are processor specific and initialized
  * by the corresponding zylonite_pxa3xx_init()
  */
index 9b9046185b00e3e8c2c7e47b13fd37c478f74640..41aa89e3577255ecfbec44bfb2cfe4a70540eeab 100644 (file)
@@ -43,7 +43,7 @@
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/pxa2xx_spi.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/littleton.h>
 #include <plat/i2c.h>
 #include <plat/pxa3xx_nand.h>
@@ -437,10 +437,9 @@ static void __init littleton_init(void)
 }
 
 MACHINE_START(LITTLETON, "Marvell Form Factor Development Platform (aka Littleton)")
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
+       .nr_irqs        = LITTLETON_NR_IRQS,
        .init_irq       = pxa3xx_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = littleton_init,
index d279507fc748275dfff6670544699cf6464eee7f..623af0232a5405d8eb29ab5e3d85df5c028fa42a 100644 (file)
@@ -505,10 +505,9 @@ static void __init lpd270_map_io(void)
 
 MACHINE_START(LOGICPD_PXA270, "LogicPD PXA270 Card Engine")
        /* Maintainer: Peter Barada */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = lpd270_map_io,
+       .nr_irqs        = LPD270_NR_IRQS,
        .init_irq       = lpd270_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = lpd270_init,
index 330c3282856e620ec879563e16655c6d56d6d2a9..1499493cd070b4636f5eb7bb7abc971cd35f385c 100644 (file)
@@ -229,7 +229,7 @@ static struct resource sa1111_resources[] = {
 };
 
 static struct sa1111_platform_data sa1111_info = {
-       .irq_base       = IRQ_BOARD_END,
+       .irq_base       = LUBBOCK_SA1111_IRQ_BASE,
 };
 
 static struct platform_device sa1111_device = {
@@ -557,9 +557,8 @@ static void __init lubbock_map_io(void)
 
 MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
        /* Maintainer: MontaVista Software Inc. */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = lubbock_map_io,
+       .nr_irqs        = LUBBOCK_NR_IRQS,
        .init_irq       = lubbock_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = lubbock_init,
index e81dd0c8e40dcced02770cb7dc57c4ca4634102b..90663760307aac11f4a1e5956ba3d7a1212ad41f 100644 (file)
@@ -764,10 +764,9 @@ static void __init magician_init(void)
 
 
 MACHINE_START(MAGICIAN, "HTC Magician")
-       .phys_io = 0x40000000,
-       .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params = 0xa0000100,
        .map_io = pxa_map_io,
+       .nr_irqs = MAGICIAN_NR_IRQS,
        .init_irq = pxa27x_init_irq,
        .init_machine = magician_init,
        .timer = &pxa_timer,
index 5543c64da9efbaedf903d8eaff3904616f90bd7e..a980a5c93e49c71e88ff256eefe6715f96d9e965 100644 (file)
@@ -50,7 +50,7 @@
 #include <mach/mmc.h>
 #include <mach/irda.h>
 #include <mach/ohci.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 
 #include "generic.h"
 #include "devices.h"
@@ -624,10 +624,9 @@ static void __init mainstone_map_io(void)
 
 MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
        /* Maintainer: MontaVista Software Inc. */
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,   /* BLOB boot parameter setting */
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = mainstone_map_io,
+       .nr_irqs        = MAINSTONE_NR_IRQS,
        .init_irq       = mainstone_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = mainstone_init,
index dc66942ef9ab47d6b911bfde28b70c1c43fb5feb..0c31fabfc7fdd46ee793252bf62fe9be2541cc47 100644 (file)
@@ -45,7 +45,7 @@
 
 #include <mach/pxa27x.h>
 #include <mach/regs-rtc.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
 #include <mach/udc.h>
@@ -819,8 +819,6 @@ static void mioa701_machine_exit(void)
 }
 
 MACHINE_START(MIOA701, "MIO A701")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = &pxa_map_io,
        .init_irq       = &pxa27x_init_irq,
index 6d4503927a760dded47a892847310a03dd6fd058..116167aaba685f0848410917531eab8690fae1ae 100644 (file)
@@ -92,9 +92,7 @@ static void __init mp900c_init(void)
 
 /* Maintainer - Michael Petchkovsky <mkpetch@internode.on.net> */
 MACHINE_START(NEC_MP900, "MobilePro900/C")
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0220100,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .timer          = &pxa_timer,
        .map_io         = pxa_map_io,
        .init_irq       = pxa25x_init_irq,
index 91038eeafe44c10680741f1266ed770d61755274..ce092c521e6df248c470bfe984e08ddac10a0f03 100644 (file)
@@ -39,7 +39,7 @@
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/palmasoc.h>
 #include <mach/palm27x.h>
 
@@ -343,8 +343,6 @@ static void __init palmld_init(void)
 }
 
 MACHINE_START(PALMLD, "Palm LifeDrive")
-       .phys_io        = PALMLD_PHYS_IO_START,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = palmld_map_io,
        .init_irq       = pxa27x_init_irq,
index 1c281995f6583faf34faa0e5daa1a5d294a7c3de..862da812cd10a61f5d80bef7290626f06bc88491 100644 (file)
@@ -39,7 +39,7 @@
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/udc.h>
 #include <mach/palmasoc.h>
 #include <mach/palm27x.h>
@@ -202,8 +202,6 @@ static void __init palmt5_init(void)
 }
 
 MACHINE_START(PALMT5, "Palm Tungsten|T5")
-       .phys_io        = PALMT5_PHYS_IO_START,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .reserve        = palmt5_reserve,
index ce1104d1bc17862834f92473cbe304070e996457..2131d5860919f6df9baa74e9765008936ed0ad69 100644 (file)
@@ -412,9 +412,7 @@ static void __init palmtc_init(void)
 };
 
 MACHINE_START(PALMTC, "Palm Tungsten|C")
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
        .init_irq       = pxa25x_init_irq,
        .timer          = &pxa_timer,
index 93c11a0438d5ac5b04705e67a1a0d5919854c0b4..a9dae7bc35d9ae585299ad4af92904c41ba9f013 100644 (file)
@@ -373,8 +373,6 @@ static void __init palmte2_init(void)
 }
 
 MACHINE_START(PALMTE2, "Palm Tungsten|E2")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .init_irq       = pxa25x_init_irq,
index 52defd5e42e520edb4912dbbaf676d6beb15d6d6..00e2d7ba84ed47c5d93c16bd699c62cdff400269 100644 (file)
@@ -39,7 +39,7 @@
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/udc.h>
 #include <mach/ohci.h>
 #include <mach/pxa2xx-regs.h>
@@ -441,8 +441,6 @@ static void __init centro_init(void)
 }
 
 MACHINE_START(TREO680, "Palm Treo 680")
-       .phys_io        = TREO_PHYS_IO_START,
-       .io_pg_offst    = io_p2v(0x40000000),
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .reserve        = treo_reserve,
@@ -452,8 +450,6 @@ MACHINE_START(TREO680, "Palm Treo 680")
 MACHINE_END
 
 MACHINE_START(CENTRO, "Palm Centro 685")
-       .phys_io        = TREO_PHYS_IO_START,
-       .io_pg_offst    = io_p2v(0x40000000),
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .reserve        = treo_reserve,
index 144dc2b6911f784f6630c8966f60d57befc7a330..d2060a1d1d6820bcaf796e1a256a92989ce45365 100644 (file)
@@ -43,7 +43,7 @@
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/udc.h>
 #include <mach/palmasoc.h>
 #include <mach/palm27x.h>
@@ -363,8 +363,6 @@ static void __init palmtx_init(void)
 }
 
 MACHINE_START(PALMTX, "Palm T|X")
-       .phys_io        = PALMTX_PHYS_IO_START,
-       .io_pg_offst    = io_p2v(0x40000000),
        .boot_params    = 0xa0000100,
        .map_io         = palmtx_map_io,
        .init_irq       = pxa27x_init_irq,
index 87e4b1044e0b68564c12f27646453123c8eea16c..af6203fbca9caa1a06299490e7aded1e9789e327 100644 (file)
@@ -41,7 +41,7 @@
 #include <mach/mmc.h>
 #include <mach/pxafb.h>
 #include <mach/irda.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/udc.h>
 #include <mach/palmasoc.h>
 #include <mach/palm27x.h>
@@ -279,8 +279,6 @@ static void __init palmz72_init(void)
 }
 
 MACHINE_START(PALMZ72, "Palm Zire72")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = io_p2v(0x40000000),
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
index 2190af066470e546a151293801f75b2311ed474c..c77e8f30a439835c2acd1ea809f9130749ac4c02 100644 (file)
@@ -259,9 +259,8 @@ static void __init pcm027_map_io(void)
 MACHINE_START(PCM027, "Phytec Messtechnik GmbH phyCORE-PXA270")
        /* Maintainer: Pengutronix */
        .boot_params    = 0xa0000100,
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pcm027_map_io,
+       .nr_irqs        = PCM027_NR_IRQS,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = pcm027_init,
index 55e8fcde0141df75dccd32b49c6a452e4f2daaea..93a191c889df5fa3d440ee269e28894a4e61dbac 100644 (file)
@@ -465,10 +465,9 @@ static void __init fixup_poodle(struct machine_desc *desc,
 }
 
 MACHINE_START(POODLE, "SHARP Poodle")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_poodle,
        .map_io         = pxa_map_io,
+       .nr_irqs        = POODLE_NR_IRQS,       /* 4 for LoCoMo */
        .init_irq       = pxa25x_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = poodle_init,
diff --git a/arch/arm/mach-pxa/pxa3xx-ulpi.c b/arch/arm/mach-pxa/pxa3xx-ulpi.c
new file mode 100644 (file)
index 0000000..ce7168b
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * linux/arch/arm/mach-pxa/pxa3xx-ulpi.c
+ *
+ * code specific to pxa3xx aka Monahans
+ *
+ * Copyright (C) 2010 CompuLab Ltd.
+ *
+ * 2010-13-07: Igor Grinberg <grinberg@compulab.co.il>
+ *             initial version: pxa310 USB Host mode 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/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/usb.h>
+#include <linux/usb/otg.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-u2d.h>
+#include <mach/pxa3xx-u2d.h>
+
+struct pxa3xx_u2d_ulpi {
+       struct clk              *clk;
+       void __iomem            *mmio_base;
+
+       struct otg_transceiver  *otg;
+       unsigned int            ulpi_mode;
+};
+
+static struct pxa3xx_u2d_ulpi *u2d;
+
+static inline u32 u2d_readl(u32 reg)
+{
+       return __raw_readl(u2d->mmio_base + reg);
+}
+
+static inline void u2d_writel(u32 reg, u32 val)
+{
+       __raw_writel(val, u2d->mmio_base + reg);
+}
+
+#if defined(CONFIG_PXA310_ULPI)
+enum u2d_ulpi_phy_mode {
+       SYNCH           = 0,
+       CARKIT          = (1 << 0),
+       SER_3PIN        = (1 << 1),
+       SER_6PIN        = (1 << 2),
+       LOWPOWER        = (1 << 3),
+};
+
+static inline enum u2d_ulpi_phy_mode pxa310_ulpi_get_phymode(void)
+{
+       return (u2d_readl(U2DOTGUSR) >> 28) & 0xF;
+}
+
+static int pxa310_ulpi_poll(void)
+{
+       int timeout = 50000;
+
+       while (timeout--) {
+               if (!(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RUN))
+                       return 0;
+
+               cpu_relax();
+       }
+
+       pr_warning("%s: ULPI access timed out!\n", __func__);
+
+       return -ETIMEDOUT;
+}
+
+static int pxa310_ulpi_read(struct otg_transceiver *otg, u32 reg)
+{
+       int err;
+
+       if (pxa310_ulpi_get_phymode() != SYNCH) {
+               pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
+               return -EBUSY;
+       }
+
+       u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | U2DOTGUCR_RNW | (reg << 16));
+       msleep(5);
+
+       err = pxa310_ulpi_poll();
+       if (err)
+               return err;
+
+       return u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA;
+}
+
+static int pxa310_ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+{
+       if (pxa310_ulpi_get_phymode() != SYNCH) {
+               pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
+               return -EBUSY;
+       }
+
+       u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | (reg << 16) | (val << 8));
+       msleep(5);
+
+       return pxa310_ulpi_poll();
+}
+
+struct otg_io_access_ops pxa310_ulpi_access_ops = {
+       .read   = pxa310_ulpi_read,
+       .write  = pxa310_ulpi_write,
+};
+
+static void pxa310_otg_transceiver_rtsm(void)
+{
+       u32 u2dotgcr;
+
+       /* put PHY to sync mode */
+       u2dotgcr = u2d_readl(U2DOTGCR);
+       u2dotgcr |=  U2DOTGCR_RTSM | U2DOTGCR_UTMID;
+       u2d_writel(U2DOTGCR, u2dotgcr);
+       msleep(10);
+
+       /* setup OTG sync mode */
+       u2dotgcr = u2d_readl(U2DOTGCR);
+       u2dotgcr |= U2DOTGCR_ULAF;
+       u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
+       u2d_writel(U2DOTGCR, u2dotgcr);
+}
+
+static int pxa310_start_otg_host_transcvr(struct usb_bus *host)
+{
+       int err;
+
+       pxa310_otg_transceiver_rtsm();
+
+       err = otg_init(u2d->otg);
+       if (err) {
+               pr_err("OTG transceiver init failed");
+               return err;
+       }
+
+       err = otg_set_vbus(u2d->otg, 1);
+       if (err) {
+               pr_err("OTG transceiver VBUS set failed");
+               return err;
+       }
+
+       err = otg_set_host(u2d->otg, host);
+       if (err)
+               pr_err("OTG transceiver Host mode set failed");
+
+       return err;
+}
+
+static int pxa310_start_otg_hc(struct usb_bus *host)
+{
+       u32 u2dotgcr;
+       int err;
+
+       /* disable USB device controller */
+       u2d_writel(U2DCR, u2d_readl(U2DCR) & ~U2DCR_UDE);
+       u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_UTMID);
+       u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~0x37F7F);
+
+       err = pxa310_start_otg_host_transcvr(host);
+       if (err)
+               return err;
+
+       /* set xceiver mode */
+       if (u2d->ulpi_mode & ULPI_IC_6PIN_SERIAL)
+               u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) & ~U2DP3CR_P2SS);
+       else if (u2d->ulpi_mode & ULPI_IC_3PIN_SERIAL)
+               u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) | U2DP3CR_P2SS);
+
+       /* start OTG host controller */
+       u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_SMAF;
+       u2d_writel(U2DOTGCR, u2dotgcr & ~(U2DOTGCR_ULAF | U2DOTGCR_CKAF));
+
+       return 0;
+}
+
+static void pxa310_stop_otg_hc(void)
+{
+       pxa310_otg_transceiver_rtsm();
+
+       otg_set_host(u2d->otg, NULL);
+       otg_set_vbus(u2d->otg, 0);
+       otg_shutdown(u2d->otg);
+}
+
+static void pxa310_u2d_setup_otg_hc(void)
+{
+       u32 u2dotgcr;
+
+       u2dotgcr = u2d_readl(U2DOTGCR);
+       u2dotgcr |= U2DOTGCR_ULAF | U2DOTGCR_UTMID;
+       u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
+       u2d_writel(U2DOTGCR, u2dotgcr);
+       msleep(5);
+       u2d_writel(U2DOTGCR, u2dotgcr | U2DOTGCR_ULE);
+       msleep(5);
+       u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~0x37F7F);
+}
+
+static int pxa310_otg_init(struct pxa3xx_u2d_platform_data *pdata)
+{
+       unsigned int ulpi_mode = ULPI_OTG_DRVVBUS;
+
+       if (pdata) {
+               if (pdata->ulpi_mode & ULPI_SER_6PIN)
+                       ulpi_mode |= ULPI_IC_6PIN_SERIAL;
+               else if (pdata->ulpi_mode & ULPI_SER_3PIN)
+                       ulpi_mode |= ULPI_IC_3PIN_SERIAL;
+       }
+
+       u2d->ulpi_mode = ulpi_mode;
+
+       u2d->otg = otg_ulpi_create(&pxa310_ulpi_access_ops, ulpi_mode);
+       if (!u2d->otg)
+               return -ENOMEM;
+
+       u2d->otg->io_priv = u2d->mmio_base;
+
+       return 0;
+}
+
+static void pxa310_otg_exit(void)
+{
+       kfree(u2d->otg);
+}
+#else
+static inline void pxa310_u2d_setup_otg_hc(void) {}
+static inline int pxa310_start_otg_hc(struct usb_bus *host)
+{
+       return 0;
+}
+static inline void pxa310_stop_otg_hc(void) {}
+static inline int pxa310_otg_init(struct pxa3xx_u2d_platform_data *pdata)
+{
+       return 0;
+}
+static inline void pxa310_otg_exit(void) {}
+#endif /* CONFIG_PXA310_ULPI */
+
+int pxa3xx_u2d_start_hc(struct usb_bus *host)
+{
+       int err = 0;
+
+       /* In case the PXA3xx ULPI isn't used, do nothing. */
+       if (!u2d)
+               return 0;
+
+       clk_enable(u2d->clk);
+
+       if (cpu_is_pxa310()) {
+               pxa310_u2d_setup_otg_hc();
+               err = pxa310_start_otg_hc(host);
+       }
+
+       return err;
+}
+
+void pxa3xx_u2d_stop_hc(struct usb_bus *host)
+{
+       /* In case the PXA3xx ULPI isn't used, do nothing. */
+       if (!u2d)
+               return;
+
+       if (cpu_is_pxa310())
+               pxa310_stop_otg_hc();
+
+       clk_disable(u2d->clk);
+}
+
+static int pxa3xx_u2d_probe(struct platform_device *pdev)
+{
+       struct pxa3xx_u2d_platform_data *pdata = pdev->dev.platform_data;
+       struct resource *r;
+       int err;
+
+       u2d = kzalloc(sizeof(struct pxa3xx_u2d_ulpi), GFP_KERNEL);
+       if (!u2d) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       u2d->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(u2d->clk)) {
+               dev_err(&pdev->dev, "failed to get u2d clock\n");
+               err = PTR_ERR(u2d->clk);
+               goto err_free_mem;
+       }
+
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!r) {
+               dev_err(&pdev->dev, "no IO memory resource defined\n");
+               err = -ENODEV;
+               goto err_put_clk;
+       }
+
+        r = request_mem_region(r->start, resource_size(r), pdev->name);
+        if (!r) {
+                dev_err(&pdev->dev, "failed to request memory resource\n");
+                err = -EBUSY;
+                goto err_put_clk;
+        }
+
+       u2d->mmio_base = ioremap(r->start, resource_size(r));
+       if (!u2d->mmio_base) {
+               dev_err(&pdev->dev, "ioremap() failed\n");
+               err = -ENODEV;
+               goto err_free_res;
+       }
+
+       if (pdata->init) {
+               err = pdata->init(&pdev->dev);
+               if (err)
+                       goto err_free_io;
+       }
+
+       /* Only PXA310 U2D has OTG functionality */
+       if (cpu_is_pxa310()) {
+               err = pxa310_otg_init(pdata);
+               if (err)
+                       goto err_free_plat;
+       }
+
+       platform_set_drvdata(pdev, &u2d);
+
+       return 0;
+
+err_free_plat:
+       if (pdata->exit)
+               pdata->exit(&pdev->dev);
+err_free_io:
+       iounmap(u2d->mmio_base);
+err_free_res:
+       release_mem_region(r->start, resource_size(r));
+err_put_clk:
+       clk_put(u2d->clk);
+err_free_mem:
+       kfree(u2d);
+       return err;
+}
+
+static int pxa3xx_u2d_remove(struct platform_device *pdev)
+{
+       struct pxa3xx_u2d_platform_data *pdata = pdev->dev.platform_data;
+       struct resource *r;
+
+       if (cpu_is_pxa310()) {
+               pxa310_stop_otg_hc();
+               pxa310_otg_exit();
+       }
+
+       if (pdata->exit)
+               pdata->exit(&pdev->dev);
+
+       platform_set_drvdata(pdev, NULL);
+       iounmap(u2d->mmio_base);
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(r->start, resource_size(r));
+
+       clk_put(u2d->clk);
+
+       kfree(u2d);
+
+       return 0;
+}
+
+static struct platform_driver pxa3xx_u2d_ulpi_driver = {
+        .driver                = {
+                .name   = "pxa3xx-u2d",
+               .owner  = THIS_MODULE,
+        },
+        .probe          = pxa3xx_u2d_probe,
+        .remove         = pxa3xx_u2d_remove,
+};
+
+static int pxa3xx_u2d_ulpi_init(void)
+{
+       return platform_driver_register(&pxa3xx_u2d_ulpi_driver);
+}
+module_init(pxa3xx_u2d_ulpi_init);
+
+static void __exit pxa3xx_u2d_ulpi_exit(void)
+{
+       platform_driver_unregister(&pxa3xx_u2d_ulpi_driver);
+}
+module_exit(pxa3xx_u2d_ulpi_exit);
+
+MODULE_DESCRIPTION("PXA3xx U2D ULPI driver");
+MODULE_AUTHOR("Igor Grinberg");
+MODULE_LICENSE("GPL v2");
index fa0014847c71503f4f929870cce2622deb0abd9d..c85c3a7abd314f84cce570a79d4f38ecce21ecce 100644 (file)
@@ -98,23 +98,6 @@ unsigned int pxa3xx_get_clk_frequency_khz(int info)
        return CLK / 1000;
 }
 
-/*
- * Return the current static memory controller clock frequency
- * in units of 10kHz
- */
-unsigned int pxa3xx_get_memclk_frequency_10khz(void)
-{
-       unsigned long acsr;
-       unsigned int smcfs, clk = 0;
-
-       acsr = ACSR;
-
-       smcfs = (acsr >> 23) & 0x7;
-       clk = (acsr & ACCR_D0CS) ? RO_CLK : smcfs_mult[smcfs] * BASE_CLK;
-
-       return (clk / 10000);
-}
-
 void pxa3xx_clear_reset_status(unsigned int mask)
 {
        /* RESET_STATUS_* has a 1:1 mapping with ARSR */
@@ -265,7 +248,7 @@ static struct clk_lookup pxa3xx_clkregs[] = {
        INIT_CLKREG(&clk_pxa3xx_i2c, "pxa2xx-i2c.0", NULL),
        INIT_CLKREG(&clk_pxa3xx_udc, "pxa27x-udc", NULL),
        INIT_CLKREG(&clk_pxa3xx_usbh, "pxa27x-ohci", NULL),
-       INIT_CLKREG(&clk_pxa3xx_u2d, NULL, "U2DCLK"),
+       INIT_CLKREG(&clk_pxa3xx_u2d, "pxa3xx-u2d", NULL),
        INIT_CLKREG(&clk_pxa3xx_keypad, "pxa27x-keypad", NULL),
        INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa27x-ssp.0", NULL),
        INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa27x-ssp.1", NULL),
index 064292008288c86f3b4b3bb9a9e7132092cf5067..7d29dd3af79d20cb55c1e20296c7f80adcd171f8 100644 (file)
@@ -192,7 +192,7 @@ static struct mfp_addr_map pxa935_mfp_addr_map[] __initdata = {
 
 static int __init pxa930_init(void)
 {
-       if (cpu_is_pxa930() || cpu_is_pxa935()) {
+       if (cpu_is_pxa930() || cpu_is_pxa935() || cpu_is_pxa950()) {
                mfp_init_base(io_p2v(MFPR_BASE));
                mfp_init_addr(pxa930_mfp_addr_map);
        }
index 67e04f4e07c122781e42ca184c30f1e7b4329e7e..4121d03ea2c3eecaa39c7c340ac0a92455adf3de 100644 (file)
@@ -1083,8 +1083,6 @@ static void __init raumfeld_speaker_init(void)
 
 #ifdef CONFIG_MACH_RAUMFELD_RC
 MACHINE_START(RAUMFELD_RC, "Raumfeld Controller")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = RAUMFELD_SDRAM_BASE + 0x100,
        .init_machine   = raumfeld_controller_init,
        .map_io         = pxa_map_io,
@@ -1095,8 +1093,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_RAUMFELD_CONNECTOR
 MACHINE_START(RAUMFELD_CONNECTOR, "Raumfeld Connector")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = RAUMFELD_SDRAM_BASE + 0x100,
        .init_machine   = raumfeld_connector_init,
        .map_io         = pxa_map_io,
@@ -1107,8 +1103,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_RAUMFELD_SPEAKER
 MACHINE_START(RAUMFELD_SPEAKER, "Raumfeld Speaker")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = RAUMFELD_SDRAM_BASE + 0x100,
        .init_machine   = raumfeld_speaker_init,
        .map_io         = pxa_map_io,
index 115b6f234bdd0e5ae0cc1fd4e3195177605d844d..4b521e045d754471df4cf4a66daff5d7434992b5 100644 (file)
@@ -596,9 +596,7 @@ static void __init saar_init(void)
 
 MACHINE_START(SAAR, "PXA930 Handheld Platform (aka SAAR)")
        /* Maintainer: Eric Miao <eric.miao@marvell.com> */
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
        .init_irq       = pxa3xx_init_irq,
        .timer          = &pxa_timer,
index 1cd99cb87bb1ff19cd9bc02e72706db89e0318a8..f736119f1ebfd46c59b7904e13685fc159b245dd 100644 (file)
@@ -979,8 +979,6 @@ static void __init spitz_fixup(struct machine_desc *desc,
 
 #ifdef CONFIG_MACH_SPITZ
 MACHINE_START(SPITZ, "SHARP Spitz")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = spitz_fixup,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
@@ -991,8 +989,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_BORZOI
 MACHINE_START(BORZOI, "SHARP Borzoi")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = spitz_fixup,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
@@ -1003,8 +999,6 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_AKITA
 MACHINE_START(AKITA, "SHARP Akita")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = spitz_fixup,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
index a654d1e6b38ad11eb6420667028c8395ab10c1ae..738adc1773fdf643cfc4a81c662fd10da0b2bc8e 100644 (file)
@@ -56,6 +56,8 @@
 #include "devices.h"
 #include "generic.h"
 
+#define STARGATE_NR_IRQS       (IRQ_BOARD_START + 8)
+
 /* Bluetooth */
 #define SG2_BT_RESET           81
 
@@ -996,8 +998,6 @@ static void __init stargate2_init(void)
 
 #ifdef CONFIG_MACH_INTELMOTE2
 MACHINE_START(INTELMOTE2, "IMOTE 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,
@@ -1008,9 +1008,8 @@ MACHINE_END
 
 #ifdef CONFIG_MACH_STARGATE2
 MACHINE_START(STARGATE2, "Stargate 2")
-       .phys_io = 0x40000000,
-       .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io = pxa_map_io,
+       .nr_irqs = STARGATE_NR_IRQS,
        .init_irq = pxa27x_init_irq,
        .timer = &pxa_timer,
        .init_machine = stargate2_init,
index f02dcb5b4e97e53e14212e0b61892abc8f3f3046..2ea7545273ad949e2b07fd2f107ef2e40a114eaf 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <mach/pxa930.h>
 #include <mach/pxafb.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 
 #include "devices.h"
 #include "generic.h"
@@ -489,9 +489,7 @@ static void __init tavorevb_init(void)
 
 MACHINE_START(TAVOREVB, "PXA930 Evaluation Board (aka TavorEVB)")
        /* Maintainer: Eric Miao <eric.miao@marvell.com> */
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
        .init_irq       = pxa3xx_init_irq,
        .timer          = &pxa_timer,
diff --git a/arch/arm/mach-pxa/tavorevb3.c b/arch/arm/mach-pxa/tavorevb3.c
new file mode 100644 (file)
index 0000000..dc30116
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ *  linux/arch/arm/mach-pxa/tavorevb3.c
+ *
+ *  Support for the Marvell EVB3 Development Platform.
+ *
+ *  Copyright:  (C) Copyright 2008-2010 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
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/mfd/88pm860x.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/pxa930.h>
+
+#include <plat/i2c.h>
+
+#include "devices.h"
+#include "generic.h"
+
+#define TAVOREVB3_NR_IRQS      (IRQ_BOARD_START + 24)
+
+static mfp_cfg_t evb3_mfp_cfg[] __initdata = {
+       /* UART */
+       GPIO53_UART1_TXD,
+       GPIO54_UART1_RXD,
+
+       /* PMIC */
+       PMIC_INT_GPIO83,
+};
+
+#if defined(CONFIG_I2C_PXA) || defined(CONFIG_I2C_PXA_MODULE)
+static struct pm860x_touch_pdata evb3_touch = {
+       .gpadc_prebias  = 1,
+       .slot_cycle     = 1,
+       .tsi_prebias    = 6,
+       .pen_prebias    = 16,
+       .pen_prechg     = 2,
+       .res_x          = 300,
+};
+
+static struct pm860x_backlight_pdata evb3_backlight[] = {
+       {
+               .id     = PM8606_ID_BACKLIGHT,
+               .iset   = PM8606_WLED_CURRENT(24),
+               .flags  = PM8606_BACKLIGHT1,
+       },
+       {},
+};
+
+static struct pm860x_led_pdata evb3_led[] = {
+       {
+               .id     = PM8606_ID_LED,
+               .iset   = PM8606_LED_CURRENT(12),
+               .flags  = PM8606_LED1_RED,
+       }, {
+               .id     = PM8606_ID_LED,
+               .iset   = PM8606_LED_CURRENT(12),
+               .flags  = PM8606_LED1_GREEN,
+       }, {
+               .id     = PM8606_ID_LED,
+               .iset   = PM8606_LED_CURRENT(12),
+               .flags  = PM8606_LED1_BLUE,
+       }, {
+               .id     = PM8606_ID_LED,
+               .iset   = PM8606_LED_CURRENT(12),
+               .flags  = PM8606_LED2_RED,
+       }, {
+               .id     = PM8606_ID_LED,
+               .iset   = PM8606_LED_CURRENT(12),
+               .flags  = PM8606_LED2_GREEN,
+       }, {
+               .id     = PM8606_ID_LED,
+               .iset   = PM8606_LED_CURRENT(12),
+               .flags  = PM8606_LED2_BLUE,
+       },
+};
+
+static struct pm860x_platform_data evb3_pm8607_info = {
+       .touch                          = &evb3_touch,
+       .backlight                      = &evb3_backlight[0],
+       .led                            = &evb3_led[0],
+       .companion_addr                 = 0x10,
+       .irq_mode                       = 0,
+       .irq_base                       = IRQ_BOARD_START,
+
+       .i2c_port                       = GI2C_PORT,
+};
+
+static struct i2c_board_info evb3_i2c_info[] = {
+       {
+               .type           = "88PM860x",
+               .addr           = 0x34,
+               .platform_data  = &evb3_pm8607_info,
+               .irq            = gpio_to_irq(mfp_to_gpio(MFP_PIN_GPIO83)),
+       },
+};
+
+static void __init evb3_init_i2c(void)
+{
+       pxa_set_i2c_info(NULL);
+       i2c_register_board_info(0, ARRAY_AND_SIZE(evb3_i2c_info));
+}
+#else
+static inline void evb3_init_i2c(void) {}
+#endif
+
+static void __init evb3_init(void)
+{
+       /* initialize MFP configurations */
+       pxa3xx_mfp_config(ARRAY_AND_SIZE(evb3_mfp_cfg));
+
+       pxa_set_ffuart_info(NULL);
+
+       evb3_init_i2c();
+}
+
+MACHINE_START(TAVOREVB3, "PXA950 Evaluation Board (aka TavorEVB3)")
+       .boot_params    = 0xa0000100,
+       .map_io         = pxa_map_io,
+       .nr_irqs        = TAVOREVB3_NR_IRQS,
+       .init_irq       = pxa3xx_init_irq,
+       .timer          = &pxa_timer,
+       .init_machine   = evb3_init,
+MACHINE_END
index 83cc3a18c2e9a0ded180a0b223f29167b3a290f7..0ee1df49606db3e33a03c76e0889dc7cc50907d0 100644 (file)
@@ -952,10 +952,9 @@ static void __init fixup_tosa(struct machine_desc *desc,
 }
 
 MACHINE_START(TOSA, "SHARP Tosa")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .fixup          = fixup_tosa,
        .map_io         = pxa_map_io,
+       .nr_irqs        = TOSA_NR_IRQS,
        .init_irq       = pxa25x_init_irq,
        .init_machine   = tosa_init,
        .timer          = &pxa_timer,
index 0acff172ef228eae96dfdc7e9dec36a2188c2430..565d062f51d58fe740ace0ec28108990a910e1d7 100644 (file)
@@ -555,8 +555,6 @@ static void __init trizeps4_map_io(void)
 
 MACHINE_START(TRIZEPS4, "Keith und Koep Trizeps IV module")
        /* MAINTAINER("Jürgen Schindele") */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = TRIZEPS4_SDRAM_BASE + 0x100,
        .init_machine   = trizeps4_init,
        .map_io         = trizeps4_map_io,
@@ -566,8 +564,6 @@ MACHINE_END
 
 MACHINE_START(TRIZEPS4WL, "Keith und Koep Trizeps IV-WL module")
        /* MAINTAINER("Jürgen Schindele") */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = TRIZEPS4_SDRAM_BASE + 0x100,
        .init_machine   = trizeps4_init,
        .map_io         = trizeps4_map_io,
index e90114a7e246ad4627db5ece88d0b2d159b677fa..438fc9a5ed59f625c21a4c6940f96c1020ad71cf 100644 (file)
@@ -992,8 +992,6 @@ static void __init viper_map_io(void)
 
 MACHINE_START(VIPER, "Arcom/Eurotech VIPER SBC")
        /* Maintainer: Marc Zyngier <maz@misterjones.org> */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = viper_map_io,
        .init_irq       = viper_init_irq,
index 37d6173bbb660868a3cb696cedcaab97b9eee66d..f45ac0961778776e1e9cc34ea540ab1825a4a013 100644 (file)
@@ -718,8 +718,6 @@ static void __init vpac270_init(void)
 }
 
 MACHINE_START(VPAC270, "Voipac PXA270")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
index d3b4e3f2e033bdea1f0cd726cd73314be23a7e5d..3260ce73d327202b5e83b7de7789ae7bab0a9b65 100644 (file)
@@ -181,8 +181,6 @@ static void __init xcep_init(void)
 }
 
 MACHINE_START(XCEP, "Iskratel XCEP")
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .boot_params    = 0xa0000100,
        .init_machine   = xcep_init,
        .map_io         = pxa_map_io,
index f0d02288b4ca3089e754dce9396ff28f23ceb3d4..fefde9848d82349e08554dd74b3fea9d7f9cbd1e 100644 (file)
@@ -37,7 +37,7 @@
 #include <mach/z2.h>
 #include <mach/pxafb.h>
 #include <mach/mmc.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <mach/pxa2xx_spi.h>
 
 #include <plat/i2c.h>
@@ -703,9 +703,7 @@ static void __init z2_init(void)
 }
 
 MACHINE_START(ZIPIT2, "Zipit Z2")
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
        .init_irq       = pxa27x_init_irq,
        .timer          = &pxa_timer,
index 03b9cb910e085b1911465e77d57a12ac11a71c9f..dea46a2d089b8a6f6d42040f8fd2debcf1b2d1c6 100644 (file)
@@ -900,10 +900,9 @@ static void __init zeus_map_io(void)
 
 MACHINE_START(ARCOM_ZEUS, "Arcom/Eurotech ZEUS")
        /* Maintainer: Marc Zyngier <maz@misterjones.org> */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = ((io_p2v(0x40000000) >> 18) & 0xfffc),
        .boot_params    = 0xa0000100,
        .map_io         = zeus_map_io,
+       .nr_irqs        = ZEUS_NR_IRQS,
        .init_irq       = zeus_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = zeus_init,
index c479cbecf784ac3c53f634d2b4fad3e1fefd4daa..f25fb6245bd787bc93636163b241f8fefe9f0210 100644 (file)
@@ -30,7 +30,7 @@
 #include <mach/zylonite.h>
 #include <mach/mmc.h>
 #include <mach/ohci.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 #include <plat/pxa3xx_nand.h>
 
 #include "devices.h"
@@ -411,10 +411,9 @@ static void __init zylonite_init(void)
 }
 
 MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
-       .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,
-       .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
+       .nr_irqs        = ZYLONITE_NR_IRQS,
        .init_irq       = pxa3xx_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = zylonite_init,
index 2fa38df284140e08099739d55305a93e7899ebe3..07c08151dfe6434be39b510e215acd79e86ea297 100644 (file)
@@ -259,6 +259,7 @@ struct mmci_platform_data realview_mmc0_plat_data = {
        .status         = realview_mmc_status,
        .gpio_wp        = 17,
        .gpio_cd        = 16,
+       .cd_invert      = true,
 };
 
 struct mmci_platform_data realview_mmc1_plat_data = {
@@ -266,6 +267,7 @@ struct mmci_platform_data realview_mmc1_plat_data = {
        .status         = realview_mmc_status,
        .gpio_wp        = 19,
        .gpio_cd        = 18,
+       .cd_invert      = true,
 };
 
 /*
index 86622289b74e97950cabe4817bfaa5fc1f378e12..90b687cbe04ef2cad3fcdf023963062233cb67f7 100644 (file)
 #error "Unknown RealView platform"
 #endif
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx,      #0x10000000
-               movne   \rx,      #0xfb000000   @ virtual base
-               orr     \rx, \rx, #DEBUG_LL_UART_OFFSET
+               .macro  addruart, rp, rv
+               mov     \rp, #DEBUG_LL_UART_OFFSET
+               orr     \rv, \rp, #0xfb000000   @ virtual base
+               orr     \rp, \rp, #0x10000000   @ physical base
                .endm
 
 #include <asm/hardware/debug-pl01x.S>
index dd53892d44a7adbaa7758cbb2293e43ee2af1433..d3cd265cb058c4acf0d29c4a14a16e097aa1ee55 100644 (file)
@@ -1,16 +1,8 @@
 #ifndef ASMARM_ARCH_SMP_H
 #define ASMARM_ARCH_SMP_H
 
-
 #include <asm/hardware/gic.h>
-
-#define hard_smp_processor_id()                        \
-       ({                                              \
-               unsigned int cpunum;                    \
-               __asm__("mrc p15, 0, %0, c0, c0, 5"     \
-                       : "=r" (cpunum));               \
-               cpunum &= 0x0F;                         \
-       })
+#include <asm/smp_mpidr.h>
 
 /*
  * We use IRQ1 as the IPI
index 991c1f8390e2a8eccfbbfae39ccab3768a7badbe..f2697106f809fd44a5ad35903496412602dfa1ba 100644 (file)
@@ -486,8 +486,6 @@ static void __init realview_eb_init(void)
 
 MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_io        = REALVIEW_EB_UART0_BASE & SECTION_MASK,
-       .io_pg_offst    = (IO_ADDRESS(REALVIEW_EB_UART0_BASE) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x00000100,
        .fixup          = realview_fixup,
        .map_io         = realview_eb_map_io,
index d2be12eb829eb3b759be8a37bc8020df9f01d253..a4125619d71b2ed54bcaad9431524803c7fe79f1 100644 (file)
@@ -378,8 +378,6 @@ static void __init realview_pb1176_init(void)
 
 MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_io        = REALVIEW_PB1176_UART0_BASE & SECTION_MASK,
-       .io_pg_offst    = (IO_ADDRESS(REALVIEW_PB1176_UART0_BASE) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x00000100,
        .fixup          = realview_pb1176_fixup,
        .map_io         = realview_pb1176_map_io,
index d591bc00b86ec74147b0ff0b8c7bb85e99d52041..117b95b2ca15c7b4bba1f398934f799fbdec570b 100644 (file)
@@ -381,8 +381,6 @@ static void __init realview_pb11mp_init(void)
 
 MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_io        = REALVIEW_PB11MP_UART0_BASE & SECTION_MASK,
-       .io_pg_offst    = (IO_ADDRESS(REALVIEW_PB11MP_UART0_BASE) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x00000100,
        .fixup          = realview_fixup,
        .map_io         = realview_pb11mp_map_io,
index 6c37621217bc916fba02af26a8d3163c4b1d4aec..929b8dc12e81754bfb0fdf88f25fa6e4d2664aa6 100644 (file)
@@ -331,8 +331,6 @@ static void __init realview_pba8_init(void)
 
 MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_io        = REALVIEW_PBA8_UART0_BASE & SECTION_MASK,
-       .io_pg_offst    = (IO_ADDRESS(REALVIEW_PBA8_UART0_BASE) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x00000100,
        .fixup          = realview_fixup,
        .map_io         = realview_pba8_map_io,
index 9428eff0b116addda238d99d492cbe9d80c6b8a5..b9f9e20031a75e1ef9442c252849689fa50d486e 100644 (file)
@@ -417,8 +417,6 @@ static void __init realview_pbx_init(void)
 
 MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_io        = REALVIEW_PBX_UART0_BASE & SECTION_MASK,
-       .io_pg_offst    = (IO_ADDRESS(REALVIEW_PBX_UART0_BASE) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x00000100,
        .fixup          = realview_pbx_fixup,
        .map_io         = realview_pbx_map_io,
index 6fc8d66395dc373d48935ec26c7364da1561ca90..85effffdc2b2a08f372f3a578e0c9e065d0ff3f8 100644 (file)
  *
 */
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #0x03000000
-               movne   \rx, #0xe0000000
-               orr     \rx, \rx, #0x00010000
-               orr     \rx, \rx, #0x00000fe0
+               .macro  addruart, rp, rv
+               mov     \rp, #0x00010000
+               orr     \rp, \rp, #0x00000fe0
+               orr     \rv, \rp, #0xe0000000   @ virtual
+               orr     \rp, \rp, #0x03000000   @ physical
                .endm
 
 #define UART_SHIFT     2
index 9a96fd69e7051e88f9d031bb91155cc56e4a8844..3bcd86fadb81ad994e771c27441eeb851c0b3d70 100644 (file)
@@ -7,4 +7,4 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x1c000000)
+#define VMALLOC_END       0xdc000000
index c7fc01e9d1f64bd9c5be760475f7d9537e497312..580b3c73d2c71ffd1b5d1a257615e4fe61bfdf61 100644 (file)
@@ -218,8 +218,6 @@ extern struct sys_timer ioc_timer;
 
 MACHINE_START(RISCPC, "Acorn-RiscPC")
        /* Maintainer: Russell King */
-       .phys_io        = 0x03000000,
-       .io_pg_offst    = ((0xe0000000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .reserve_lp0    = 1,
        .reserve_lp1    = 1,
index 0eef78b4a6ed6fa24cddf346dfe55afeaf28a2e8..5882deaa56bebcf36a0b9bc073fddd964d36f2a0 100644 (file)
 #define S3C2410_UART1_OFF (0x4000)
 #define SHIFT_2440TXF (14-9)
 
-       .macro addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1
-               ldreq   \rx, = S3C24XX_PA_UART
-               ldrne   \rx, = S3C24XX_VA_UART
+       .macro addruart, rp, rv
+               ldr     \rp, = S3C24XX_PA_UART
+               ldr     \rv, = S3C24XX_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-               add     \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+               add     \rp, \rp, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+               add     \rv, \rv, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
 #endif
        .endm
 
index 34fc05a4244b6424230d3f7d0f386ab516fed3ac..44440cbd76204f7212d97f87228ae4d8394ae4b0 100644 (file)
@@ -241,8 +241,6 @@ static void __init amlm5900_init(void)
 }
 
 MACHINE_START(AML_M5900, "AML_M5900")
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = amlm5900_map_io,
        .init_irq       = s3c24xx_init_irq,
index c1f90f6fab42c0d867ccfe25ffe7fbdee835fda8..2970ea9f7c2bfced373562f3d0c8e157a23f8bf3 100644 (file)
@@ -664,8 +664,6 @@ static void __init bast_init(void)
 
 MACHINE_START(BAST, "Simtec-BAST")
        /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = bast_map_io,
        .init_irq       = s3c24xx_init_irq,
index 3ba3bab139d0917ce45feaeb079573428f8a2af2..98c5c9e81ee9d8e20af0c27ee98d7f2e4001a8b5 100644 (file)
@@ -350,8 +350,6 @@ static void __init h1940_init(void)
 
 MACHINE_START(H1940, "IPAQ-H1940")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = h1940_map_io,
        .reserve        = h1940_reserve,
index 41f299d983eb0a06a8c9e6b64e660963b871431b..271b9aa6d40a35ecf971543790f5c44182d11f9d 100644 (file)
@@ -605,8 +605,6 @@ MACHINE_START(N30, "Acer-N30")
        /* Maintainer: Christer Weinigel <christer@weinigel.se>,
                                Ben Dooks <ben-linux@fluff.org>
        */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .timer          = &s3c24xx_timer,
        .init_machine   = n30_init,
@@ -617,8 +615,6 @@ MACHINE_END
 MACHINE_START(N35, "Acer-N35")
        /* Maintainer: Christer Weinigel <christer@weinigel.se>
        */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .timer          = &s3c24xx_timer,
        .init_machine   = n30_init,
index d8c7f2efc1a7bbf050cbcbe710fc0441eb0ae816..0aa16cd5acbcf6c9837126672e44c132befb7db5 100644 (file)
@@ -116,8 +116,6 @@ static void __init otom11_init(void)
 
 MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
        /* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = otom11_map_io,
        .init_machine   = otom11_init,
index d0e87b6e2e0fce574a843862a77666ba03a5f4df..e8f49feef28cc55736d530f186851f15a02d67ef 100644 (file)
@@ -362,8 +362,6 @@ static void __init qt2410_machine_init(void)
 }
 
 MACHINE_START(QT2410, "QT2410")
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = qt2410_map_io,
        .init_irq       = s3c24xx_init_irq,
index 452223042201afc2c60654bb0aac9a3d11c47a8a..e17f03387aba98447c00d582381d3af64bb9454b 100644 (file)
@@ -111,8 +111,6 @@ static void __init smdk2410_init(void)
 MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
                                    * to SMDK2410 */
        /* Maintainer: Jonas Dietsche */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = smdk2410_map_io,
        .init_irq       = s3c24xx_init_irq,
index 929164a8e9b148dc747d3d36e66a318128ec479b..a15d0621c22f2e4bbb4f7786d0435b575d3217ba 100644 (file)
@@ -152,8 +152,6 @@ static void __init tct_hammer_init(void)
 }
 
 MACHINE_START(TCT_HAMMER, "TCT_HAMMER")
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = tct_hammer_map_io,
        .init_irq       = s3c24xx_init_irq,
index d540d79dd264ce04b31f3eddbb6a96380a8ce19e..6ccce5a761b4009b28f0905e6ea398596fb40b86 100644 (file)
@@ -400,8 +400,6 @@ static void __init vr1000_init(void)
 
 MACHINE_START(VR1000, "Thorcom-VR1000")
        /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = vr1000_map_io,
        .init_machine   = vr1000_init,
index 478f4b4606c2bd024c4209a4f59cc8c301542b46..923e01bdf0170c370c683f5f268d87067863da3f 100644 (file)
@@ -675,8 +675,6 @@ static void __init jive_machine_init(void)
 
 MACHINE_START(JIVE, "JIVE")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
 
        .init_irq       = s3c24xx_init_irq,
index 054c9f92232aa676dad11c0b86359ad21ef47fa6..8e5758bdd666ee18bc12a419a0240e738d296e13 100644 (file)
@@ -150,8 +150,6 @@ static void __init smdk2413_machine_init(void)
 
 MACHINE_START(S3C2413, "S3C2413")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
 
        .fixup          = smdk2413_fixup,
@@ -163,8 +161,6 @@ MACHINE_END
 
 MACHINE_START(SMDK2412, "SMDK2412")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
 
        .fixup          = smdk2413_fixup,
@@ -176,8 +172,6 @@ MACHINE_END
 
 MACHINE_START(SMDK2413, "SMDK2413")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
 
        .fixup          = smdk2413_fixup,
index f291ac25d31252a8882bc632434a2c03f71e0361..83544ebe20ac9282f17498998ef5b03df8215bb8 100644 (file)
@@ -156,8 +156,6 @@ static void __init vstms_init(void)
 }
 
 MACHINE_START(VSTMS, "VSTMS")
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
 
        .fixup          = vstms_fixup,
index 5fc3f67ef265006d271d9a185d5fd6a9b5c09fbd..7fc366476d7e0e68522f8b47f8065d264840b9ed 100644 (file)
@@ -195,8 +195,6 @@ static void __init smdk2416_machine_init(void)
 
 MACHINE_START(SMDK2416, "SMDK2416")
        /* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
 
        .init_irq       = s3c24xx_init_irq,
index b73f78a9da5cfdeb40086664be5344e8b8a7756d..d7086788b1ff40c2a7a458faab5ac9c9ee4c42b0 100644 (file)
@@ -498,8 +498,6 @@ static void __init anubis_init(void)
 
 MACHINE_START(ANUBIS, "Simtec-Anubis")
        /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = anubis_map_io,
        .init_machine   = anubis_init,
index 84725791e6bfe7298d85ff0bf06a49a911812975..e3810c86a5e6fd3754f67deaa0b069dac7aec908 100644 (file)
@@ -233,8 +233,6 @@ static void __init at2440evb_init(void)
 
 
 MACHINE_START(AT2440EVB, "AT2440EVB")
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = at2440evb_map_io,
        .init_machine   = at2440evb_init,
index deaabe86741d2336acb2886e4db2ff99baece745..9f2c14ec71819f89b7f327f5c97bf70370211b92 100644 (file)
@@ -572,8 +572,6 @@ static void __init gta02_machine_init(void)
 
 MACHINE_START(NEO1973_GTA02, "GTA02")
        /* Maintainer: Nelson Castillo <arhuaco@freaks-unidos.net> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = gta02_map_io,
        .init_irq       = s3c24xx_init_irq,
index a76bcda210ad78c9aeb0a090d9c2903ca28eb5cb..f62bb4c793bdd6e226d6651d1e704b3b1459b94f 100644 (file)
@@ -691,8 +691,6 @@ static void __init mini2440_init(void)
 
 MACHINE_START(MINI2440, "MINI2440")
        /* Maintainer: Michel Pollet <buserror@gmail.com> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = mini2440_map_io,
        .init_machine   = mini2440_init,
index 3ff62de45fde3644ae2827feec9f517ec216fa7f..37dd306fb7dcab1da53f81f721e802811ae67897 100644 (file)
@@ -151,8 +151,6 @@ static void __init nexcoder_init(void)
 
 MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
        /* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = nexcoder_map_io,
        .init_machine   = nexcoder_init,
index 319458da71a0761dd4bfaa9838144ae8a991474f..14dc67897757ea4d27dcde40fab8de7af74341a5 100644 (file)
@@ -455,8 +455,6 @@ static void __init osiris_init(void)
 
 MACHINE_START(OSIRIS, "Simtec-OSIRIS")
        /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = osiris_map_io,
        .init_irq       = s3c24xx_init_irq,
index 142d1f92117651e60fdad7e55fcc52997e430962..32019bd9db3bb8506f2562ff31fc00741b0bdd26 100644 (file)
@@ -580,8 +580,6 @@ static void __init rx1950_reserve(void)
 
 MACHINE_START(RX1950, "HP iPAQ RX1950")
     /* Maintainers: Vasily Khoruzhick */
-    .phys_io = S3C2410_PA_UART,
-       .io_pg_offst = (((u32) S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params = S3C2410_SDRAM_PA + 0x100,
        .map_io = rx1950_map_io,
        .reserve        = rx1950_reserve,
index 6bb44f75a9ce65094a35c1bdad78775c1c655eee..1472b1a5b2fbc4f1348de2bf6fc74c9882b7d139 100644 (file)
@@ -218,8 +218,6 @@ static void __init rx3715_init_machine(void)
 
 MACHINE_START(RX3715, "IPAQ-RX3715")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
        .map_io         = rx3715_map_io,
        .reserve        = rx3715_reserve,
index df83276d85aeba60bd582c7e5106c1380a36d890..eedfe0f11643ddb9ac48bc487505ef8d0257d679 100644 (file)
@@ -175,8 +175,6 @@ static void __init smdk2440_machine_init(void)
 
 MACHINE_START(S3C2440, "SMDK2440")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
 
        .init_irq       = s3c24xx_init_irq,
index 4c863d3a52f4689bd50212ea6550f33ffcda8dec..4337f0a9960d17eef0c6fbe413a95ea10f2c626b 100644 (file)
@@ -132,8 +132,6 @@ static void __init smdk2443_machine_init(void)
 
 MACHINE_START(SMDK2443, "SMDK2443")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
-       .phys_io        = S3C2410_PA_UART,
-       .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C2410_SDRAM_PA + 0x100,
 
        .init_irq       = s3c24xx_init_irq,
index 239476b81f3b4fd643410401fad18c1b646739ef..0c5a73805560f664684a3692d23f8cf44749ea82 100644 (file)
 #include <mach/map.h>
 #include <plat/regs-serial.h>
 
-       .macro addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1
-               ldreq   \rx, = S3C24XX_PA_UART
-               ldrne   \rx, = S3C24XX_VA_UART
+       .macro addruart, rp, rv
+               ldr     \rp, = S3C24XX_PA_UART
+               ldr     \rv, = S3C24XX_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-               add     \rx, \rx, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+               add     \rp, \rp, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
+               add     \rv, \rv, #(S3C2410_UART1_OFF * CONFIG_DEBUG_S3C_UART)
 #endif
        .endm
 
index f9ab5d26052a38762c1559b51dbe1d46ab7786cc..a29e70550c70849ec7a8c271cb50d6684eee52da 100644 (file)
         * aligned and add in the offset when we load the value here.
         */
 
-       .macro addruart, rx, rtmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1
-               ldreq   \rx, = S3C_PA_UART
-               ldrne   \rx, = (S3C_VA_UART + S3C_PA_UART & 0xfffff)
+       .macro addruart, rp, rv
+               ldr     \rp, = S3C_PA_UART
+               ldr     \rv, = (S3C_VA_UART + S3C_PA_UART & 0xfffff)
 #if CONFIG_DEBUG_S3C_UART != 0
-               add     \rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
+               add     \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
+               add     \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
 #endif
        .endm
 
index 742dc87bd9c1f1f374a17ff2ca3b8ced7e7208a7..a53cf149476e882b7c96e5d776b39eb6486e9957 100644 (file)
@@ -233,8 +233,6 @@ static void __init anw6410_machine_init(void)
 
 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,
index fba90229f0dfb1627135f3a2c4f09517890d04c2..b2639582cacaa32013804a385e3a5b0079ae6108 100644 (file)
@@ -265,8 +265,6 @@ static void __init hmt_machine_init(void)
 
 MACHINE_START(HMT, "Airgoo-HMT")
        /* Maintainer: Peter Korsgaard <jacmet@sunsite.dk> */
-       .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         = hmt_map_io,
index bf65747ea68ec2e5700464f007870d611139999b..c4986498cd1203f93bd15783d801216f3d2f8fc8 100644 (file)
@@ -97,8 +97,6 @@ static void __init ncp_machine_init(void)
 
 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,
index e130379ba0e8df2752dfd5e4cae25e25b5dc6630..4b4475da8ec6f129c478b6c0ade9c2116738372e 100644 (file)
@@ -141,8 +141,6 @@ static void __init real6410_machine_init(void)
 
 MACHINE_START(REAL6410, "REAL6410")
        /* Maintainer: Darius Augulis <augulis.darius@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,
index 3a9639bc3d9b24df59de162b428a6965d2bba093..cb1ebeb087631a8f39cac7a85ebf597eb4a4f19e 100644 (file)
@@ -136,7 +136,7 @@ static struct platform_device smartq_usb_otg_vbus_dev = {
        .dev.platform_data      = &smartq_usb_otg_vbus_pdata,
 };
 
-static int __init smartq_bl_init(struct device *dev)
+static int smartq_bl_init(struct device *dev)
 {
     s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2));
 
index a4d59b076e3d9d31b518160b28d87d65c93d1300..3a3e5acde523c8fde3a12d254d476a9ac9d03fd2 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "mach-smartq.h"
 
-static struct gpio_led smartq5_leds[] __initdata = {
+static struct gpio_led smartq5_leds[] = {
        {
                .name                   = "smartq5:green",
                .active_low             = 1,
@@ -146,8 +146,6 @@ static void __init smartq5_machine_init(void)
 
 MACHINE_START(SMARTQ5, "SmartQ 5")
        /* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT 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         = smartq_map_io,
index e50a7d781732fd2e7d072f647439421e7489c8f3..e65375877d53437b7ee51a508025a4afc56d1414 100644 (file)
@@ -32,7 +32,7 @@
 
 #include "mach-smartq.h"
 
-static struct gpio_led smartq7_leds[] __initdata = {
+static struct gpio_led smartq7_leds[] = {
        {
                .name                   = "smartq7:red",
                .active_low             = 1,
@@ -162,8 +162,6 @@ static void __init smartq7_machine_init(void)
 
 MACHINE_START(SMARTQ7, "SmartQ 7")
        /* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT 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         = smartq_map_io,
index 59916676d8d26c2b9def21828a9386daf45e877e..3cca642f1e6da9655c4192aab673ffe8d116ab65 100644 (file)
@@ -85,8 +85,6 @@ static void __init smdk6400_machine_init(void)
 
 MACHINE_START(SMDK6400, "SMDK6400")
        /* Maintainer: Ben Dooks <ben-linux@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,
index d498219fff1bd34ed1c8b180a67c1ce24fe1835c..ec8865c03a1965d0ae51c7f64251fd8e0a08beae 100644 (file)
@@ -704,8 +704,6 @@ static void __init smdk6410_machine_init(void)
 
 MACHINE_START(SMDK6410, "SMDK6410")
        /* Maintainer: Ben Dooks <ben-linux@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       = s3c6410_init_irq,
diff --git a/arch/arm/mach-s5p6440/Kconfig b/arch/arm/mach-s5p6440/Kconfig
deleted file mode 100644 (file)
index 6a4af7f..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-# arch/arm/mach-s5p6440/Kconfig
-#
-# Copyright (c) 2009 Samsung Electronics Co., Ltd.
-#              http://www.samsung.com/
-#
-# Licensed under GPLv2
-
-if ARCH_S5P6440
-
-config CPU_S5P6440
-       bool
-       select S3C_PL330_DMA
-       help
-         Enable S5P6440 CPU support
-
-config S5P6440_SETUP_I2C1
-       bool
-       help
-         Common setup code for i2c bus 1.
-
-config MACH_SMDK6440
-       bool "SMDK6440"
-       select CPU_S5P6440
-       select S3C_DEV_I2C1
-       select S3C_DEV_RTC
-       select S3C_DEV_WDT
-       select SAMSUNG_DEV_ADC
-       select SAMSUNG_DEV_TS
-       select S5P6440_SETUP_I2C1
-       help
-         Machine support for the Samsung SMDK6440
-
-endif
diff --git a/arch/arm/mach-s5p6440/Makefile b/arch/arm/mach-s5p6440/Makefile
deleted file mode 100644 (file)
index c3fe4d3..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# arch/arm/mach-s5p6440/Makefile
-#
-# Copyright (c) 2009 Samsung Electronics Co., Ltd.
-#              http://www.samsung.com/
-#
-# Licensed under GPLv2
-
-obj-y                          :=
-obj-m                          :=
-obj-n                          :=
-obj-                           :=
-
-# Core support for S5P6440 system
-
-obj-$(CONFIG_CPU_S5P6440)      += cpu.o init.o clock.o gpio.o dma.o
-obj-$(CONFIG_CPU_S5P6440)      += setup-i2c0.o
-
-# machine support
-
-obj-$(CONFIG_MACH_SMDK6440)    += mach-smdk6440.o
-
-# device support
-obj-y                          += dev-audio.o
-obj-$(CONFIG_S3C64XX_DEV_SPI)  += dev-spi.o
-obj-$(CONFIG_S5P6440_SETUP_I2C1)       += setup-i2c1.o
diff --git a/arch/arm/mach-s5p6440/clock.c b/arch/arm/mach-s5p6440/clock.c
deleted file mode 100644 (file)
index ca6e48d..0000000
+++ /dev/null
@@ -1,846 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/clock.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6440 - Clock 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/module.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/sysdev.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-
-#include <plat/cpu-freq.h>
-#include <mach/regs-clock.h>
-#include <plat/clock.h>
-#include <plat/cpu.h>
-#include <plat/clock-clksrc.h>
-#include <plat/s5p-clock.h>
-#include <plat/pll.h>
-#include <plat/s5p6440.h>
-
-/* APLL Mux output clock */
-static struct clksrc_clk clk_mout_apll = {
-       .clk    = {
-               .name           = "mout_apll",
-               .id             = -1,
-       },
-       .sources        = &clk_src_apll,
-       .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 },
-};
-
-static int s5p6440_epll_enable(struct clk *clk, int enable)
-{
-       unsigned int ctrlbit = clk->ctrlbit;
-       unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit;
-
-       if (enable)
-               __raw_writel(epll_con | ctrlbit, S5P_EPLL_CON);
-       else
-               __raw_writel(epll_con, S5P_EPLL_CON);
-
-       return 0;
-}
-
-static unsigned long s5p6440_epll_get_rate(struct clk *clk)
-{
-       return clk->rate;
-}
-
-static u32 epll_div[][5] = {
-       { 36000000,     0,      48, 1, 4 },
-       { 48000000,     0,      32, 1, 3 },
-       { 60000000,     0,      40, 1, 3 },
-       { 72000000,     0,      48, 1, 3 },
-       { 84000000,     0,      28, 1, 2 },
-       { 96000000,     0,      32, 1, 2 },
-       { 32768000,     45264,  43, 1, 4 },
-       { 45158000,     6903,   30, 1, 3 },
-       { 49152000,     50332,  32, 1, 3 },
-       { 67738000,     10398,  45, 1, 3 },
-       { 73728000,     9961,   49, 1, 3 }
-};
-
-static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate)
-{
-       unsigned int epll_con, epll_con_k;
-       unsigned int i;
-
-       if (clk->rate == rate)  /* Return if nothing changed */
-               return 0;
-
-       epll_con = __raw_readl(S5P_EPLL_CON);
-       epll_con_k = __raw_readl(S5P_EPLL_CON_K);
-
-       epll_con_k &= ~(PLL90XX_KDIV_MASK);
-       epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
-
-       for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
-                if (epll_div[i][0] == rate) {
-                       epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
-                       epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
-                                   (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
-                                   (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
-                       break;
-               }
-       }
-
-       if (i == ARRAY_SIZE(epll_div)) {
-               printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
-               return -EINVAL;
-       }
-
-       __raw_writel(epll_con, S5P_EPLL_CON);
-       __raw_writel(epll_con_k, S5P_EPLL_CON_K);
-
-       clk->rate = rate;
-
-       return 0;
-}
-
-static struct clk_ops s5p6440_epll_ops = {
-       .get_rate = s5p6440_epll_get_rate,
-       .set_rate = s5p6440_epll_set_rate,
-};
-
-static struct clksrc_clk clk_mout_epll = {
-       .clk    = {
-               .name           = "mout_epll",
-               .id             = -1,
-       },
-       .sources        = &clk_src_epll,
-       .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 2, .size = 1 },
-};
-
-static struct clksrc_clk clk_mout_mpll = {
-       .clk = {
-               .name           = "mout_mpll",
-               .id             = -1,
-       },
-       .sources        = &clk_src_mpll,
-       .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 1, .size = 1 },
-};
-
-enum perf_level {
-       L0 = 532*1000,
-       L1 = 266*1000,
-       L2 = 133*1000,
-};
-
-static const u32 clock_table[][3] = {
-       /*{ARM_CLK, DIVarm, DIVhclk}*/
-       {L0 * 1000, (0 << ARM_DIV_RATIO_SHIFT), (3 << S5P_CLKDIV0_HCLK_SHIFT)},
-       {L1 * 1000, (1 << ARM_DIV_RATIO_SHIFT), (1 << S5P_CLKDIV0_HCLK_SHIFT)},
-       {L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P_CLKDIV0_HCLK_SHIFT)},
-};
-
-static unsigned long s5p6440_armclk_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(ARM_CLK_DIV) & ARM_DIV_MASK;
-
-       return rate / (clkdiv + 1);
-}
-
-static unsigned long s5p6440_armclk_round_rate(struct clk *clk,
-                                               unsigned long rate)
-{
-       u32 iter;
-
-       for (iter = 1 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
-               if (rate > clock_table[iter][0])
-                       return clock_table[iter-1][0];
-       }
-
-       return clock_table[ARRAY_SIZE(clock_table) - 1][0];
-}
-
-static int s5p6440_armclk_set_rate(struct clk *clk, unsigned long rate)
-{
-       u32 round_tmp;
-       u32 iter;
-       u32 clk_div0_tmp;
-       u32 cur_rate = clk->ops->get_rate(clk);
-       unsigned long flags;
-
-       round_tmp = clk->ops->round_rate(clk, rate);
-       if (round_tmp == cur_rate)
-               return 0;
-
-
-       for (iter = 0 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
-               if (round_tmp == clock_table[iter][0])
-                       break;
-       }
-
-       if (iter >= ARRAY_SIZE(clock_table))
-               iter = ARRAY_SIZE(clock_table) - 1;
-
-       local_irq_save(flags);
-       if (cur_rate > round_tmp) {
-               /* Frequency Down */
-               clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
-               clk_div0_tmp |= clock_table[iter][1];
-               __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
-
-               clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
-                               ~(S5P_CLKDIV0_HCLK_MASK);
-               clk_div0_tmp |= clock_table[iter][2];
-               __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
-
-
-       } else {
-               /* Frequency Up */
-               clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
-                               ~(S5P_CLKDIV0_HCLK_MASK);
-               clk_div0_tmp |= clock_table[iter][2];
-               __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
-
-               clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
-               clk_div0_tmp |= clock_table[iter][1];
-               __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
-               }
-       local_irq_restore(flags);
-
-       clk->rate = clock_table[iter][0];
-
-       return 0;
-}
-
-static struct clk_ops s5p6440_clkarm_ops = {
-       .get_rate       = s5p6440_armclk_get_rate,
-       .set_rate       = s5p6440_armclk_set_rate,
-       .round_rate     = s5p6440_armclk_round_rate,
-};
-
-static struct clksrc_clk clk_armclk = {
-       .clk    = {
-               .name   = "armclk",
-               .id     = 1,
-               .parent = &clk_mout_apll.clk,
-               .ops    = &s5p6440_clkarm_ops,
-       },
-       .reg_div        = { .reg = S5P_CLK_DIV0, .shift = 0, .size = 4 },
-};
-
-static struct clksrc_clk clk_dout_mpll = {
-       .clk    = {
-               .name   = "dout_mpll",
-               .id     = -1,
-               .parent = &clk_mout_mpll.clk,
-       },
-       .reg_div        = { .reg = S5P_CLK_DIV0, .shift = 4, .size = 1 },
-};
-
-static struct clksrc_clk clk_hclk = {
-       .clk    = {
-               .name   = "clk_hclk",
-               .id     = -1,
-               .parent = &clk_armclk.clk,
-       },
-       .reg_div        = { .reg = S5P_CLK_DIV0, .shift = 8, .size = 4 },
-};
-
-static struct clksrc_clk clk_pclk = {
-       .clk    = {
-               .name   = "clk_pclk",
-               .id     = -1,
-               .parent = &clk_hclk.clk,
-       },
-       .reg_div = { .reg = S5P_CLK_DIV0, .shift = 12, .size = 4 },
-};
-
-static struct clk *clkset_hclklow_list[] = {
-       &clk_mout_apll.clk,
-       &clk_mout_mpll.clk,
-};
-
-static struct clksrc_sources clkset_hclklow = {
-       .sources        = clkset_hclklow_list,
-       .nr_sources     = ARRAY_SIZE(clkset_hclklow_list),
-};
-
-static struct clksrc_clk clk_hclk_low = {
-       .clk = {
-               .name   = "hclk_low",
-               .id     = -1,
-       },
-       .sources        = &clkset_hclklow,
-       .reg_src        = { .reg = S5P_SYS_OTHERS, .shift = 6, .size = 1 },
-       .reg_div        = { .reg = S5P_CLK_DIV3, .shift = 8, .size = 4 },
-};
-
-static struct clksrc_clk clk_pclk_low = {
-       .clk    = {
-               .name   = "pclk_low",
-               .id     = -1,
-               .parent = &clk_hclk_low.clk,
-       },
-       .reg_div = { .reg = S5P_CLK_DIV3, .shift = 12, .size = 4 },
-};
-
-int s5p6440_clk48m_ctrl(struct clk *clk, int enable)
-{
-       unsigned long flags;
-       u32 val;
-
-       /* can't rely on clock lock, this register has other usages */
-       local_irq_save(flags);
-
-       val = __raw_readl(S5P_OTHERS);
-       if (enable)
-               val |= S5P_OTHERS_USB_SIG_MASK;
-       else
-               val &= ~S5P_OTHERS_USB_SIG_MASK;
-
-       __raw_writel(val, S5P_OTHERS);
-
-       local_irq_restore(flags);
-
-       return 0;
-}
-
-static int s5p6440_pclk_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLK_GATE_PCLK, clk, enable);
-}
-
-static int s5p6440_hclk0_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLK_GATE_HCLK0, clk, enable);
-}
-
-static int s5p6440_hclk1_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLK_GATE_HCLK1, clk, enable);
-}
-
-static int s5p6440_sclk_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLK_GATE_SCLK0, clk, enable);
-}
-
-static int s5p6440_sclk1_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLK_GATE_SCLK1, clk, enable);
-}
-
-static int s5p6440_mem_ctrl(struct clk *clk, int enable)
-{
-       return s5p_gatectrl(S5P_CLK_GATE_MEM0, clk, enable);
-}
-
-/*
- * The following clocks will be disabled during clock initialization. It is
- * recommended to keep the following clocks disabled until the driver requests
- * for enabling the clock.
- */
-static struct clk init_clocks_disable[] = {
-       {
-               .name           = "nand",
-               .id             = -1,
-               .parent         = &clk_hclk.clk,
-               .enable         = s5p6440_mem_ctrl,
-               .ctrlbit        = S5P_CLKCON_MEM0_HCLK_NFCON,
-       }, {
-               .name           = "adc",
-               .id             = -1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_TSADC,
-       }, {
-               .name           = "i2c",
-               .id             = -1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_IIC0,
-       }, {
-               .name           = "i2s_v40",
-               .id             = 0,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_IIS2,
-       }, {
-               .name           = "spi",
-               .id             = 0,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_SPI0,
-       }, {
-               .name           = "spi",
-               .id             = 1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_SPI1,
-       }, {
-               .name           = "sclk_spi_48",
-               .id             = 0,
-               .parent         = &clk_48m,
-               .enable         = s5p6440_sclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_SCLK0_SPI0_48,
-       }, {
-               .name           = "sclk_spi_48",
-               .id             = 1,
-               .parent         = &clk_48m,
-               .enable         = s5p6440_sclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_SCLK0_SPI1_48,
-       }, {
-               .name           = "mmc_48m",
-               .id             = 0,
-               .parent         = &clk_48m,
-               .enable         = s5p6440_sclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_SCLK0_MMC0_48,
-       }, {
-               .name           = "mmc_48m",
-               .id             = 1,
-               .parent         = &clk_48m,
-               .enable         = s5p6440_sclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_SCLK0_MMC1_48,
-       }, {
-               .name           = "mmc_48m",
-               .id             = 2,
-               .parent         = &clk_48m,
-               .enable         = s5p6440_sclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_SCLK0_MMC2_48,
-       }, {
-               .name           = "otg",
-               .id             = -1,
-               .parent         = &clk_hclk_low.clk,
-               .enable         = s5p6440_hclk0_ctrl,
-               .ctrlbit        = S5P_CLKCON_HCLK0_USB
-       }, {
-               .name           = "post",
-               .id             = -1,
-               .parent         = &clk_hclk_low.clk,
-               .enable         = s5p6440_hclk0_ctrl,
-               .ctrlbit        = S5P_CLKCON_HCLK0_POST0
-       }, {
-               .name           = "lcd",
-               .id             = -1,
-               .parent         = &clk_hclk_low.clk,
-               .enable         = s5p6440_hclk1_ctrl,
-               .ctrlbit        = S5P_CLKCON_HCLK1_DISPCON,
-       }, {
-               .name           = "hsmmc",
-               .id             = 0,
-               .parent         = &clk_hclk_low.clk,
-               .enable         = s5p6440_hclk0_ctrl,
-               .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC0,
-       }, {
-               .name           = "hsmmc",
-               .id             = 1,
-               .parent         = &clk_hclk_low.clk,
-               .enable         = s5p6440_hclk0_ctrl,
-               .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC1,
-       }, {
-               .name           = "hsmmc",
-               .id             = 2,
-               .parent         = &clk_hclk_low.clk,
-               .enable         = s5p6440_hclk0_ctrl,
-               .ctrlbit        = S5P_CLKCON_HCLK0_HSMMC2,
-       }, {
-               .name           = "rtc",
-               .id             = -1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_RTC,
-       }, {
-               .name           = "watchdog",
-               .id             = -1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_WDT,
-       }, {
-               .name           = "timers",
-               .id             = -1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_PWM,
-       }, {
-               .name           = "hclk_fimgvg",
-               .id             = -1,
-               .parent         = &clk_hclk.clk,
-               .enable         = s5p6440_hclk1_ctrl,
-               .ctrlbit        = (1 << 2),
-       }, {
-               .name           = "tsi",
-               .id             = -1,
-               .parent         = &clk_hclk_low.clk,
-               .enable         = s5p6440_hclk1_ctrl,
-               .ctrlbit        = (1 << 0),
-       }, {
-               .name           = "pclk_fimgvg",
-               .id             = -1,
-               .parent         = &clk_pclk.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = (1 << 31),
-       }, {
-               .name           = "dmc0",
-               .id             = -1,
-               .parent         = &clk_pclk.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = (1 << 30),
-       }, {
-               .name           = "etm",
-               .id             = -1,
-               .parent         = &clk_pclk.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = (1 << 29),
-       }, {
-               .name           = "dsim",
-               .id             = -1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = (1 << 28),
-       }, {
-               .name           = "gps",
-               .id             = -1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = (1 << 25),
-       }, {
-               .name           = "pcm",
-               .id             = -1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = (1 << 8),
-       }, {
-               .name           = "irom",
-               .id             = -1,
-               .parent         = &clk_hclk.clk,
-               .enable         = s5p6440_hclk0_ctrl,
-               .ctrlbit        = (1 << 25),
-       }, {
-               .name           = "dma",
-               .id             = -1,
-               .parent         = &clk_hclk_low.clk,
-               .enable         = s5p6440_hclk0_ctrl,
-               .ctrlbit        = (1 << 12),
-       }, {
-               .name           = "2d",
-               .id             = -1,
-               .parent         = &clk_hclk.clk,
-               .enable         = s5p6440_hclk0_ctrl,
-               .ctrlbit        = (1 << 8),
-       },
-};
-
-/*
- * The following clocks will be enabled during clock initialization.
- */
-static struct clk init_clocks[] = {
-       {
-               .name           = "gpio",
-               .id             = -1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_GPIO,
-       }, {
-               .name           = "uart",
-               .id             = 0,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_UART0,
-       }, {
-               .name           = "uart",
-               .id             = 1,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_UART1,
-       }, {
-               .name           = "uart",
-               .id             = 2,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_UART2,
-       }, {
-               .name           = "uart",
-               .id             = 3,
-               .parent         = &clk_pclk_low.clk,
-               .enable         = s5p6440_pclk_ctrl,
-               .ctrlbit        = S5P_CLKCON_PCLK_UART3,
-       }, {
-               .name           = "mem",
-               .id             = -1,
-               .parent         = &clk_hclk.clk,
-               .enable         = s5p6440_hclk0_ctrl,
-               .ctrlbit        = (1 << 21),
-       }, {
-               .name           = "intc",
-               .id             = -1,
-               .parent         = &clk_hclk.clk,
-               .enable         = s5p6440_hclk0_ctrl,
-               .ctrlbit        = (1 << 1),
-       },
-};
-
-static struct clk clk_iis_cd_v40 = {
-       .name           = "iis_cdclk_v40",
-       .id             = -1,
-};
-
-static struct clk clk_pcm_cd = {
-       .name           = "pcm_cdclk",
-       .id             = -1,
-};
-
-static struct clk *clkset_group1_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll.clk,
-       &clk_fin_epll,
-};
-
-static struct clksrc_sources clkset_group1 = {
-       .sources        = clkset_group1_list,
-       .nr_sources     = ARRAY_SIZE(clkset_group1_list),
-};
-
-static struct clk *clkset_uart_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll.clk,
-};
-
-static struct clksrc_sources clkset_uart = {
-       .sources        = clkset_uart_list,
-       .nr_sources     = ARRAY_SIZE(clkset_uart_list),
-};
-
-static struct clk *clkset_audio_list[] = {
-       &clk_mout_epll.clk,
-       &clk_dout_mpll.clk,
-       &clk_fin_epll,
-       &clk_iis_cd_v40,
-       &clk_pcm_cd,
-};
-
-static struct clksrc_sources clkset_audio = {
-       .sources        = clkset_audio_list,
-       .nr_sources     = ARRAY_SIZE(clkset_audio_list),
-};
-
-static struct clksrc_clk clksrcs[] = {
-       {
-               .clk    = {
-                       .name           = "mmc_bus",
-                       .id             = 0,
-                       .ctrlbit        = S5P_CLKCON_SCLK0_MMC0,
-                       .enable         = s5p6440_sclk_ctrl,
-               },
-               .sources = &clkset_group1,
-               .reg_src = { .reg = S5P_CLK_SRC0, .shift = 18, .size = 2 },
-               .reg_div = { .reg = S5P_CLK_DIV1, .shift = 0, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "mmc_bus",
-                       .id             = 1,
-                       .ctrlbit        = S5P_CLKCON_SCLK0_MMC1,
-                       .enable         = s5p6440_sclk_ctrl,
-               },
-               .sources = &clkset_group1,
-               .reg_src = { .reg = S5P_CLK_SRC0, .shift = 20, .size = 2 },
-               .reg_div = { .reg = S5P_CLK_DIV1, .shift = 4, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "mmc_bus",
-                       .id             = 2,
-                       .ctrlbit        = S5P_CLKCON_SCLK0_MMC2,
-                       .enable         = s5p6440_sclk_ctrl,
-               },
-               .sources = &clkset_group1,
-               .reg_src = { .reg = S5P_CLK_SRC0, .shift = 22, .size = 2 },
-               .reg_div = { .reg = S5P_CLK_DIV1, .shift = 8, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "uclk1",
-                       .id             = -1,
-                       .ctrlbit        = S5P_CLKCON_SCLK0_UART,
-                       .enable         = s5p6440_sclk_ctrl,
-               },
-               .sources = &clkset_uart,
-               .reg_src = { .reg = S5P_CLK_SRC0, .shift = 13, .size = 1 },
-               .reg_div = { .reg = S5P_CLK_DIV2, .shift = 16, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "spi_epll",
-                       .id             = 0,
-                       .ctrlbit        = S5P_CLKCON_SCLK0_SPI0,
-                       .enable         = s5p6440_sclk_ctrl,
-               },
-               .sources = &clkset_group1,
-               .reg_src = { .reg = S5P_CLK_SRC0, .shift = 14, .size = 2 },
-               .reg_div = { .reg = S5P_CLK_DIV2, .shift = 0, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "spi_epll",
-                       .id             = 1,
-                       .ctrlbit        = S5P_CLKCON_SCLK0_SPI1,
-                       .enable         = s5p6440_sclk_ctrl,
-               },
-               .sources = &clkset_group1,
-               .reg_src = { .reg = S5P_CLK_SRC0, .shift = 16, .size = 2 },
-               .reg_div = { .reg = S5P_CLK_DIV2, .shift = 4, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "sclk_post",
-                       .id             = -1,
-                       .ctrlbit        = (1 << 10),
-                       .enable         = s5p6440_sclk_ctrl,
-               },
-               .sources = &clkset_group1,
-               .reg_src = { .reg = S5P_CLK_SRC0, .shift = 26, .size = 2 },
-               .reg_div = { .reg = S5P_CLK_DIV1, .shift = 12, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "sclk_dispcon",
-                       .id             = -1,
-                       .ctrlbit        = (1 << 1),
-                       .enable         = s5p6440_sclk1_ctrl,
-               },
-               .sources = &clkset_group1,
-               .reg_src = { .reg = S5P_CLK_SRC1, .shift = 4, .size = 2 },
-               .reg_div = { .reg = S5P_CLK_DIV3, .shift = 0, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "sclk_fimgvg",
-                       .id             = -1,
-                       .ctrlbit        = (1 << 2),
-                       .enable         = s5p6440_sclk1_ctrl,
-               },
-               .sources = &clkset_group1,
-               .reg_src = { .reg = S5P_CLK_SRC1, .shift = 8, .size = 2 },
-               .reg_div = { .reg = S5P_CLK_DIV3, .shift = 4, .size = 4 },
-       }, {
-               .clk    = {
-                       .name           = "sclk_audio2",
-                       .id             = -1,
-                       .ctrlbit        = (1 << 11),
-                       .enable         = s5p6440_sclk_ctrl,
-               },
-               .sources = &clkset_audio,
-               .reg_src = { .reg = S5P_CLK_SRC1, .shift = 0, .size = 3 },
-               .reg_div = { .reg = S5P_CLK_DIV2, .shift = 24, .size = 4 },
-       },
-};
-
-/* Clock initialisation code */
-static struct clksrc_clk *sysclks[] = {
-       &clk_mout_apll,
-       &clk_mout_epll,
-       &clk_mout_mpll,
-       &clk_dout_mpll,
-       &clk_armclk,
-       &clk_hclk,
-       &clk_pclk,
-       &clk_hclk_low,
-       &clk_pclk_low,
-};
-
-void __init_or_cpufreq s5p6440_setup_clocks(void)
-{
-       struct clk *xtal_clk;
-       unsigned long xtal;
-       unsigned long fclk;
-       unsigned long hclk;
-       unsigned long hclk_low;
-       unsigned long pclk;
-       unsigned long pclk_low;
-       unsigned long epll;
-       unsigned long apll;
-       unsigned long mpll;
-       unsigned int ptr;
-
-       /* Set S5P6440 functions for clk_fout_epll */
-       clk_fout_epll.enable = s5p6440_epll_enable;
-       clk_fout_epll.ops = &s5p6440_epll_ops;
-
-       clk_48m.enable = s5p6440_clk48m_ctrl;
-
-       xtal_clk = clk_get(NULL, "ext_xtal");
-       BUG_ON(IS_ERR(xtal_clk));
-
-       xtal = clk_get_rate(xtal_clk);
-       clk_put(xtal_clk);
-
-       epll = s5p_get_pll90xx(xtal, __raw_readl(S5P_EPLL_CON),
-                               __raw_readl(S5P_EPLL_CON_K));
-       mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
-       apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4502);
-
-       clk_fout_mpll.rate = mpll;
-       clk_fout_epll.rate = epll;
-       clk_fout_apll.rate = apll;
-
-       printk(KERN_INFO "S5P6440: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
-                       " E=%ld.%ldMHz\n",
-                       print_mhz(apll), print_mhz(mpll), print_mhz(epll));
-
-       fclk = clk_get_rate(&clk_armclk.clk);
-       hclk = clk_get_rate(&clk_hclk.clk);
-       pclk = clk_get_rate(&clk_pclk.clk);
-       hclk_low = clk_get_rate(&clk_hclk_low.clk);
-       pclk_low = clk_get_rate(&clk_pclk_low.clk);
-
-       printk(KERN_INFO "S5P6440: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
-                       " PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
-                       print_mhz(hclk), print_mhz(hclk_low),
-                       print_mhz(pclk), print_mhz(pclk_low));
-
-       clk_f.rate = fclk;
-       clk_h.rate = hclk;
-       clk_p.rate = pclk;
-
-       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
-               s3c_set_clksrc(&clksrcs[ptr], true);
-}
-
-static struct clk *clks[] __initdata = {
-       &clk_ext,
-       &clk_iis_cd_v40,
-       &clk_pcm_cd,
-};
-
-void __init s5p6440_register_clocks(void)
-{
-       struct clk *clkp;
-       int ret;
-       int ptr;
-
-       ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
-       if (ret > 0)
-               printk(KERN_ERR "Failed to register %u clocks\n", ret);
-
-       for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
-               s3c_register_clksrc(sysclks[ptr], 1);
-
-       s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
-       s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
-
-       clkp = init_clocks_disable;
-       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
-
-               ret = s3c24xx_register_clock(clkp);
-               if (ret < 0) {
-                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
-                              clkp->name, ret);
-               }
-               (clkp->enable)(clkp, 0);
-       }
-
-       s3c_pwmclk_init();
-}
diff --git a/arch/arm/mach-s5p6440/cpu.c b/arch/arm/mach-s5p6440/cpu.c
deleted file mode 100644 (file)
index ec592e8..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/cpu.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#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 <linux/sched.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <asm/proc-fns.h>
-
-#include <mach/hardware.h>
-#include <mach/map.h>
-#include <asm/irq.h>
-
-#include <plat/regs-serial.h>
-#include <mach/regs-clock.h>
-
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/clock.h>
-#include <plat/s5p6440.h>
-#include <plat/adc-core.h>
-
-static void s5p6440_idle(void)
-{
-       unsigned long val;
-
-       if (!need_resched()) {
-               val = __raw_readl(S5P_PWR_CFG);
-               val &= ~(0x3<<5);
-               val |= (0x1<<5);
-               __raw_writel(val, S5P_PWR_CFG);
-
-               cpu_do_idle();
-       }
-       local_irq_enable();
-}
-
-/* s5p6440_map_io
- *
- * register the standard cpu IO areas
-*/
-
-void __init s5p6440_map_io(void)
-{
-       /* initialize any device information early */
-       s3c_adc_setname("s3c64xx-adc");
-}
-
-void __init s5p6440_init_clocks(int xtal)
-{
-       printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
-
-       s3c24xx_register_baseclocks(xtal);
-       s5p_register_clocks(xtal);
-       s5p6440_register_clocks();
-       s5p6440_setup_clocks();
-}
-
-void __init s5p6440_init_irq(void)
-{
-       /* S5P6440 supports only 2 VIC */
-       u32 vic[2];
-
-       /*
-        * VIC0 is missing IRQ_VIC0[3, 4, 8, 10, (12-22)]
-        * VIC1 is missing IRQ VIC1[1, 3, 4, 10, 11, 12, 14, 15, 22]
-        */
-       vic[0] = 0xff800ae7;
-       vic[1] = 0xffbf23e5;
-
-       s5p_init_irq(vic, ARRAY_SIZE(vic));
-}
-
-struct sysdev_class s5p6440_sysclass = {
-       .name   = "s5p6440-core",
-};
-
-static struct sys_device s5p6440_sysdev = {
-       .cls    = &s5p6440_sysclass,
-};
-
-static int __init s5p6440_core_init(void)
-{
-       return sysdev_class_register(&s5p6440_sysclass);
-}
-
-core_initcall(s5p6440_core_init);
-
-int __init s5p6440_init(void)
-{
-       printk(KERN_INFO "S5P6440: Initializing architecture\n");
-
-       /* set idle function */
-       pm_idle = s5p6440_idle;
-
-       return sysdev_register(&s5p6440_sysdev);
-}
diff --git a/arch/arm/mach-s5p6440/dev-audio.c b/arch/arm/mach-s5p6440/dev-audio.c
deleted file mode 100644 (file)
index 3ca0d2b..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/dev-audio.c
- *
- * Copyright (c) 2010 Samsung Electronics Co. Ltd
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-
-#include <plat/gpio-cfg.h>
-#include <plat/audio.h>
-
-#include <mach/map.h>
-#include <mach/dma.h>
-#include <mach/irqs.h>
-
-static int s5p6440_cfg_i2s(struct platform_device *pdev)
-{
-       /* configure GPIO for i2s port */
-       switch (pdev->id) {
-       case -1:
-               s3c_gpio_cfgpin(S5P6440_GPR(4), S3C_GPIO_SFN(5));
-               s3c_gpio_cfgpin(S5P6440_GPR(5), S3C_GPIO_SFN(5));
-               s3c_gpio_cfgpin(S5P6440_GPR(6), S3C_GPIO_SFN(5));
-               s3c_gpio_cfgpin(S5P6440_GPR(7), S3C_GPIO_SFN(5));
-               s3c_gpio_cfgpin(S5P6440_GPR(8), S3C_GPIO_SFN(5));
-               s3c_gpio_cfgpin(S5P6440_GPR(13), S3C_GPIO_SFN(5));
-               s3c_gpio_cfgpin(S5P6440_GPR(14), S3C_GPIO_SFN(5));
-               break;
-
-       default:
-               printk(KERN_ERR "Invalid Device %d\n", pdev->id);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static struct s3c_audio_pdata s3c_i2s_pdata = {
-       .cfg_gpio = s5p6440_cfg_i2s,
-};
-
-static struct resource s5p6440_iis0_resource[] = {
-       [0] = {
-               .start = S5P6440_PA_I2S,
-               .end   = S5P6440_PA_I2S + 0x100 - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = DMACH_I2S0_TX,
-               .end   = DMACH_I2S0_TX,
-               .flags = IORESOURCE_DMA,
-       },
-       [2] = {
-               .start = DMACH_I2S0_RX,
-               .end   = DMACH_I2S0_RX,
-               .flags = IORESOURCE_DMA,
-       },
-};
-
-struct platform_device s5p6440_device_iis = {
-       .name             = "s3c64xx-iis-v4",
-       .id               = -1,
-       .num_resources    = ARRAY_SIZE(s5p6440_iis0_resource),
-       .resource         = s5p6440_iis0_resource,
-       .dev = {
-               .platform_data = &s3c_i2s_pdata,
-       },
-};
-
-/* PCM Controller platform_devices */
-
-static int s5p6440_pcm_cfg_gpio(struct platform_device *pdev)
-{
-       switch (pdev->id) {
-       case 0:
-               s3c_gpio_cfgpin(S5P6440_GPR(7), S3C_GPIO_SFN(2));
-               s3c_gpio_cfgpin(S5P6440_GPR(13), S3C_GPIO_SFN(2));
-               s3c_gpio_cfgpin(S5P6440_GPR(14), S3C_GPIO_SFN(2));
-               s3c_gpio_cfgpin(S5P6440_GPR(8), S3C_GPIO_SFN(2));
-               s3c_gpio_cfgpin(S5P6440_GPR(6), S3C_GPIO_SFN(2));
-               break;
-
-       default:
-               printk(KERN_DEBUG "Invalid PCM Controller number!");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static struct s3c_audio_pdata s3c_pcm_pdata = {
-       .cfg_gpio = s5p6440_pcm_cfg_gpio,
-};
-
-static struct resource s5p6440_pcm0_resource[] = {
-       [0] = {
-               .start = S5P6440_PA_PCM,
-               .end   = S5P6440_PA_PCM + 0x100 - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = DMACH_PCM0_TX,
-               .end   = DMACH_PCM0_TX,
-               .flags = IORESOURCE_DMA,
-       },
-       [2] = {
-               .start = DMACH_PCM0_RX,
-               .end   = DMACH_PCM0_RX,
-               .flags = IORESOURCE_DMA,
-       },
-};
-
-struct platform_device s5p6440_device_pcm = {
-       .name             = "samsung-pcm",
-       .id               = 0,
-       .num_resources    = ARRAY_SIZE(s5p6440_pcm0_resource),
-       .resource         = s5p6440_pcm0_resource,
-       .dev = {
-               .platform_data = &s3c_pcm_pdata,
-       },
-};
diff --git a/arch/arm/mach-s5p6440/dev-spi.c b/arch/arm/mach-s5p6440/dev-spi.c
deleted file mode 100644 (file)
index 510af44..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/dev-spi.c
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-
-#include <mach/dma.h>
-#include <mach/map.h>
-#include <mach/irqs.h>
-#include <mach/spi-clocks.h>
-
-#include <plat/s3c64xx-spi.h>
-#include <plat/gpio-cfg.h>
-
-static char *spi_src_clks[] = {
-       [S5P6440_SPI_SRCCLK_PCLK] = "pclk",
-       [S5P6440_SPI_SRCCLK_SCLK] = "spi_epll",
-};
-
-/* SPI Controller platform_devices */
-
-/* Since we emulate multi-cs capability, we do not touch the CS.
- * The emulated CS is toggled by board specific mechanism, as it can
- * be either some immediate GPIO or some signal out of some other
- * chip in between ... or some yet another way.
- * We simply do not assume anything about CS.
- */
-static int s5p6440_spi_cfg_gpio(struct platform_device *pdev)
-{
-       switch (pdev->id) {
-       case 0:
-               s3c_gpio_cfgpin(S5P6440_GPC(0), S3C_GPIO_SFN(2));
-               s3c_gpio_cfgpin(S5P6440_GPC(1), S3C_GPIO_SFN(2));
-               s3c_gpio_cfgpin(S5P6440_GPC(2), S3C_GPIO_SFN(2));
-               s3c_gpio_setpull(S5P6440_GPC(0), S3C_GPIO_PULL_UP);
-               s3c_gpio_setpull(S5P6440_GPC(1), S3C_GPIO_PULL_UP);
-               s3c_gpio_setpull(S5P6440_GPC(2), S3C_GPIO_PULL_UP);
-               break;
-
-       case 1:
-               s3c_gpio_cfgpin(S5P6440_GPC(4), S3C_GPIO_SFN(2));
-               s3c_gpio_cfgpin(S5P6440_GPC(5), S3C_GPIO_SFN(2));
-               s3c_gpio_cfgpin(S5P6440_GPC(6), S3C_GPIO_SFN(2));
-               s3c_gpio_setpull(S5P6440_GPC(4), S3C_GPIO_PULL_UP);
-               s3c_gpio_setpull(S5P6440_GPC(5), S3C_GPIO_PULL_UP);
-               s3c_gpio_setpull(S5P6440_GPC(6), S3C_GPIO_PULL_UP);
-               break;
-
-       default:
-               dev_err(&pdev->dev, "Invalid SPI Controller number!");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static struct resource s5p6440_spi0_resource[] = {
-       [0] = {
-               .start = S5P6440_PA_SPI0,
-               .end   = S5P6440_PA_SPI0 + 0x100 - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = DMACH_SPI0_TX,
-               .end   = DMACH_SPI0_TX,
-               .flags = IORESOURCE_DMA,
-       },
-       [2] = {
-               .start = DMACH_SPI0_RX,
-               .end   = DMACH_SPI0_RX,
-               .flags = IORESOURCE_DMA,
-       },
-       [3] = {
-               .start = IRQ_SPI0,
-               .end   = IRQ_SPI0,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-static struct s3c64xx_spi_info s5p6440_spi0_pdata = {
-       .cfg_gpio = s5p6440_spi_cfg_gpio,
-       .fifo_lvl_mask = 0x1ff,
-       .rx_lvl_offset = 15,
-};
-
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-struct platform_device s5p6440_device_spi0 = {
-       .name             = "s3c64xx-spi",
-       .id               = 0,
-       .num_resources    = ARRAY_SIZE(s5p6440_spi0_resource),
-       .resource         = s5p6440_spi0_resource,
-       .dev = {
-               .dma_mask               = &spi_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-               .platform_data = &s5p6440_spi0_pdata,
-       },
-};
-
-static struct resource s5p6440_spi1_resource[] = {
-       [0] = {
-               .start = S5P6440_PA_SPI1,
-               .end   = S5P6440_PA_SPI1 + 0x100 - 1,
-               .flags = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start = DMACH_SPI1_TX,
-               .end   = DMACH_SPI1_TX,
-               .flags = IORESOURCE_DMA,
-       },
-       [2] = {
-               .start = DMACH_SPI1_RX,
-               .end   = DMACH_SPI1_RX,
-               .flags = IORESOURCE_DMA,
-       },
-       [3] = {
-               .start = IRQ_SPI1,
-               .end   = IRQ_SPI1,
-               .flags = IORESOURCE_IRQ,
-       },
-};
-
-static struct s3c64xx_spi_info s5p6440_spi1_pdata = {
-       .cfg_gpio = s5p6440_spi_cfg_gpio,
-       .fifo_lvl_mask = 0x7f,
-       .rx_lvl_offset = 15,
-};
-
-struct platform_device s5p6440_device_spi1 = {
-       .name             = "s3c64xx-spi",
-       .id               = 1,
-       .num_resources    = ARRAY_SIZE(s5p6440_spi1_resource),
-       .resource         = s5p6440_spi1_resource,
-       .dev = {
-               .dma_mask               = &spi_dmamask,
-               .coherent_dma_mask      = DMA_BIT_MASK(32),
-               .platform_data = &s5p6440_spi1_pdata,
-       },
-};
-
-void __init s5p6440_spi_set_info(int cntrlr, int src_clk_nr, int num_cs)
-{
-       struct s3c64xx_spi_info *pd;
-
-       /* Reject invalid configuration */
-       if (!num_cs || src_clk_nr < 0
-                       || src_clk_nr > S5P6440_SPI_SRCCLK_SCLK) {
-               printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__);
-               return;
-       }
-
-       switch (cntrlr) {
-       case 0:
-               pd = &s5p6440_spi0_pdata;
-               break;
-       case 1:
-               pd = &s5p6440_spi1_pdata;
-               break;
-       default:
-               printk(KERN_ERR "%s: Invalid SPI controller(%d)\n",
-                                                       __func__, cntrlr);
-               return;
-       }
-
-       pd->num_cs = num_cs;
-       pd->src_clk_nr = src_clk_nr;
-       pd->src_clk_name = spi_src_clks[src_clk_nr];
-}
diff --git a/arch/arm/mach-s5p6440/include/mach/debug-macro.S b/arch/arm/mach-s5p6440/include/mach/debug-macro.S
deleted file mode 100644 (file)
index 1347d7f..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/debug-macro.S
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-/* pull in the relevant register and map files. */
-
-#include <mach/map.h>
-#include <plat/regs-serial.h>
-
-       /* note, for the boot process to work we have to keep the UART
-        * virtual address aligned to an 1MiB boundary for the L1
-        * mapping the head code makes. We keep the UART virtual address
-        * aligned and add in the offset when we load the value here.
-        */
-
-       .macro addruart, rx, rtmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1
-               ldreq   \rx, = S3C_PA_UART
-               ldrne   \rx, = S3C_VA_UART
-#if CONFIG_DEBUG_S3C_UART != 0
-               add     \rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
-#endif
-       .endm
-
-/* include the reset of the code which will do the work, we're only
- * compiling for a single cpu processor type so the default of s3c2440
- * will be fine with us.
- */
-
-#include <plat/debug-macro.S>
diff --git a/arch/arm/mach-s5p6440/include/mach/gpio.h b/arch/arm/mach-s5p6440/include/mach/gpio.h
deleted file mode 100644 (file)
index 2178383..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/gpio.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6440 - GPIO lib 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.
-*/
-
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H __FILE__
-
-#define gpio_get_value __gpio_get_value
-#define gpio_set_value __gpio_set_value
-#define gpio_cansleep  __gpio_cansleep
-#define gpio_to_irq    __gpio_to_irq
-
-/* GPIO bank sizes */
-#define S5P6440_GPIO_A_NR      (6)
-#define S5P6440_GPIO_B_NR      (7)
-#define S5P6440_GPIO_C_NR      (8)
-#define S5P6440_GPIO_F_NR      (2)
-#define S5P6440_GPIO_G_NR      (7)
-#define S5P6440_GPIO_H_NR      (10)
-#define S5P6440_GPIO_I_NR      (16)
-#define S5P6440_GPIO_J_NR      (12)
-#define S5P6440_GPIO_N_NR      (16)
-#define S5P6440_GPIO_P_NR      (8)
-#define S5P6440_GPIO_R_NR      (15)
-
-/* GPIO bank numbers */
-
-/* CONFIG_S3C_GPIO_SPACE allows the user to select extra
- * space for debugging purposes so that any accidental
- * change from one gpio bank to another can be caught.
-*/
-#define S5P6440_GPIO_NEXT(__gpio) \
-       ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
-
-enum s5p_gpio_number {
-       S5P6440_GPIO_A_START = 0,
-       S5P6440_GPIO_B_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_A),
-       S5P6440_GPIO_C_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_B),
-       S5P6440_GPIO_F_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_C),
-       S5P6440_GPIO_G_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_F),
-       S5P6440_GPIO_H_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_G),
-       S5P6440_GPIO_I_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_H),
-       S5P6440_GPIO_J_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_I),
-       S5P6440_GPIO_N_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_J),
-       S5P6440_GPIO_P_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_N),
-       S5P6440_GPIO_R_START = S5P6440_GPIO_NEXT(S5P6440_GPIO_P),
-};
-
-/* S5P6440 GPIO number definitions. */
-#define S5P6440_GPA(_nr)       (S5P6440_GPIO_A_START + (_nr))
-#define S5P6440_GPB(_nr)       (S5P6440_GPIO_B_START + (_nr))
-#define S5P6440_GPC(_nr)       (S5P6440_GPIO_C_START + (_nr))
-#define S5P6440_GPF(_nr)       (S5P6440_GPIO_F_START + (_nr))
-#define S5P6440_GPG(_nr)       (S5P6440_GPIO_G_START + (_nr))
-#define S5P6440_GPH(_nr)       (S5P6440_GPIO_H_START + (_nr))
-#define S5P6440_GPI(_nr)       (S5P6440_GPIO_I_START + (_nr))
-#define S5P6440_GPJ(_nr)       (S5P6440_GPIO_J_START + (_nr))
-#define S5P6440_GPN(_nr)       (S5P6440_GPIO_N_START + (_nr))
-#define S5P6440_GPP(_nr)       (S5P6440_GPIO_P_START + (_nr))
-#define S5P6440_GPR(_nr)       (S5P6440_GPIO_R_START + (_nr))
-
-/* the end of the S5P6440 specific gpios */
-#define S5P6440_GPIO_END       (S5P6440_GPR(S5P6440_GPIO_R_NR) + 1)
-#define S3C_GPIO_END           S5P6440_GPIO_END
-
-/* define the number of gpios we need to the one after the GPR() range */
-#define ARCH_NR_GPIOS          (S5P6440_GPR(S5P6440_GPIO_R_NR) +       \
-                                CONFIG_SAMSUNG_GPIO_EXTRA + 1)
-
-#include <asm-generic/gpio.h>
-
-#endif /* __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-s5p6440/include/mach/io.h b/arch/arm/mach-s5p6440/include/mach/io.h
deleted file mode 100644 (file)
index fa2d69c..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* arch/arm/mach-s5p6440/include/mach/io.h
- *
- * Copyright 2008 Simtec Electronics
- *     Ben Dooks <ben-linux@fluff.org>
- *
- * Default IO routines for S3C64XX based
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/* No current ISA/PCI bus support. */
-#define __io(a)                __typesafe_io(a)
-#define __mem_pci(a)   (a)
-
-#define IO_SPACE_LIMIT (0xFFFFFFFF)
-
-#endif
diff --git a/arch/arm/mach-s5p6440/include/mach/map.h b/arch/arm/mach-s5p6440/include/mach/map.h
deleted file mode 100644 (file)
index 6cc5cbc..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/map.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6440 - Memory map definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_MAP_H
-#define __ASM_ARCH_MAP_H __FILE__
-
-#include <plat/map-base.h>
-#include <plat/map-s5p.h>
-
-#define S5P6440_PA_CHIPID      (0xE0000000)
-#define S5P_PA_CHIPID          S5P6440_PA_CHIPID
-
-#define S5P6440_PA_SYSCON      (0xE0100000)
-#define S5P6440_PA_CLK         (S5P6440_PA_SYSCON + 0x0)
-#define S5P_PA_SYSCON          S5P6440_PA_SYSCON
-
-#define S5P6440_PA_GPIO                (0xE0308000)
-#define S5P_PA_GPIO            S5P6440_PA_GPIO
-
-#define S5P6440_PA_VIC0                (0xE4000000)
-#define S5P_PA_VIC0            S5P6440_PA_VIC0
-
-#define S5P6440_PA_PDMA                0xE9000000
-
-#define S5P6440_PA_VIC1                (0xE4100000)
-#define S5P_PA_VIC1            S5P6440_PA_VIC1
-
-#define S5P6440_PA_TIMER       (0xEA000000)
-#define S5P_PA_TIMER           S5P6440_PA_TIMER
-
-#define S5P6440_PA_RTC         (0xEA100000)
-
-#define S5P6440_PA_WDT         (0xEA200000)
-#define S5P_PA_WDT             S5P6440_PA_WDT
-
-#define S5P6440_PA_UART                (0xEC000000)
-
-#define S5P_PA_UART0           (S5P6440_PA_UART + 0x0)
-#define S5P_PA_UART1           (S5P6440_PA_UART + 0x400)
-#define S5P_PA_UART2           (S5P6440_PA_UART + 0x800)
-#define S5P_PA_UART3           (S5P6440_PA_UART + 0xC00)
-
-#define S5P_SZ_UART            SZ_256
-
-#define S5P6440_PA_IIC0                (0xEC104000)
-#define S5P6440_PA_IIC1                (0xEC20F000)
-
-#define S5P6440_PA_SPI0                0xEC400000
-#define S5P6440_PA_SPI1                0xEC500000
-
-#define S5P6440_PA_HSOTG       (0xED100000)
-
-#define S5P6440_PA_HSMMC0      (0xED800000)
-#define S5P6440_PA_HSMMC1      (0xED900000)
-#define S5P6440_PA_HSMMC2      (0xEDA00000)
-
-#define S5P6440_PA_SDRAM       (0x20000000)
-#define S5P_PA_SDRAM           S5P6440_PA_SDRAM
-
-/* I2S */
-#define S5P6440_PA_I2S         0xF2000000
-
-/* PCM */
-#define S5P6440_PA_PCM         0xF2100000
-
-#define S5P6440_PA_ADC         (0xF3000000)
-
-/* compatibiltiy defines. */
-#define S3C_PA_UART            S5P6440_PA_UART
-#define S3C_PA_IIC             S5P6440_PA_IIC0
-#define S3C_PA_RTC             S5P6440_PA_RTC
-#define S3C_PA_IIC1            S5P6440_PA_IIC1
-#define S3C_PA_WDT             S5P6440_PA_WDT
-
-#define SAMSUNG_PA_ADC         S5P6440_PA_ADC
-
-#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-s5p6440/include/mach/regs-clock.h b/arch/arm/mach-s5p6440/include/mach/regs-clock.h
deleted file mode 100644 (file)
index c783ecc..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/regs-clock.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6440 - Clock register definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#ifndef __ASM_ARCH_REGS_CLOCK_H
-#define __ASM_ARCH_REGS_CLOCK_H __FILE__
-
-#include <mach/map.h>
-
-#define S5P_CLKREG(x)          (S3C_VA_SYS + (x))
-
-#define S5P_APLL_LOCK          S5P_CLKREG(0x00)
-#define S5P_MPLL_LOCK          S5P_CLKREG(0x04)
-#define S5P_EPLL_LOCK          S5P_CLKREG(0x08)
-#define S5P_APLL_CON           S5P_CLKREG(0x0C)
-#define S5P_MPLL_CON           S5P_CLKREG(0x10)
-#define S5P_EPLL_CON           S5P_CLKREG(0x14)
-#define S5P_EPLL_CON_K         S5P_CLKREG(0x18)
-#define S5P_CLK_SRC0           S5P_CLKREG(0x1C)
-#define S5P_CLK_DIV0           S5P_CLKREG(0x20)
-#define S5P_CLK_DIV1           S5P_CLKREG(0x24)
-#define S5P_CLK_DIV2           S5P_CLKREG(0x28)
-#define S5P_CLK_OUT            S5P_CLKREG(0x2C)
-#define S5P_CLK_GATE_HCLK0     S5P_CLKREG(0x30)
-#define S5P_CLK_GATE_PCLK      S5P_CLKREG(0x34)
-#define S5P_CLK_GATE_SCLK0     S5P_CLKREG(0x38)
-#define S5P_CLK_GATE_MEM0      S5P_CLKREG(0x3C)
-#define S5P_CLK_DIV3           S5P_CLKREG(0x40)
-#define S5P_CLK_GATE_HCLK1     S5P_CLKREG(0x44)
-#define S5P_CLK_GATE_SCLK1     S5P_CLKREG(0x48)
-#define S5P_AHB_CON0                   S5P_CLKREG(0x100)
-#define S5P_CLK_SRC1                   S5P_CLKREG(0x10C)
-#define S5P_SWRESET            S5P_CLKREG(0x114)
-#define S5P_SYS_ID             S5P_CLKREG(0x118)
-#define S5P_SYS_OTHERS         S5P_CLKREG(0x11C)
-#define S5P_MEM_CFG_STAT       S5P_CLKREG(0x12C)
-#define S5P_PWR_CFG            S5P_CLKREG(0x804)
-#define S5P_EINT_WAKEUP_MASK   S5P_CLKREG(0x808)
-#define S5P_NORMAL_CFG         S5P_CLKREG(0x810)
-#define S5P_STOP_CFG           S5P_CLKREG(0x814)
-#define S5P_SLEEP_CFG          S5P_CLKREG(0x818)
-#define S5P_OSC_FREQ           S5P_CLKREG(0x820)
-#define S5P_OSC_STABLE         S5P_CLKREG(0x824)
-#define S5P_PWR_STABLE         S5P_CLKREG(0x828)
-#define S5P_MTC_STABLE         S5P_CLKREG(0x830)
-#define S5P_OTHERS             S5P_CLKREG(0x900)
-#define S5P_RST_STAT           S5P_CLKREG(0x904)
-#define S5P_WAKEUP_STAT                S5P_CLKREG(0x908)
-#define S5P_SLPEN              S5P_CLKREG(0x930)
-#define S5P_INFORM0            S5P_CLKREG(0xA00)
-#define S5P_INFORM1            S5P_CLKREG(0xA04)
-#define S5P_INFORM2            S5P_CLKREG(0xA08)
-#define S5P_INFORM3            S5P_CLKREG(0xA0C)
-
-/* CLKDIV0 */
-#define S5P_CLKDIV0_PCLK_MASK          (0xf << 12)
-#define S5P_CLKDIV0_PCLK_SHIFT         (12)
-#define S5P_CLKDIV0_HCLK_MASK          (0xf << 8)
-#define S5P_CLKDIV0_HCLK_SHIFT         (8)
-#define S5P_CLKDIV0_MPLL_MASK          (0x1 << 4)
-#define S5P_CLKDIV0_ARM_MASK           (0xf << 0)
-#define S5P_CLKDIV0_ARM_SHIFT          (0)
-
-/* CLKDIV3 */
-#define S5P_CLKDIV3_PCLK_LOW_MASK      (0xf << 12)
-#define S5P_CLKDIV3_PCLK_LOW_SHIFT     (12)
-#define S5P_CLKDIV3_HCLK_LOW_MASK      (0xf << 8)
-#define S5P_CLKDIV3_HCLK_LOW_SHIFT     (8)
-
-/* HCLK0 GATE Registers */
-#define S5P_CLKCON_HCLK0_USB           (1<<20)
-#define S5P_CLKCON_HCLK0_HSMMC2                (1<<19)
-#define S5P_CLKCON_HCLK0_HSMMC1                (1<<18)
-#define S5P_CLKCON_HCLK0_HSMMC0                (1<<17)
-#define S5P_CLKCON_HCLK0_POST0         (1<<5)
-
-/* HCLK1 GATE Registers */
-#define S5P_CLKCON_HCLK1_DISPCON       (1<<1)
-
-/* PCLK GATE Registers */
-#define S5P_CLKCON_PCLK_IIS2           (1<<26)
-#define S5P_CLKCON_PCLK_SPI1           (1<<22)
-#define S5P_CLKCON_PCLK_SPI0           (1<<21)
-#define S5P_CLKCON_PCLK_GPIO           (1<<18)
-#define S5P_CLKCON_PCLK_IIC0           (1<<17)
-#define S5P_CLKCON_PCLK_TSADC          (1<<12)
-#define S5P_CLKCON_PCLK_PWM            (1<<7)
-#define S5P_CLKCON_PCLK_RTC            (1<<6)
-#define S5P_CLKCON_PCLK_WDT            (1<<5)
-#define S5P_CLKCON_PCLK_UART3          (1<<4)
-#define S5P_CLKCON_PCLK_UART2          (1<<3)
-#define S5P_CLKCON_PCLK_UART1          (1<<2)
-#define S5P_CLKCON_PCLK_UART0          (1<<1)
-
-/* SCLK0 GATE Registers */
-#define S5P_CLKCON_SCLK0_MMC2_48       (1<<29)
-#define S5P_CLKCON_SCLK0_MMC1_48       (1<<28)
-#define S5P_CLKCON_SCLK0_MMC0_48       (1<<27)
-#define S5P_CLKCON_SCLK0_MMC2          (1<<26)
-#define S5P_CLKCON_SCLK0_MMC1          (1<<25)
-#define S5P_CLKCON_SCLK0_MMC0          (1<<24)
-#define S5P_CLKCON_SCLK0_SPI1_48       (1<<23)
-#define S5P_CLKCON_SCLK0_SPI0_48       (1<<22)
-#define S5P_CLKCON_SCLK0_SPI1          (1<<21)
-#define S5P_CLKCON_SCLK0_SPI0          (1<<20)
-#define S5P_CLKCON_SCLK0_UART          (1<<5)
-
-/* SCLK1 GATE Registers */
-
-/* MEM0 GATE Registers */
-#define S5P_CLKCON_MEM0_HCLK_NFCON     (1<<2)
-
-/*OTHERS Resgister */
-#define S5P_OTHERS_USB_SIG_MASK                (1<<16)
-#define S5P_OTHERS_HCLK_LOW_SEL_MPLL   (1<<6)
-
-/* Compatibility defines */
-#define ARM_CLK_DIV                    S5P_CLK_DIV0
-#define ARM_DIV_RATIO_SHIFT            0
-#define ARM_DIV_MASK                   (0xf << ARM_DIV_RATIO_SHIFT)
-
-#endif /* __ASM_ARCH_REGS_CLOCK_H */
diff --git a/arch/arm/mach-s5p6440/include/mach/spi-clocks.h b/arch/arm/mach-s5p6440/include/mach/spi-clocks.h
deleted file mode 100644 (file)
index 5fbca50..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/spi-clocks.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *     Jaswinder Singh <jassi.brar@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __S5P6440_PLAT_SPI_CLKS_H
-#define __S5P6440_PLAT_SPI_CLKS_H __FILE__
-
-#define S5P6440_SPI_SRCCLK_PCLK                0
-#define S5P6440_SPI_SRCCLK_SCLK                1
-
-#endif /* __S5P6440_PLAT_SPI_CLKS_H */
diff --git a/arch/arm/mach-s5p6440/include/mach/uncompress.h b/arch/arm/mach-s5p6440/include/mach/uncompress.h
deleted file mode 100644 (file)
index 7c1f600..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/uncompress.h
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6440 - uncompress 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.
-*/
-
-#ifndef __ASM_ARCH_UNCOMPRESS_H
-#define __ASM_ARCH_UNCOMPRESS_H
-
-#include <mach/map.h>
-#include <plat/uncompress.h>
-
-static void arch_detect_cpu(void)
-{
-       /* we do not need to do any cpu detection here at the moment. */
-}
-
-#endif /* __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-s5p6440/init.c b/arch/arm/mach-s5p6440/init.c
deleted file mode 100644 (file)
index a1f3727..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* linux/arch/arm/mach-s5p6440/init.c
- *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
- *
- * S5P6440 - Init support
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/serial_core.h>
-
-#include <plat/cpu.h>
-#include <plat/devs.h>
-#include <plat/s5p6440.h>
-#include <plat/regs-serial.h>
-
-static struct s3c24xx_uart_clksrc s5p6440_serial_clocks[] = {
-       [0] = {
-               .name           = "pclk_low",
-               .divisor        = 1,
-               .min_baud       = 0,
-               .max_baud       = 0,
-       },
-       [1] = {
-               .name           = "uclk1",
-               .divisor        = 1,
-               .min_baud       = 0,
-               .max_baud       = 0,
-       },
-};
-
-/* uart registration process */
-void __init s5p6440_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
-{
-       struct s3c2410_uartcfg *tcfg = cfg;
-       u32 ucnt;
-
-       for (ucnt = 0; ucnt < no; ucnt++, tcfg++) {
-               if (!tcfg->clocks) {
-                       tcfg->clocks = s5p6440_serial_clocks;
-                       tcfg->clocks_size = ARRAY_SIZE(s5p6440_serial_clocks);
-               }
-       }
-
-       s3c24xx_init_uartdevs("s3c6400-uart", s5p_uart_resources, cfg, no);
-}
index 70ac681af72bc7a1a9ce5434c164e5b86e1fdf55..842af86bda6def3db35fcab32bd36127f5e14aad 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-s5p6442/cpu.c
  *
  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ *             http://www.samsung.com
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -47,11 +47,31 @@ static struct map_desc s5p6442_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(S5P6442_PA_SYSTIMER),
                .length         = SZ_16K,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_GPIO,
+               .pfn            = __phys_to_pfn(S5P6442_PA_GPIO),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)VA_VIC0,
+               .pfn            = __phys_to_pfn(S5P6442_PA_VIC0),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)VA_VIC1,
+               .pfn            = __phys_to_pfn(S5P6442_PA_VIC1),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)VA_VIC2,
                .pfn            = __phys_to_pfn(S5P6442_PA_VIC2),
                .length         = SZ_16K,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_UART,
+               .pfn            = __phys_to_pfn(S3C_PA_UART),
+               .length         = SZ_512K,
+               .type           = MT_DEVICE,
        }
 };
 
@@ -63,10 +83,11 @@ static void s5p6442_idle(void)
        local_irq_enable();
 }
 
-/* s5p6442_map_io
+/*
+ * s5p6442_map_io
  *
  * register the standard cpu IO areas
-*/
+ */
 
 void __init s5p6442_map_io(void)
 {
index bb6536147ffb0bd7c55c95d8eb796401824ceeb7..e2213205d780bbdfdb0083d49747b632ebbf445b 100644 (file)
 #include <mach/map.h>
 #include <plat/regs-serial.h>
 
-       .macro addruart, rx, rtmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1
-               ldreq   \rx, = S3C_PA_UART
-               ldrne   \rx, = S3C_VA_UART
+       .macro addruart, rp, rv
+               ldr     \rp, = S3C_PA_UART
+               ldr     \rv, = S3C_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-               add     \rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
+               add     \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
+               add     \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
 #endif
        .endm
 
index 281d256faafb0d6e4e817261ac78e5b091a4078d..31fb2e68d527915080df5f9ff498c835218f972c 100644 (file)
 #define S5P_PA_SYSCON          S5P6442_PA_SYSCON
 
 #define S5P6442_PA_GPIO                (0xE0200000)
-#define S5P_PA_GPIO            S5P6442_PA_GPIO
 
 #define S5P6442_PA_VIC0                (0xE4000000)
-#define S5P_PA_VIC0            S5P6442_PA_VIC0
-
 #define S5P6442_PA_VIC1                (0xE4100000)
-#define S5P_PA_VIC1            S5P6442_PA_VIC1
-
 #define S5P6442_PA_VIC2                (0xE4200000)
-#define S5P_PA_VIC2            S5P6442_PA_VIC2
 
 #define S5P6442_PA_MDMA                0xE8000000
 #define S5P6442_PA_PDMA                0xE9000000
index 8d8d04272f852eec0bf843d94a2f14a80a5a3b79..819fd80d00afc74a34c2741409de363bd14ecde7 100644 (file)
@@ -83,8 +83,6 @@ static void __init smdk6442_machine_init(void)
 
 MACHINE_START(SMDK6442, "SMDK6442")
        /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
-       .phys_io        = S3C_PA_UART & 0xfff00000,
-       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S5P_PA_SDRAM + 0x100,
        .init_irq       = s5p6442_init_irq,
        .map_io         = smdk6442_map_io,
diff --git a/arch/arm/mach-s5p64x0/Kconfig b/arch/arm/mach-s5p64x0/Kconfig
new file mode 100644 (file)
index 0000000..fbcae93
--- /dev/null
@@ -0,0 +1,57 @@
+# arch/arm/mach-s5p64x0/Kconfig
+#
+# Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+#              http://www.samsung.com/
+#
+# Licensed under GPLv2
+
+if ARCH_S5P64X0
+
+config CPU_S5P6440
+       bool
+       select PLAT_S5P
+       select S3C_PL330_DMA
+       help
+         Enable S5P6440 CPU support
+
+config CPU_S5P6450
+       bool
+       select PLAT_S5P
+       select S3C_PL330_DMA
+       help
+         Enable S5P6450 CPU support
+
+config S5P64X0_SETUP_I2C1
+       bool
+       help
+         Common setup code for i2c bus 1.
+
+# machine support
+
+config MACH_SMDK6440
+       bool "SMDK6440"
+       select CPU_S5P6440
+       select S3C_DEV_I2C1
+       select S3C_DEV_RTC
+       select S3C_DEV_WDT
+       select S3C64XX_DEV_SPI
+       select SAMSUNG_DEV_ADC
+       select SAMSUNG_DEV_TS
+       select S5P64X0_SETUP_I2C1
+       help
+         Machine support for the Samsung SMDK6440
+
+config MACH_SMDK6450
+       bool "SMDK6450"
+       select CPU_S5P6450
+       select S3C_DEV_I2C1
+       select S3C_DEV_RTC
+       select S3C_DEV_WDT
+       select S3C64XX_DEV_SPI
+       select SAMSUNG_DEV_ADC
+       select SAMSUNG_DEV_TS
+       select S5P64X0_SETUP_I2C1
+       help
+         Machine support for the Samsung SMDK6450
+
+endif
diff --git a/arch/arm/mach-s5p64x0/Makefile b/arch/arm/mach-s5p64x0/Makefile
new file mode 100644 (file)
index 0000000..2655829
--- /dev/null
@@ -0,0 +1,30 @@
+# arch/arm/mach-s5p64x0/Makefile
+#
+# Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+#              http://www.samsung.com
+#
+# Licensed under GPLv2
+
+obj-y                          :=
+obj-m                          :=
+obj-n                          :=
+obj-                           :=
+
+# Core support for S5P64X0 system
+
+obj-$(CONFIG_ARCH_S5P64X0)     += cpu.o init.o clock.o dma.o
+obj-$(CONFIG_ARCH_S5P64X0)     += setup-i2c0.o
+obj-$(CONFIG_CPU_S5P6440)      += clock-s5p6440.o gpio.o
+obj-$(CONFIG_CPU_S5P6450)      += clock-s5p6450.o
+
+# machine support
+
+obj-$(CONFIG_MACH_SMDK6440)    += mach-smdk6440.o
+obj-$(CONFIG_MACH_SMDK6450)    += mach-smdk6450.o
+
+# device support
+
+obj-y                          += dev-audio.o
+obj-$(CONFIG_S3C64XX_DEV_SPI)  += dev-spi.o
+
+obj-$(CONFIG_S5P64X0_SETUP_I2C1)       += setup-i2c1.o
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6440.c b/arch/arm/mach-s5p64x0/clock-s5p6440.c
new file mode 100644 (file)
index 0000000..f93dcd8
--- /dev/null
@@ -0,0 +1,626 @@
+/* linux/arch/arm/mach-s5p64x0/clock-s5p6440.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P6440 - Clock 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/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/s5p64x0-clock.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/s5p6440.h>
+
+static u32 epll_div[][5] = {
+       { 36000000,     0,      48, 1, 4 },
+       { 48000000,     0,      32, 1, 3 },
+       { 60000000,     0,      40, 1, 3 },
+       { 72000000,     0,      48, 1, 3 },
+       { 84000000,     0,      28, 1, 2 },
+       { 96000000,     0,      32, 1, 2 },
+       { 32768000,     45264,  43, 1, 4 },
+       { 45158000,     6903,   30, 1, 3 },
+       { 49152000,     50332,  32, 1, 3 },
+       { 67738000,     10398,  45, 1, 3 },
+       { 73728000,     9961,   49, 1, 3 }
+};
+
+static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned int epll_con, epll_con_k;
+       unsigned int i;
+
+       if (clk->rate == rate)  /* Return if nothing changed */
+               return 0;
+
+       epll_con = __raw_readl(S5P64X0_EPLL_CON);
+       epll_con_k = __raw_readl(S5P64X0_EPLL_CON_K);
+
+       epll_con_k &= ~(PLL90XX_KDIV_MASK);
+       epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
+
+       for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+                if (epll_div[i][0] == rate) {
+                       epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
+                       epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
+                                   (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
+                                   (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(epll_div)) {
+               printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
+               return -EINVAL;
+       }
+
+       __raw_writel(epll_con, S5P64X0_EPLL_CON);
+       __raw_writel(epll_con_k, S5P64X0_EPLL_CON_K);
+
+       clk->rate = rate;
+
+       return 0;
+}
+
+static struct clk_ops s5p6440_epll_ops = {
+       .get_rate = s5p64x0_epll_get_rate,
+       .set_rate = s5p6440_epll_set_rate,
+};
+
+static struct clksrc_clk clk_hclk = {
+       .clk    = {
+               .name           = "clk_hclk",
+               .id             = -1,
+               .parent         = &clk_armclk.clk,
+       },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV0, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clk_pclk = {
+       .clk    = {
+               .name           = "clk_pclk",
+               .id             = -1,
+               .parent         = &clk_hclk.clk,
+       },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV0, .shift = 12, .size = 4 },
+};
+static struct clksrc_clk clk_hclk_low = {
+       .clk    = {
+               .name           = "clk_hclk_low",
+               .id             = -1,
+       },
+       .sources        = &clkset_hclk_low,
+       .reg_src        = { .reg = S5P64X0_SYS_OTHERS, .shift = 6, .size = 1 },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV3, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clk_pclk_low = {
+       .clk    = {
+               .name           = "clk_pclk_low",
+               .id             = -1,
+               .parent         = &clk_hclk_low.clk,
+       },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV3, .shift = 12, .size = 4 },
+};
+
+/*
+ * The following clocks will be disabled during clock initialization. It is
+ * recommended to keep the following clocks disabled until the driver requests
+ * for enabling the clock.
+ */
+static struct clk init_clocks_disable[] = {
+       {
+               .name           = "nand",
+               .id             = -1,
+               .parent         = &clk_hclk.clk,
+               .enable         = s5p64x0_mem_ctrl,
+               .ctrlbit        = (1 << 2),
+       }, {
+               .name           = "post",
+               .id             = -1,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 5)
+       }, {
+               .name           = "2d",
+               .id             = -1,
+               .parent         = &clk_hclk.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 8),
+       }, {
+               .name           = "hsmmc",
+               .id             = 0,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 17),
+       }, {
+               .name           = "hsmmc",
+               .id             = 1,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 18),
+       }, {
+               .name           = "hsmmc",
+               .id             = 2,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 19),
+       }, {
+               .name           = "otg",
+               .id             = -1,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 20)
+       }, {
+               .name           = "irom",
+               .id             = -1,
+               .parent         = &clk_hclk.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 25),
+       }, {
+               .name           = "lcd",
+               .id             = -1,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk1_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "hclk_fimgvg",
+               .id             = -1,
+               .parent         = &clk_hclk.clk,
+               .enable         = s5p64x0_hclk1_ctrl,
+               .ctrlbit        = (1 << 2),
+       }, {
+               .name           = "tsi",
+               .id             = -1,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk1_ctrl,
+               .ctrlbit        = (1 << 0),
+       }, {
+               .name           = "watchdog",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 5),
+       }, {
+               .name           = "rtc",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 6),
+       }, {
+               .name           = "timers",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 7),
+       }, {
+               .name           = "pcm",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 8),
+       }, {
+               .name           = "adc",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 12),
+       }, {
+               .name           = "i2c",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 17),
+       }, {
+               .name           = "spi",
+               .id             = 0,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 21),
+       }, {
+               .name           = "spi",
+               .id             = 1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 22),
+       }, {
+               .name           = "gps",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 25),
+       }, {
+               .name           = "i2s_v40",
+               .id             = 0,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 26),
+       }, {
+               .name           = "dsim",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 28),
+       }, {
+               .name           = "etm",
+               .id             = -1,
+               .parent         = &clk_pclk.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 29),
+       }, {
+               .name           = "dmc0",
+               .id             = -1,
+               .parent         = &clk_pclk.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 30),
+       }, {
+               .name           = "pclk_fimgvg",
+               .id             = -1,
+               .parent         = &clk_pclk.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 31),
+       }, {
+               .name           = "sclk_spi_48",
+               .id             = 0,
+               .parent         = &clk_48m,
+               .enable         = s5p64x0_sclk_ctrl,
+               .ctrlbit        = (1 << 22),
+       }, {
+               .name           = "sclk_spi_48",
+               .id             = 1,
+               .parent         = &clk_48m,
+               .enable         = s5p64x0_sclk_ctrl,
+               .ctrlbit        = (1 << 23),
+       }, {
+               .name           = "mmc_48m",
+               .id             = 0,
+               .parent         = &clk_48m,
+               .enable         = s5p64x0_sclk_ctrl,
+               .ctrlbit        = (1 << 27),
+       }, {
+               .name           = "mmc_48m",
+               .id             = 1,
+               .parent         = &clk_48m,
+               .enable         = s5p64x0_sclk_ctrl,
+               .ctrlbit        = (1 << 28),
+       }, {
+               .name           = "mmc_48m",
+               .id             = 2,
+               .parent         = &clk_48m,
+               .enable         = s5p64x0_sclk_ctrl,
+               .ctrlbit        = (1 << 29),
+       },
+};
+
+/*
+ * The following clocks will be enabled during clock initialization.
+ */
+static struct clk init_clocks[] = {
+       {
+               .name           = "intc",
+               .id             = -1,
+               .parent         = &clk_hclk.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "mem",
+               .id             = -1,
+               .parent         = &clk_hclk.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 21),
+       }, {
+               .name           = "dma",
+               .id             = -1,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 12),
+       }, {
+               .name           = "uart",
+               .id             = 0,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "uart",
+               .id             = 1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 2),
+       }, {
+               .name           = "uart",
+               .id             = 2,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 3),
+       }, {
+               .name           = "uart",
+               .id             = 3,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 4),
+       }, {
+               .name           = "gpio",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 18),
+       },
+};
+
+static struct clk clk_iis_cd_v40 = {
+       .name           = "iis_cdclk_v40",
+       .id             = -1,
+};
+
+static struct clk clk_pcm_cd = {
+       .name           = "pcm_cdclk",
+       .id             = -1,
+};
+
+static struct clk *clkset_group1_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll.clk,
+       &clk_fin_epll,
+};
+
+static struct clksrc_sources clkset_group1 = {
+       .sources        = clkset_group1_list,
+       .nr_sources     = ARRAY_SIZE(clkset_group1_list),
+};
+
+static struct clk *clkset_uart_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll.clk,
+};
+
+static struct clksrc_sources clkset_uart = {
+       .sources        = clkset_uart_list,
+       .nr_sources     = ARRAY_SIZE(clkset_uart_list),
+};
+
+static struct clk *clkset_audio_list[] = {
+       &clk_mout_epll.clk,
+       &clk_dout_mpll.clk,
+       &clk_fin_epll,
+       &clk_iis_cd_v40,
+       &clk_pcm_cd,
+};
+
+static struct clksrc_sources clkset_audio = {
+       .sources        = clkset_audio_list,
+       .nr_sources     = ARRAY_SIZE(clkset_audio_list),
+};
+
+static struct clksrc_clk clksrcs[] = {
+       {
+               .clk    = {
+                       .name           = "mmc_bus",
+                       .id             = 0,
+                       .ctrlbit        = (1 << 24),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group1,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 18, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "mmc_bus",
+                       .id             = 1,
+                       .ctrlbit        = (1 << 25),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group1,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 20, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 4, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "mmc_bus",
+                       .id             = 2,
+                       .ctrlbit        = (1 << 26),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group1,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 22, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 8, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "uclk1",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 5),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_uart,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 13, .size = 1 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 16, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_spi",
+                       .id             = 0,
+                       .ctrlbit        = (1 << 20),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group1,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 14, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_spi",
+                       .id             = 1,
+                       .ctrlbit        = (1 << 21),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group1,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 16, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 4, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_post",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 10),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group1,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 26, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 12, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_dispcon",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 1),
+                       .enable         = s5p64x0_sclk1_ctrl,
+               },
+               .sources = &clkset_group1,
+               .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 4, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_fimgvg",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 2),
+                       .enable         = s5p64x0_sclk1_ctrl,
+               },
+               .sources = &clkset_group1,
+               .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 8, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 4, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_audio2",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 11),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_audio,
+               .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 0, .size = 3 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 24, .size = 4 },
+       },
+};
+
+/* Clock initialization code */
+static struct clksrc_clk *sysclks[] = {
+       &clk_mout_apll,
+       &clk_mout_epll,
+       &clk_mout_mpll,
+       &clk_dout_mpll,
+       &clk_armclk,
+       &clk_hclk,
+       &clk_pclk,
+       &clk_hclk_low,
+       &clk_pclk_low,
+};
+
+void __init_or_cpufreq s5p6440_setup_clocks(void)
+{
+       struct clk *xtal_clk;
+
+       unsigned long xtal;
+       unsigned long fclk;
+       unsigned long hclk;
+       unsigned long hclk_low;
+       unsigned long pclk;
+       unsigned long pclk_low;
+
+       unsigned long apll;
+       unsigned long mpll;
+       unsigned long epll;
+       unsigned int ptr;
+
+       /* Set S5P6440 functions for clk_fout_epll */
+
+       clk_fout_epll.enable = s5p64x0_epll_enable;
+       clk_fout_epll.ops = &s5p6440_epll_ops;
+
+       clk_48m.enable = s5p64x0_clk48m_ctrl;
+
+       xtal_clk = clk_get(NULL, "ext_xtal");
+       BUG_ON(IS_ERR(xtal_clk));
+
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
+
+       apll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_APLL_CON), pll_4502);
+       mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_MPLL_CON), pll_4502);
+       epll = s5p_get_pll90xx(xtal, __raw_readl(S5P64X0_EPLL_CON),
+                               __raw_readl(S5P64X0_EPLL_CON_K));
+
+       clk_fout_apll.rate = apll;
+       clk_fout_mpll.rate = mpll;
+       clk_fout_epll.rate = epll;
+
+       printk(KERN_INFO "S5P6440: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
+                       " E=%ld.%ldMHz\n",
+                       print_mhz(apll), print_mhz(mpll), print_mhz(epll));
+
+       fclk = clk_get_rate(&clk_armclk.clk);
+       hclk = clk_get_rate(&clk_hclk.clk);
+       pclk = clk_get_rate(&clk_pclk.clk);
+       hclk_low = clk_get_rate(&clk_hclk_low.clk);
+       pclk_low = clk_get_rate(&clk_pclk_low.clk);
+
+       printk(KERN_INFO "S5P6440: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
+                       " PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
+                       print_mhz(hclk), print_mhz(hclk_low),
+                       print_mhz(pclk), print_mhz(pclk_low));
+
+       clk_f.rate = fclk;
+       clk_h.rate = hclk;
+       clk_p.rate = pclk;
+
+       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+               s3c_set_clksrc(&clksrcs[ptr], true);
+}
+
+static struct clk *clks[] __initdata = {
+       &clk_ext,
+       &clk_iis_cd_v40,
+       &clk_pcm_cd,
+};
+
+void __init s5p6440_register_clocks(void)
+{
+       struct clk *clkp;
+       int ret;
+       int ptr;
+
+       s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
+
+       for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
+               s3c_register_clksrc(sysclks[ptr], 1);
+
+       s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
+       s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
+
+       clkp = init_clocks_disable;
+       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+               (clkp->enable)(clkp, 0);
+       }
+
+       s3c_pwmclk_init();
+}
diff --git a/arch/arm/mach-s5p64x0/clock-s5p6450.c b/arch/arm/mach-s5p64x0/clock-s5p6450.c
new file mode 100644 (file)
index 0000000..f9afb05
--- /dev/null
@@ -0,0 +1,655 @@
+/* linux/arch/arm/mach-s5p64x0/clock-s5p6450.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P6450 - Clock 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/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/s5p64x0-clock.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/s5p6450.h>
+
+static struct clksrc_clk clk_mout_dpll = {
+       .clk    = {
+               .name           = "mout_dpll",
+               .id             = -1,
+       },
+       .sources        = &clk_src_dpll,
+       .reg_src        = { .reg = S5P64X0_CLK_SRC0, .shift = 5, .size = 1 },
+};
+
+static u32 epll_div[][5] = {
+       { 133000000,    27307,  55, 2, 2 },
+       { 100000000,    43691,  41, 2, 2 },
+       { 480000000,    0,      80, 2, 0 },
+};
+
+static int s5p6450_epll_set_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned int epll_con, epll_con_k;
+       unsigned int i;
+
+       if (clk->rate == rate)  /* Return if nothing changed */
+               return 0;
+
+       epll_con = __raw_readl(S5P64X0_EPLL_CON);
+       epll_con_k = __raw_readl(S5P64X0_EPLL_CON_K);
+
+       epll_con_k &= ~(PLL90XX_KDIV_MASK);
+       epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK);
+
+       for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
+                if (epll_div[i][0] == rate) {
+                       epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT);
+                       epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) |
+                                   (epll_div[i][3] << PLL90XX_PDIV_SHIFT) |
+                                   (epll_div[i][4] << PLL90XX_SDIV_SHIFT);
+                       break;
+               }
+       }
+
+       if (i == ARRAY_SIZE(epll_div)) {
+               printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__);
+               return -EINVAL;
+       }
+
+       __raw_writel(epll_con, S5P64X0_EPLL_CON);
+       __raw_writel(epll_con_k, S5P64X0_EPLL_CON_K);
+
+       clk->rate = rate;
+
+       return 0;
+}
+
+static struct clk_ops s5p6450_epll_ops = {
+       .get_rate = s5p64x0_epll_get_rate,
+       .set_rate = s5p6450_epll_set_rate,
+};
+
+static struct clksrc_clk clk_dout_epll = {
+       .clk    = {
+               .name           = "dout_epll",
+               .id             = -1,
+               .parent         = &clk_mout_epll.clk,
+       },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV1, .shift = 24, .size = 4 },
+};
+
+static struct clksrc_clk clk_mout_hclk_sel = {
+       .clk    = {
+               .name           = "mout_hclk_sel",
+               .id             = -1,
+       },
+       .sources        = &clkset_hclk_low,
+       .reg_src        = { .reg = S5P64X0_OTHERS, .shift = 15, .size = 1 },
+};
+
+static struct clk *clkset_hclk_list[] = {
+       &clk_mout_hclk_sel.clk,
+       &clk_armclk.clk,
+};
+
+static struct clksrc_sources clkset_hclk = {
+       .sources        = clkset_hclk_list,
+       .nr_sources     = ARRAY_SIZE(clkset_hclk_list),
+};
+
+static struct clksrc_clk clk_hclk = {
+       .clk    = {
+               .name           = "clk_hclk",
+               .id             = -1,
+       },
+       .sources        = &clkset_hclk,
+       .reg_src        = { .reg = S5P64X0_OTHERS, .shift = 14, .size = 1 },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV0, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clk_pclk = {
+       .clk    = {
+               .name           = "clk_pclk",
+               .id             = -1,
+               .parent         = &clk_hclk.clk,
+       },
+       .reg_div = { .reg = S5P64X0_CLK_DIV0, .shift = 12, .size = 4 },
+};
+static struct clksrc_clk clk_dout_pwm_ratio0 = {
+       .clk    = {
+               .name           = "clk_dout_pwm_ratio0",
+               .id             = -1,
+               .parent         = &clk_mout_hclk_sel.clk,
+       },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV3, .shift = 16, .size = 4 },
+};
+
+static struct clksrc_clk clk_pclk_to_wdt_pwm = {
+       .clk    = {
+               .name           = "clk_pclk_to_wdt_pwm",
+               .id             = -1,
+               .parent         = &clk_dout_pwm_ratio0.clk,
+       },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV3, .shift = 20, .size = 4 },
+};
+
+static struct clksrc_clk clk_hclk_low = {
+       .clk    = {
+               .name           = "clk_hclk_low",
+               .id             = -1,
+       },
+       .sources        = &clkset_hclk_low,
+       .reg_src        = { .reg = S5P64X0_OTHERS, .shift = 6, .size = 1 },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV3, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clk_pclk_low = {
+       .clk    = {
+               .name           = "clk_pclk_low",
+               .id             = -1,
+               .parent         = &clk_hclk_low.clk,
+       },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV3, .shift = 12, .size = 4 },
+};
+
+/*
+ * The following clocks will be disabled during clock initialization. It is
+ * recommended to keep the following clocks disabled until the driver requests
+ * for enabling the clock.
+ */
+static struct clk init_clocks_disable[] = {
+       {
+               .name           = "usbhost",
+               .id             = -1,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 3),
+       }, {
+               .name           = "hsmmc",
+               .id             = 0,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 17),
+       }, {
+               .name           = "hsmmc",
+               .id             = 1,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 18),
+       }, {
+               .name           = "hsmmc",
+               .id             = 2,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 19),
+       }, {
+               .name           = "usbotg",
+               .id             = -1,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 20),
+       }, {
+               .name           = "lcd",
+               .id             = -1,
+               .parent         = &clk_h,
+               .enable         = s5p64x0_hclk1_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "watchdog",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 5),
+       }, {
+               .name           = "adc",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 12),
+       }, {
+               .name           = "i2c",
+               .id             = 0,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 17),
+       }, {
+               .name           = "spi",
+               .id             = 0,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 21),
+       }, {
+               .name           = "spi",
+               .id             = 1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 22),
+       }, {
+               .name           = "iis",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 26),
+       }, {
+               .name           = "i2c",
+               .id             = 1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 27),
+       }, {
+               .name           = "dmc0",
+               .id             = -1,
+               .parent         = &clk_pclk.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 30),
+       }
+};
+
+/*
+ * The following clocks will be enabled during clock initialization.
+ */
+static struct clk init_clocks[] = {
+       {
+               .name           = "intc",
+               .id             = -1,
+               .parent         = &clk_hclk.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "mem",
+               .id             = -1,
+               .parent         = &clk_hclk.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 21),
+       }, {
+               .name           = "dma",
+               .id             = -1,
+               .parent         = &clk_hclk_low.clk,
+               .enable         = s5p64x0_hclk0_ctrl,
+               .ctrlbit        = (1 << 12),
+       }, {
+               .name           = "uart",
+               .id             = 0,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 1),
+       }, {
+               .name           = "uart",
+               .id             = 1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 2),
+       }, {
+               .name           = "uart",
+               .id             = 2,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 3),
+       }, {
+               .name           = "uart",
+               .id             = 3,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 4),
+       }, {
+               .name           = "timers",
+               .id             = -1,
+               .parent         = &clk_pclk_to_wdt_pwm.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 7),
+       }, {
+               .name           = "gpio",
+               .id             = -1,
+               .parent         = &clk_pclk_low.clk,
+               .enable         = s5p64x0_pclk_ctrl,
+               .ctrlbit        = (1 << 18),
+       },
+};
+
+static struct clk *clkset_uart_list[] = {
+       &clk_dout_epll.clk,
+       &clk_dout_mpll.clk,
+};
+
+static struct clksrc_sources clkset_uart = {
+       .sources        = clkset_uart_list,
+       .nr_sources     = ARRAY_SIZE(clkset_uart_list),
+};
+
+static struct clk *clkset_mali_list[] = {
+       &clk_mout_epll.clk,
+       &clk_mout_apll.clk,
+       &clk_mout_mpll.clk,
+};
+
+static struct clksrc_sources clkset_mali = {
+       .sources        = clkset_mali_list,
+       .nr_sources     = ARRAY_SIZE(clkset_mali_list),
+};
+
+static struct clk *clkset_group2_list[] = {
+       &clk_dout_epll.clk,
+       &clk_dout_mpll.clk,
+       &clk_ext_xtal_mux,
+};
+
+static struct clksrc_sources clkset_group2 = {
+       .sources        = clkset_group2_list,
+       .nr_sources     = ARRAY_SIZE(clkset_group2_list),
+};
+
+static struct clk *clkset_dispcon_list[] = {
+       &clk_dout_epll.clk,
+       &clk_dout_mpll.clk,
+       &clk_ext_xtal_mux,
+       &clk_mout_dpll.clk,
+};
+
+static struct clksrc_sources clkset_dispcon = {
+       .sources        = clkset_dispcon_list,
+       .nr_sources     = ARRAY_SIZE(clkset_dispcon_list),
+};
+
+static struct clk *clkset_hsmmc44_list[] = {
+       &clk_dout_epll.clk,
+       &clk_dout_mpll.clk,
+       &clk_ext_xtal_mux,
+       &s5p_clk_27m,
+       &clk_48m,
+};
+
+static struct clksrc_sources clkset_hsmmc44 = {
+       .sources        = clkset_hsmmc44_list,
+       .nr_sources     = ARRAY_SIZE(clkset_hsmmc44_list),
+};
+
+static struct clk *clkset_sclk_audio0_list[] = {
+       [0] = &clk_dout_epll.clk,
+       [1] = &clk_dout_mpll.clk,
+       [2] = &clk_ext_xtal_mux,
+       [3] = NULL,
+       [4] = NULL,
+};
+
+static struct clksrc_sources clkset_sclk_audio0 = {
+       .sources        = clkset_sclk_audio0_list,
+       .nr_sources     = ARRAY_SIZE(clkset_sclk_audio0_list),
+};
+
+static struct clksrc_clk clk_sclk_audio0 = {
+       .clk            = {
+               .name           = "audio-bus",
+               .id             = -1,
+               .enable         = s5p64x0_sclk_ctrl,
+               .ctrlbit        = (1 << 8),
+               .parent         = &clk_dout_epll.clk,
+       },
+       .sources        = &clkset_sclk_audio0,
+       .reg_src        = { .reg = S5P64X0_CLK_SRC1, .shift = 10, .size = 3 },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV2, .shift = 8, .size = 4 },
+};
+
+static struct clksrc_clk clksrcs[] = {
+       {
+               .clk    = {
+                       .name           = "sclk_mmc",
+                       .id             = 0,
+                       .ctrlbit        = (1 << 24),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group2,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 18, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_mmc",
+                       .id             = 1,
+                       .ctrlbit        = (1 << 25),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group2,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 20, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 4, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_mmc",
+                       .id             = 2,
+                       .ctrlbit        = (1 << 26),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group2,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 22, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 8, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "uclk1",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 5),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_uart,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 13, .size = 1 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 16, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_spi",
+                       .id             = 0,
+                       .ctrlbit        = (1 << 20),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group2,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 14, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_spi",
+                       .id             = 1,
+                       .ctrlbit        = (1 << 21),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group2,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 16, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 4, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_fimc",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 10),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group2,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 26, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 12, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "aclk_mali",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 2),
+                       .enable         = s5p64x0_sclk1_ctrl,
+               },
+               .sources = &clkset_mali,
+               .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 8, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 4, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_2d",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 12),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_mali,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 30, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV2, .shift = 20, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_usi",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 7),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group2,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 10, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 16, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_camif",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 6),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_group2,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 28, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 20, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_dispcon",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 1),
+                       .enable         = s5p64x0_sclk1_ctrl,
+               },
+               .sources = &clkset_dispcon,
+               .reg_src = { .reg = S5P64X0_CLK_SRC1, .shift = 4, .size = 2 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV3, .shift = 0, .size = 4 },
+       }, {
+               .clk    = {
+                       .name           = "sclk_hsmmc44",
+                       .id             = -1,
+                       .ctrlbit        = (1 << 30),
+                       .enable         = s5p64x0_sclk_ctrl,
+               },
+               .sources = &clkset_hsmmc44,
+               .reg_src = { .reg = S5P64X0_CLK_SRC0, .shift = 6, .size = 3 },
+               .reg_div = { .reg = S5P64X0_CLK_DIV1, .shift = 28, .size = 4 },
+       },
+};
+
+/* Clock initialization code */
+static struct clksrc_clk *sysclks[] = {
+       &clk_mout_apll,
+       &clk_mout_epll,
+       &clk_dout_epll,
+       &clk_mout_mpll,
+       &clk_dout_mpll,
+       &clk_armclk,
+       &clk_mout_hclk_sel,
+       &clk_dout_pwm_ratio0,
+       &clk_pclk_to_wdt_pwm,
+       &clk_hclk,
+       &clk_pclk,
+       &clk_hclk_low,
+       &clk_pclk_low,
+       &clk_sclk_audio0,
+};
+
+void __init_or_cpufreq s5p6450_setup_clocks(void)
+{
+       struct clk *xtal_clk;
+
+       unsigned long xtal;
+       unsigned long fclk;
+       unsigned long hclk;
+       unsigned long hclk_low;
+       unsigned long pclk;
+       unsigned long pclk_low;
+
+       unsigned long apll;
+       unsigned long mpll;
+       unsigned long epll;
+       unsigned long dpll;
+       unsigned int ptr;
+
+       /* Set S5P6450 functions for clk_fout_epll */
+
+       clk_fout_epll.enable = s5p64x0_epll_enable;
+       clk_fout_epll.ops = &s5p6450_epll_ops;
+
+       clk_48m.enable = s5p64x0_clk48m_ctrl;
+
+       xtal_clk = clk_get(NULL, "ext_xtal");
+       BUG_ON(IS_ERR(xtal_clk));
+
+       xtal = clk_get_rate(xtal_clk);
+       clk_put(xtal_clk);
+
+       apll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_APLL_CON), pll_4502);
+       mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P64X0_MPLL_CON), pll_4502);
+       epll = s5p_get_pll90xx(xtal, __raw_readl(S5P64X0_EPLL_CON),
+                               __raw_readl(S5P64X0_EPLL_CON_K));
+       dpll = s5p_get_pll46xx(xtal, __raw_readl(S5P6450_DPLL_CON),
+                               __raw_readl(S5P6450_DPLL_CON_K), pll_4650c);
+
+       clk_fout_apll.rate = apll;
+       clk_fout_mpll.rate = mpll;
+       clk_fout_epll.rate = epll;
+       clk_fout_dpll.rate = dpll;
+
+       printk(KERN_INFO "S5P6450: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \
+                       " E=%ld.%ldMHz, D=%ld.%ldMHz\n",
+                       print_mhz(apll), print_mhz(mpll), print_mhz(epll),
+                       print_mhz(dpll));
+
+       fclk = clk_get_rate(&clk_armclk.clk);
+       hclk = clk_get_rate(&clk_hclk.clk);
+       pclk = clk_get_rate(&clk_pclk.clk);
+       hclk_low = clk_get_rate(&clk_hclk_low.clk);
+       pclk_low = clk_get_rate(&clk_pclk_low.clk);
+
+       printk(KERN_INFO "S5P6450: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \
+                       " PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n",
+                       print_mhz(hclk), print_mhz(hclk_low),
+                       print_mhz(pclk), print_mhz(pclk_low));
+
+       clk_f.rate = fclk;
+       clk_h.rate = hclk;
+       clk_p.rate = pclk;
+
+       for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
+               s3c_set_clksrc(&clksrcs[ptr], true);
+}
+
+void __init s5p6450_register_clocks(void)
+{
+       struct clk *clkp;
+       int ret;
+       int ptr;
+
+       for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
+               s3c_register_clksrc(sysclks[ptr], 1);
+
+       s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
+       s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
+
+       clkp = init_clocks_disable;
+       for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
+
+               ret = s3c24xx_register_clock(clkp);
+               if (ret < 0) {
+                       printk(KERN_ERR "Failed to register clock %s (%d)\n",
+                              clkp->name, ret);
+               }
+               (clkp->enable)(clkp, 0);
+       }
+
+       s3c_pwmclk_init();
+}
diff --git a/arch/arm/mach-s5p64x0/clock.c b/arch/arm/mach-s5p64x0/clock.c
new file mode 100644 (file)
index 0000000..523ba80
--- /dev/null
@@ -0,0 +1,253 @@
+/* linux/arch/arm/mach-s5p64x0/clock.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P64X0 - Clock 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/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysdev.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include <plat/cpu-freq.h>
+#include <plat/clock.h>
+#include <plat/cpu.h>
+#include <plat/pll.h>
+#include <plat/s5p-clock.h>
+#include <plat/clock-clksrc.h>
+#include <plat/s5p6440.h>
+#include <plat/s5p6450.h>
+
+struct clksrc_clk clk_mout_apll = {
+       .clk    = {
+               .name           = "mout_apll",
+               .id             = -1,
+       },
+       .sources        = &clk_src_apll,
+       .reg_src        = { .reg = S5P64X0_CLK_SRC0, .shift = 0, .size = 1 },
+};
+
+struct clksrc_clk clk_mout_mpll = {
+       .clk    = {
+               .name           = "mout_mpll",
+               .id             = -1,
+       },
+       .sources        = &clk_src_mpll,
+       .reg_src        = { .reg = S5P64X0_CLK_SRC0, .shift = 1, .size = 1 },
+};
+
+struct clksrc_clk clk_mout_epll = {
+       .clk    = {
+               .name           = "mout_epll",
+               .id             = -1,
+       },
+       .sources        = &clk_src_epll,
+       .reg_src        = { .reg = S5P64X0_CLK_SRC0, .shift = 2, .size = 1 },
+};
+
+enum perf_level {
+       L0 = 532*1000,
+       L1 = 266*1000,
+       L2 = 133*1000,
+};
+
+static const u32 clock_table[][3] = {
+       /*{ARM_CLK, DIVarm, DIVhclk}*/
+       {L0 * 1000, (0 << ARM_DIV_RATIO_SHIFT), (3 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
+       {L1 * 1000, (1 << ARM_DIV_RATIO_SHIFT), (1 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
+       {L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P64X0_CLKDIV0_HCLK_SHIFT)},
+};
+
+int s5p64x0_epll_enable(struct clk *clk, int enable)
+{
+       unsigned int ctrlbit = clk->ctrlbit;
+       unsigned int epll_con = __raw_readl(S5P64X0_EPLL_CON) & ~ctrlbit;
+
+       if (enable)
+               __raw_writel(epll_con | ctrlbit, S5P64X0_EPLL_CON);
+       else
+               __raw_writel(epll_con, S5P64X0_EPLL_CON);
+
+       return 0;
+}
+
+unsigned long s5p64x0_epll_get_rate(struct clk *clk)
+{
+       return clk->rate;
+}
+
+unsigned long s5p64x0_armclk_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(ARM_CLK_DIV) & ARM_DIV_MASK;
+
+       return rate / (clkdiv + 1);
+}
+
+unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate)
+{
+       u32 iter;
+
+       for (iter = 1 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
+               if (rate > clock_table[iter][0])
+                       return clock_table[iter-1][0];
+       }
+
+       return clock_table[ARRAY_SIZE(clock_table) - 1][0];
+}
+
+int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 round_tmp;
+       u32 iter;
+       u32 clk_div0_tmp;
+       u32 cur_rate = clk->ops->get_rate(clk);
+       unsigned long flags;
+
+       round_tmp = clk->ops->round_rate(clk, rate);
+       if (round_tmp == cur_rate)
+               return 0;
+
+
+       for (iter = 0 ; iter < ARRAY_SIZE(clock_table) ; iter++) {
+               if (round_tmp == clock_table[iter][0])
+                       break;
+       }
+
+       if (iter >= ARRAY_SIZE(clock_table))
+               iter = ARRAY_SIZE(clock_table) - 1;
+
+       local_irq_save(flags);
+       if (cur_rate > round_tmp) {
+               /* Frequency Down */
+               clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
+               clk_div0_tmp |= clock_table[iter][1];
+               __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
+
+               clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
+                               ~(S5P64X0_CLKDIV0_HCLK_MASK);
+               clk_div0_tmp |= clock_table[iter][2];
+               __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
+
+
+       } else {
+               /* Frequency Up */
+               clk_div0_tmp = __raw_readl(ARM_CLK_DIV) &
+                               ~(S5P64X0_CLKDIV0_HCLK_MASK);
+               clk_div0_tmp |= clock_table[iter][2];
+               __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
+
+               clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK);
+               clk_div0_tmp |= clock_table[iter][1];
+               __raw_writel(clk_div0_tmp, ARM_CLK_DIV);
+       }
+       local_irq_restore(flags);
+
+       clk->rate = clock_table[iter][0];
+
+       return 0;
+}
+
+struct clk_ops s5p64x0_clkarm_ops = {
+       .get_rate       = s5p64x0_armclk_get_rate,
+       .set_rate       = s5p64x0_armclk_set_rate,
+       .round_rate     = s5p64x0_armclk_round_rate,
+};
+
+struct clksrc_clk clk_armclk = {
+       .clk    = {
+               .name           = "armclk",
+               .id             = 1,
+               .parent         = &clk_mout_apll.clk,
+               .ops            = &s5p64x0_clkarm_ops,
+       },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV0, .shift = 0, .size = 4 },
+};
+
+struct clksrc_clk clk_dout_mpll = {
+       .clk    = {
+               .name           = "dout_mpll",
+               .id             = -1,
+               .parent         = &clk_mout_mpll.clk,
+       },
+       .reg_div        = { .reg = S5P64X0_CLK_DIV0, .shift = 4, .size = 1 },
+};
+
+struct clk *clkset_hclk_low_list[] = {
+       &clk_mout_apll.clk,
+       &clk_mout_mpll.clk,
+};
+
+struct clksrc_sources clkset_hclk_low = {
+       .sources        = clkset_hclk_low_list,
+       .nr_sources     = ARRAY_SIZE(clkset_hclk_low_list),
+};
+
+int s5p64x0_pclk_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(S5P64X0_CLK_GATE_PCLK, clk, enable);
+}
+
+int s5p64x0_hclk0_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(S5P64X0_CLK_GATE_HCLK0, clk, enable);
+}
+
+int s5p64x0_hclk1_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(S5P64X0_CLK_GATE_HCLK1, clk, enable);
+}
+
+int s5p64x0_sclk_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(S5P64X0_CLK_GATE_SCLK0, clk, enable);
+}
+
+int s5p64x0_sclk1_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(S5P64X0_CLK_GATE_SCLK1, clk, enable);
+}
+
+int s5p64x0_mem_ctrl(struct clk *clk, int enable)
+{
+       return s5p_gatectrl(S5P64X0_CLK_GATE_MEM0, clk, enable);
+}
+
+int s5p64x0_clk48m_ctrl(struct clk *clk, int enable)
+{
+       unsigned long flags;
+       u32 val;
+
+       /* can't rely on clock lock, this register has other usages */
+       local_irq_save(flags);
+
+       val = __raw_readl(S5P64X0_OTHERS);
+       if (enable)
+               val |= S5P64X0_OTHERS_USB_SIG_MASK;
+       else
+               val &= ~S5P64X0_OTHERS_USB_SIG_MASK;
+
+       __raw_writel(val, S5P64X0_OTHERS);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
diff --git a/arch/arm/mach-s5p64x0/cpu.c b/arch/arm/mach-s5p64x0/cpu.c
new file mode 100644 (file)
index 0000000..b8d02eb
--- /dev/null
@@ -0,0 +1,209 @@
+/* linux/arch/arm/mach-s5p64x0/cpu.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#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 <linux/sched.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/proc-fns.h>
+#include <asm/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+
+#include <plat/regs-serial.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/clock.h>
+#include <plat/s5p6440.h>
+#include <plat/s5p6450.h>
+#include <plat/adc-core.h>
+
+/* Initial IO mappings */
+
+static struct map_desc s5p64x0_iodesc[] __initdata = {
+       {
+               .virtual        = (unsigned long)S5P_VA_GPIO,
+               .pfn            = __phys_to_pfn(S5P64X0_PA_GPIO),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)VA_VIC0,
+               .pfn            = __phys_to_pfn(S5P64X0_PA_VIC0),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)VA_VIC1,
+               .pfn            = __phys_to_pfn(S5P64X0_PA_VIC1),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       },
+};
+
+static struct map_desc s5p6440_iodesc[] __initdata = {
+       {
+               .virtual        = (unsigned long)S3C_VA_UART,
+               .pfn            = __phys_to_pfn(S5P6440_PA_UART(0)),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       },
+};
+
+static struct map_desc s5p6450_iodesc[] __initdata = {
+       {
+               .virtual        = (unsigned long)S3C_VA_UART,
+               .pfn            = __phys_to_pfn(S5P6450_PA_UART(0)),
+               .length         = SZ_512K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_UART + SZ_512K,
+               .pfn            = __phys_to_pfn(S5P6450_PA_UART(5)),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       },
+};
+
+static void s5p64x0_idle(void)
+{
+       unsigned long val;
+
+       if (!need_resched()) {
+               val = __raw_readl(S5P64X0_PWR_CFG);
+               val &= ~(0x3 << 5);
+               val |= (0x1 << 5);
+               __raw_writel(val, S5P64X0_PWR_CFG);
+
+               cpu_do_idle();
+       }
+       local_irq_enable();
+}
+
+/*
+ * s5p64x0_map_io
+ *
+ * register the standard CPU IO areas
+ */
+
+void __init s5p6440_map_io(void)
+{
+       /* initialize any device information early */
+       s3c_adc_setname("s3c64xx-adc");
+
+       iotable_init(s5p64x0_iodesc, ARRAY_SIZE(s5p64x0_iodesc));
+       iotable_init(s5p6440_iodesc, ARRAY_SIZE(s5p6440_iodesc));
+}
+
+void __init s5p6450_map_io(void)
+{
+       /* initialize any device information early */
+       s3c_adc_setname("s3c64xx-adc");
+
+       iotable_init(s5p64x0_iodesc, ARRAY_SIZE(s5p64x0_iodesc));
+       iotable_init(s5p6450_iodesc, ARRAY_SIZE(s5p6440_iodesc));
+}
+
+/*
+ * s5p64x0_init_clocks
+ *
+ * register and setup the CPU clocks
+ */
+
+void __init s5p6440_init_clocks(int xtal)
+{
+       printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
+
+       s3c24xx_register_baseclocks(xtal);
+       s5p_register_clocks(xtal);
+       s5p6440_register_clocks();
+       s5p6440_setup_clocks();
+}
+
+void __init s5p6450_init_clocks(int xtal)
+{
+       printk(KERN_DEBUG "%s: initializing clocks\n", __func__);
+
+       s3c24xx_register_baseclocks(xtal);
+       s5p_register_clocks(xtal);
+       s5p6450_register_clocks();
+       s5p6450_setup_clocks();
+}
+
+/*
+ * s5p64x0_init_irq
+ *
+ * register the CPU interrupts
+ */
+
+void __init s5p6440_init_irq(void)
+{
+       /* S5P6440 supports 2 VIC */
+       u32 vic[2];
+
+       /*
+        * VIC0 is missing IRQ_VIC0[3, 4, 8, 10, (12-22)]
+        * VIC1 is missing IRQ VIC1[1, 3, 4, 10, 11, 12, 14, 15, 22]
+        */
+       vic[0] = 0xff800ae7;
+       vic[1] = 0xffbf23e5;
+
+       s5p_init_irq(vic, ARRAY_SIZE(vic));
+}
+
+void __init s5p6450_init_irq(void)
+{
+       /* S5P6450 supports only 2 VIC */
+       u32 vic[2];
+
+       /*
+        * VIC0 is missing IRQ_VIC0[(13-15), (21-22)]
+        * VIC1 is missing IRQ VIC1[12, 14, 23]
+        */
+       vic[0] = 0xff9f1fff;
+       vic[1] = 0xff7fafff;
+
+       s5p_init_irq(vic, ARRAY_SIZE(vic));
+}
+
+struct sysdev_class s5p64x0_sysclass = {
+       .name   = "s5p64x0-core",
+};
+
+static struct sys_device s5p64x0_sysdev = {
+       .cls    = &s5p64x0_sysclass,
+};
+
+static int __init s5p64x0_core_init(void)
+{
+       return sysdev_class_register(&s5p64x0_sysclass);
+}
+core_initcall(s5p64x0_core_init);
+
+int __init s5p64x0_init(void)
+{
+       printk(KERN_INFO "S5P64X0(S5P6440/S5P6450): Initializing architecture\n");
+
+       /* set idle function */
+       pm_idle = s5p64x0_idle;
+
+       return sysdev_register(&s5p64x0_sysdev);
+}
diff --git a/arch/arm/mach-s5p64x0/dev-audio.c b/arch/arm/mach-s5p64x0/dev-audio.c
new file mode 100644 (file)
index 0000000..fa097bd
--- /dev/null
@@ -0,0 +1,164 @@
+/* linux/arch/arm/mach-s5p64x0/dev-audio.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ *     Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+
+#include <plat/gpio-cfg.h>
+#include <plat/audio.h>
+
+#include <mach/map.h>
+#include <mach/dma.h>
+#include <mach/irqs.h>
+
+static int s5p6440_cfg_i2s(struct platform_device *pdev)
+{
+       /* configure GPIO for i2s port */
+       switch (pdev->id) {
+       case -1:
+               s3c_gpio_cfgpin(S5P6440_GPR(4), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6440_GPR(5), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6440_GPR(6), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6440_GPR(7), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6440_GPR(8), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6440_GPR(13), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6440_GPR(14), S3C_GPIO_SFN(5));
+               break;
+
+       default:
+               printk(KERN_ERR "Invalid Device %d\n", pdev->id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int s5p6450_cfg_i2s(struct platform_device *pdev)
+{
+       /* configure GPIO for i2s port */
+       switch (pdev->id) {
+       case -1:
+               s3c_gpio_cfgpin(S5P6450_GPB(4), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6450_GPR(4), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6450_GPR(5), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6450_GPR(6), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6450_GPR(7), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6450_GPR(8), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6450_GPR(13), S3C_GPIO_SFN(5));
+               s3c_gpio_cfgpin(S5P6450_GPR(14), S3C_GPIO_SFN(5));
+               break;
+
+       default:
+               printk(KERN_ERR "Invalid Device %d\n", pdev->id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct s3c_audio_pdata s5p6440_i2s_pdata = {
+       .cfg_gpio = s5p6440_cfg_i2s,
+};
+
+static struct s3c_audio_pdata s5p6450_i2s_pdata = {
+       .cfg_gpio = s5p6450_cfg_i2s,
+};
+
+static struct resource s5p64x0_iis0_resource[] = {
+       [0] = {
+               .start  = S5P64X0_PA_I2S,
+               .end    = S5P64X0_PA_I2S + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_I2S0_TX,
+               .end    = DMACH_I2S0_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_I2S0_RX,
+               .end    = DMACH_I2S0_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5p6440_device_iis = {
+       .name           = "s3c64xx-iis-v4",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(s5p64x0_iis0_resource),
+       .resource       = s5p64x0_iis0_resource,
+       .dev = {
+               .platform_data = &s5p6440_i2s_pdata,
+       },
+};
+
+struct platform_device s5p6450_device_iis0 = {
+       .name           = "s3c64xx-iis-v4",
+       .id             = -1,
+       .num_resources  = ARRAY_SIZE(s5p64x0_iis0_resource),
+       .resource       = s5p64x0_iis0_resource,
+       .dev = {
+               .platform_data = &s5p6450_i2s_pdata,
+       },
+};
+
+/* PCM Controller platform_devices */
+
+static int s5p6440_pcm_cfg_gpio(struct platform_device *pdev)
+{
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin(S5P6440_GPR(7), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPR(13), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPR(14), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPR(8), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPR(6), S3C_GPIO_SFN(2));
+               break;
+
+       default:
+               printk(KERN_DEBUG "Invalid PCM Controller number!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct s3c_audio_pdata s5p6440_pcm_pdata = {
+       .cfg_gpio = s5p6440_pcm_cfg_gpio,
+};
+
+static struct resource s5p6440_pcm0_resource[] = {
+       [0] = {
+               .start  = S5P64X0_PA_PCM,
+               .end    = S5P64X0_PA_PCM + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_PCM0_TX,
+               .end    = DMACH_PCM0_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_PCM0_RX,
+               .end    = DMACH_PCM0_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+};
+
+struct platform_device s5p6440_device_pcm = {
+       .name           = "samsung-pcm",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(s5p6440_pcm0_resource),
+       .resource       = s5p6440_pcm0_resource,
+       .dev = {
+               .platform_data = &s5p6440_pcm_pdata,
+       },
+};
diff --git a/arch/arm/mach-s5p64x0/dev-spi.c b/arch/arm/mach-s5p64x0/dev-spi.c
new file mode 100644 (file)
index 0000000..5b69ec4
--- /dev/null
@@ -0,0 +1,232 @@
+/* linux/arch/arm/mach-s5p64x0/dev-spi.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gpio.h>
+
+#include <mach/dma.h>
+#include <mach/map.h>
+#include <mach/irqs.h>
+#include <mach/regs-clock.h>
+#include <mach/spi-clocks.h>
+
+#include <plat/s3c64xx-spi.h>
+#include <plat/gpio-cfg.h>
+
+static char *s5p64x0_spi_src_clks[] = {
+       [S5P64X0_SPI_SRCCLK_PCLK] = "pclk",
+       [S5P64X0_SPI_SRCCLK_SCLK] = "sclk_spi",
+};
+
+/* SPI Controller platform_devices */
+
+/* Since we emulate multi-cs capability, we do not touch the CS.
+ * The emulated CS is toggled by board specific mechanism, as it can
+ * be either some immediate GPIO or some signal out of some other
+ * chip in between ... or some yet another way.
+ * We simply do not assume anything about CS.
+ */
+static int s5p6440_spi_cfg_gpio(struct platform_device *pdev)
+{
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin(S5P6440_GPC(0), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPC(1), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPC(2), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5P6440_GPC(0), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6440_GPC(1), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6440_GPC(2), S3C_GPIO_PULL_UP);
+               break;
+
+       case 1:
+               s3c_gpio_cfgpin(S5P6440_GPC(4), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPC(5), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6440_GPC(6), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5P6440_GPC(4), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6440_GPC(5), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6440_GPC(6), S3C_GPIO_PULL_UP);
+               break;
+
+       default:
+               dev_err(&pdev->dev, "Invalid SPI Controller number!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int s5p6450_spi_cfg_gpio(struct platform_device *pdev)
+{
+       switch (pdev->id) {
+       case 0:
+               s3c_gpio_cfgpin(S5P6450_GPC(0), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6450_GPC(1), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6450_GPC(2), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5P6450_GPC(0), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6450_GPC(1), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6450_GPC(2), S3C_GPIO_PULL_UP);
+               break;
+
+       case 1:
+               s3c_gpio_cfgpin(S5P6450_GPC(4), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6450_GPC(5), S3C_GPIO_SFN(2));
+               s3c_gpio_cfgpin(S5P6450_GPC(6), S3C_GPIO_SFN(2));
+               s3c_gpio_setpull(S5P6450_GPC(4), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6450_GPC(5), S3C_GPIO_PULL_UP);
+               s3c_gpio_setpull(S5P6450_GPC(6), S3C_GPIO_PULL_UP);
+               break;
+
+       default:
+               dev_err(&pdev->dev, "Invalid SPI Controller number!");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct resource s5p64x0_spi0_resource[] = {
+       [0] = {
+               .start  = S5P64X0_PA_SPI0,
+               .end    = S5P64X0_PA_SPI0 + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_SPI0_TX,
+               .end    = DMACH_SPI0_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_SPI0_RX,
+               .end    = DMACH_SPI0_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = IRQ_SPI0,
+               .end    = IRQ_SPI0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c64xx_spi_info s5p6440_spi0_pdata = {
+       .cfg_gpio       = s5p6440_spi_cfg_gpio,
+       .fifo_lvl_mask  = 0x1ff,
+       .rx_lvl_offset  = 15,
+};
+
+static struct s3c64xx_spi_info s5p6450_spi0_pdata = {
+       .cfg_gpio       = s5p6450_spi_cfg_gpio,
+       .fifo_lvl_mask  = 0x1ff,
+       .rx_lvl_offset  = 15,
+};
+
+static u64 spi_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s5p64x0_device_spi0 = {
+       .name           = "s3c64xx-spi",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(s5p64x0_spi0_resource),
+       .resource       = s5p64x0_spi0_resource,
+       .dev = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+
+static struct resource s5p64x0_spi1_resource[] = {
+       [0] = {
+               .start  = S5P64X0_PA_SPI1,
+               .end    = S5P64X0_PA_SPI1 + 0x100 - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = DMACH_SPI1_TX,
+               .end    = DMACH_SPI1_TX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [2] = {
+               .start  = DMACH_SPI1_RX,
+               .end    = DMACH_SPI1_RX,
+               .flags  = IORESOURCE_DMA,
+       },
+       [3] = {
+               .start  = IRQ_SPI1,
+               .end    = IRQ_SPI1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct s3c64xx_spi_info s5p6440_spi1_pdata = {
+       .cfg_gpio       = s5p6440_spi_cfg_gpio,
+       .fifo_lvl_mask  = 0x7f,
+       .rx_lvl_offset  = 15,
+};
+
+static struct s3c64xx_spi_info s5p6450_spi1_pdata = {
+       .cfg_gpio       = s5p6450_spi_cfg_gpio,
+       .fifo_lvl_mask  = 0x7f,
+       .rx_lvl_offset  = 15,
+};
+
+struct platform_device s5p64x0_device_spi1 = {
+       .name           = "s3c64xx-spi",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(s5p64x0_spi1_resource),
+       .resource       = s5p64x0_spi1_resource,
+       .dev = {
+               .dma_mask               = &spi_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       },
+};
+
+void __init s5p64x0_spi_set_info(int cntrlr, int src_clk_nr, int num_cs)
+{
+       unsigned int id;
+       struct s3c64xx_spi_info *pd;
+
+       id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000;
+
+       /* Reject invalid configuration */
+       if (!num_cs || src_clk_nr < 0
+                       || src_clk_nr > S5P64X0_SPI_SRCCLK_SCLK) {
+               printk(KERN_ERR "%s: Invalid SPI configuration\n", __func__);
+               return;
+       }
+
+       switch (cntrlr) {
+       case 0:
+               if (id == 0x50000)
+                       pd = &s5p6450_spi0_pdata;
+               else
+                       pd = &s5p6440_spi0_pdata;
+
+               s5p64x0_device_spi0.dev.platform_data = pd;
+               break;
+       case 1:
+               if (id == 0x50000)
+                       pd = &s5p6450_spi1_pdata;
+               else
+                       pd = &s5p6440_spi1_pdata;
+
+               s5p64x0_device_spi1.dev.platform_data = pd;
+               break;
+       default:
+               printk(KERN_ERR "%s: Invalid SPI controller(%d)\n",
+                                                       __func__, cntrlr);
+               return;
+       }
+
+       pd->num_cs = num_cs;
+       pd->src_clk_nr = src_clk_nr;
+       pd->src_clk_name = s5p64x0_spi_src_clks[src_clk_nr];
+}
similarity index 55%
rename from arch/arm/mach-s5p6440/dma.c
rename to arch/arm/mach-s5p64x0/dma.c
index 07606ad57519a21656b6dcac2af45eea419f6013..29a8c2410049f7fa6b41c51a71f938abcdec9eb7 100644 (file)
@@ -1,4 +1,8 @@
-/*
+/* linux/arch/arm/mach-s5p64x0/dma.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
  * Copyright (C) 2010 Samsung Electronics Co. Ltd.
  *     Jaswinder Singh <jassi.brar@samsung.com>
  *
  * 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/platform_device.h>
 #include <linux/dma-mapping.h>
 
-#include <plat/devs.h>
-#include <plat/irqs.h>
-
 #include <mach/map.h>
 #include <mach/irqs.h>
+#include <mach/regs-clock.h>
 
+#include <plat/devs.h>
 #include <plat/s3c-pl330-pdata.h>
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-static struct resource s5p6440_pdma_resource[] = {
+static struct resource s5p64x0_pdma_resource[] = {
        [0] = {
-               .start  = S5P6440_PA_PDMA,
-               .end    = S5P6440_PA_PDMA + SZ_4K,
-               .flags = IORESOURCE_MEM,
+               .start  = S5P64X0_PA_PDMA,
+               .end    = S5P64X0_PA_PDMA + SZ_4K,
+               .flags  = IORESOURCE_MEM,
        },
        [1] = {
                .start  = IRQ_DMA0,
@@ -80,26 +83,67 @@ static struct s3c_pl330_platdata s5p6440_pdma_pdata = {
        },
 };
 
-static struct platform_device s5p6440_device_pdma = {
+static struct s3c_pl330_platdata s5p6450_pdma_pdata = {
+       .peri = {
+               [0] = DMACH_UART0_RX,
+               [1] = DMACH_UART0_TX,
+               [2] = DMACH_UART1_RX,
+               [3] = DMACH_UART1_TX,
+               [4] = DMACH_UART2_RX,
+               [5] = DMACH_UART2_TX,
+               [6] = DMACH_UART3_RX,
+               [7] = DMACH_UART3_TX,
+               [8] = DMACH_UART4_RX,
+               [9] = DMACH_UART4_TX,
+               [10] = DMACH_PCM0_TX,
+               [11] = DMACH_PCM0_RX,
+               [12] = DMACH_I2S0_TX,
+               [13] = DMACH_I2S0_RX,
+               [14] = DMACH_SPI0_TX,
+               [15] = DMACH_SPI0_RX,
+               [16] = DMACH_PCM1_TX,
+               [17] = DMACH_PCM1_RX,
+               [18] = DMACH_PCM2_TX,
+               [19] = DMACH_PCM2_RX,
+               [20] = DMACH_SPI1_TX,
+               [21] = DMACH_SPI1_RX,
+               [22] = DMACH_USI_TX,
+               [23] = DMACH_USI_RX,
+               [24] = DMACH_MAX,
+               [25] = DMACH_I2S1_TX,
+               [26] = DMACH_I2S1_RX,
+               [27] = DMACH_I2S2_TX,
+               [28] = DMACH_I2S2_RX,
+               [29] = DMACH_PWM,
+               [30] = DMACH_UART5_RX,
+               [31] = DMACH_UART5_TX,
+       },
+};
+
+static struct platform_device s5p64x0_device_pdma = {
        .name           = "s3c-pl330",
-       .id             = 1,
-       .num_resources  = ARRAY_SIZE(s5p6440_pdma_resource),
-       .resource       = s5p6440_pdma_resource,
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(s5p64x0_pdma_resource),
+       .resource       = s5p64x0_pdma_resource,
        .dev            = {
                .dma_mask = &dma_dmamask,
                .coherent_dma_mask = DMA_BIT_MASK(32),
-               .platform_data = &s5p6440_pdma_pdata,
        },
 };
 
-static struct platform_device *s5p6440_dmacs[] __initdata = {
-       &s5p6440_device_pdma,
-};
-
-static int __init s5p6440_dma_init(void)
+static int __init s5p64x0_dma_init(void)
 {
-       platform_add_devices(s5p6440_dmacs, ARRAY_SIZE(s5p6440_dmacs));
+       unsigned int id;
+
+       id = __raw_readl(S5P64X0_SYS_ID) & 0xFF000;
+
+       if (id == 0x50000)
+               s5p64x0_device_pdma.dev.platform_data = &s5p6450_pdma_pdata;
+       else
+               s5p64x0_device_pdma.dev.platform_data = &s5p6440_pdma_pdata;
+
+       platform_device_register(&s5p64x0_device_pdma);
 
        return 0;
 }
-arch_initcall(s5p6440_dma_init);
+arch_initcall(s5p64x0_dma_init);
similarity index 74%
rename from arch/arm/mach-s5p6440/gpio.c
rename to arch/arm/mach-s5p64x0/gpio.c
index 8bf6e0ce51c9cd9b95830770e6e62edf8710d83f..39159dd5a29ac7bf091e457a03d6eed14ef6573d 100644 (file)
@@ -1,14 +1,14 @@
-/* arch/arm/mach-s5p6440/gpio.c
+/* linux/arch/arm/mach-s5p64x0/gpio.c
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
- * S5P6440 - GPIOlib support
+ * S5P64X0 - GPIOlib support
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- */
+*/
 
 #include <linux/kernel.h>
 #include <linux/irq.h>
 #include <plat/gpio-cfg.h>
 #include <plat/gpio-cfg-helpers.h>
 
-/* GPIO bank summary:
-*
-* Bank GPIOs   Style   SlpCon  ExtInt Group
-* A    6       4Bit    Yes     1
-* B    7       4Bit    Yes     1
-* C    8       4Bit    Yes     2
-* F    2       2Bit    Yes     4 [1]
-* G    7       4Bit    Yes     5
-* H    10      4Bit[2] Yes     6
-* I    16      2Bit    Yes     None
-* J    12      2Bit    Yes     None
-* N    16      2Bit    No      IRQ_EINT
-* P    8       2Bit    Yes     8
-* R    15      4Bit[2] Yes     8
-*
-* [1] BANKF pins 14,15 do not form part of the external interrupt sources
-* [2] BANK has two control registers, GPxCON0 and GPxCON1
-*/
+/* To be implemented S5P6450 GPIO */
+
+/*
+ * S5P6440 GPIO bank summary:
+ *
+ * Bank        GPIOs   Style   SlpCon  ExtInt Group
+ * A   6       4Bit    Yes     1
+ * B   7       4Bit    Yes     1
+ * C   8       4Bit    Yes     2
+ * F   2       2Bit    Yes     4 [1]
+ * G   7       4Bit    Yes     5
+ * H   10      4Bit[2] Yes     6
+ * I   16      2Bit    Yes     None
+ * J   12      2Bit    Yes     None
+ * N   16      2Bit    No      IRQ_EINT
+ * P   8       2Bit    Yes     8
+ * R   15      4Bit[2] Yes     8
+ *
+ * [1] BANKF pins 14,15 do not form part of the external interrupt sources
+ * [2] BANK has two control registers, GPxCON0 and GPxCON1
+ */
 
-static int s5p6440_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
+static int s5p64x0_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
                                             unsigned int offset)
 {
        struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
@@ -77,7 +80,7 @@ static int s5p6440_gpiolib_rbank_4bit2_input(struct gpio_chip *chip,
        return 0;
 }
 
-static int s5p6440_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
+static int s5p64x0_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
                                              unsigned int offset, int value)
 {
        struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip);
@@ -124,12 +127,11 @@ static int s5p6440_gpiolib_rbank_4bit2_output(struct gpio_chip *chip,
        return 0;
 }
 
-int s5p6440_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
+int s5p64x0_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
                                   unsigned int off, unsigned int cfg)
 {
        void __iomem *reg = chip->base;
        unsigned int shift;
-       unsigned long flags;
        u32 con;
 
        switch (off) {
@@ -155,26 +157,22 @@ int s5p6440_gpio_setcfg_4bit_rbank(struct s3c_gpio_chip *chip,
                cfg <<= shift;
        }
 
-       s3c_gpio_lock(chip, flags);
-
        con = __raw_readl(reg);
        con &= ~(0xf << shift);
        con |= cfg;
        __raw_writel(con, reg);
 
-       s3c_gpio_unlock(chip, flags);
-
        return 0;
 }
 
-static struct s3c_gpio_cfg s5p6440_gpio_cfgs[] = {
+static struct s3c_gpio_cfg s5p64x0_gpio_cfgs[] = {
        {
                .cfg_eint       = 0,
        }, {
                .cfg_eint       = 7,
        }, {
                .cfg_eint       = 3,
-               .set_config     = s5p6440_gpio_setcfg_4bit_rbank,
+               .set_config     = s5p64x0_gpio_setcfg_4bit_rbank,
        }, {
                .cfg_eint       = 0,
                .set_config     = s3c_gpio_setcfg_s3c24xx,
@@ -193,7 +191,7 @@ static struct s3c_gpio_cfg s5p6440_gpio_cfgs[] = {
 static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
        {
                .base   = S5P6440_GPA_BASE,
-               .config = &s5p6440_gpio_cfgs[1],
+               .config = &s5p64x0_gpio_cfgs[1],
                .chip   = {
                        .base   = S5P6440_GPA(0),
                        .ngpio  = S5P6440_GPIO_A_NR,
@@ -201,7 +199,7 @@ static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
                },
        }, {
                .base   = S5P6440_GPB_BASE,
-               .config = &s5p6440_gpio_cfgs[1],
+               .config = &s5p64x0_gpio_cfgs[1],
                .chip   = {
                        .base   = S5P6440_GPB(0),
                        .ngpio  = S5P6440_GPIO_B_NR,
@@ -209,7 +207,7 @@ static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
                },
        }, {
                .base   = S5P6440_GPC_BASE,
-               .config = &s5p6440_gpio_cfgs[1],
+               .config = &s5p64x0_gpio_cfgs[1],
                .chip   = {
                        .base   = S5P6440_GPC(0),
                        .ngpio  = S5P6440_GPIO_C_NR,
@@ -217,7 +215,7 @@ static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
                },
        }, {
                .base   = S5P6440_GPG_BASE,
-               .config = &s5p6440_gpio_cfgs[1],
+               .config = &s5p64x0_gpio_cfgs[1],
                .chip   = {
                        .base   = S5P6440_GPG(0),
                        .ngpio  = S5P6440_GPIO_G_NR,
@@ -229,7 +227,7 @@ static struct s3c_gpio_chip s5p6440_gpio_4bit[] = {
 static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
        {
                .base   = S5P6440_GPH_BASE + 0x4,
-               .config = &s5p6440_gpio_cfgs[1],
+               .config = &s5p64x0_gpio_cfgs[1],
                .chip   = {
                        .base   = S5P6440_GPH(0),
                        .ngpio  = S5P6440_GPIO_H_NR,
@@ -238,10 +236,10 @@ static struct s3c_gpio_chip s5p6440_gpio_4bit2[] = {
        },
 };
 
-static struct s3c_gpio_chip gpio_rbank_4bit2[] = {
+static struct s3c_gpio_chip s5p6440_gpio_rbank_4bit2[] = {
        {
                .base   = S5P6440_GPR_BASE + 0x4,
-               .config = &s5p6440_gpio_cfgs[2],
+               .config = &s5p64x0_gpio_cfgs[2],
                .chip   = {
                        .base   = S5P6440_GPR(0),
                        .ngpio  = S5P6440_GPIO_R_NR,
@@ -253,7 +251,7 @@ static struct s3c_gpio_chip gpio_rbank_4bit2[] = {
 static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
        {
                .base   = S5P6440_GPF_BASE,
-               .config = &s5p6440_gpio_cfgs[5],
+               .config = &s5p64x0_gpio_cfgs[5],
                .chip   = {
                        .base   = S5P6440_GPF(0),
                        .ngpio  = S5P6440_GPIO_F_NR,
@@ -261,7 +259,7 @@ static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
                },
        }, {
                .base   = S5P6440_GPI_BASE,
-               .config = &s5p6440_gpio_cfgs[3],
+               .config = &s5p64x0_gpio_cfgs[3],
                .chip   = {
                        .base   = S5P6440_GPI(0),
                        .ngpio  = S5P6440_GPIO_I_NR,
@@ -269,7 +267,7 @@ static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
                },
        }, {
                .base   = S5P6440_GPJ_BASE,
-               .config = &s5p6440_gpio_cfgs[3],
+               .config = &s5p64x0_gpio_cfgs[3],
                .chip   = {
                        .base   = S5P6440_GPJ(0),
                        .ngpio  = S5P6440_GPIO_J_NR,
@@ -277,7 +275,7 @@ static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
                },
        }, {
                .base   = S5P6440_GPN_BASE,
-               .config = &s5p6440_gpio_cfgs[4],
+               .config = &s5p64x0_gpio_cfgs[4],
                .chip   = {
                        .base   = S5P6440_GPN(0),
                        .ngpio  = S5P6440_GPIO_N_NR,
@@ -285,7 +283,7 @@ static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
                },
        }, {
                .base   = S5P6440_GPP_BASE,
-               .config = &s5p6440_gpio_cfgs[5],
+               .config = &s5p64x0_gpio_cfgs[5],
                .chip   = {
                        .base   = S5P6440_GPP(0),
                        .ngpio  = S5P6440_GPIO_P_NR,
@@ -294,7 +292,7 @@ static struct s3c_gpio_chip s5p6440_gpio_2bit[] = {
        },
 };
 
-void __init s5p6440_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
+void __init s5p64x0_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
 {
        for (; nr_chips > 0; nr_chips--, chipcfg++) {
                if (!chipcfg->set_config)
@@ -308,13 +306,13 @@ void __init s5p6440_gpiolib_set_cfg(struct s3c_gpio_cfg *chipcfg, int nr_chips)
        }
 }
 
-static void __init s5p6440_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
+static void __init s5p64x0_gpio_add_rbank_4bit2(struct s3c_gpio_chip *chip,
                                                int nr_chips)
 {
        for (; nr_chips > 0; nr_chips--, chip++) {
-               chip->chip.direction_input = s5p6440_gpiolib_rbank_4bit2_input;
+               chip->chip.direction_input = s5p64x0_gpiolib_rbank_4bit2_input;
                chip->chip.direction_output =
-                                       s5p6440_gpiolib_rbank_4bit2_output;
+                                       s5p64x0_gpiolib_rbank_4bit2_output;
                s3c_gpiolib_add(chip);
        }
 }
@@ -324,8 +322,8 @@ static int __init s5p6440_gpiolib_init(void)
        struct s3c_gpio_chip *chips = s5p6440_gpio_2bit;
        int nr_chips = ARRAY_SIZE(s5p6440_gpio_2bit);
 
-       s5p6440_gpiolib_set_cfg(s5p6440_gpio_cfgs,
-                               ARRAY_SIZE(s5p6440_gpio_cfgs));
+       s5p64x0_gpiolib_set_cfg(s5p64x0_gpio_cfgs,
+                               ARRAY_SIZE(s5p64x0_gpio_cfgs));
 
        for (; nr_chips > 0; nr_chips--, chips++)
                s3c_gpiolib_add(chips);
@@ -336,8 +334,8 @@ static int __init s5p6440_gpiolib_init(void)
        samsung_gpiolib_add_4bit2_chips(s5p6440_gpio_4bit2,
                                ARRAY_SIZE(s5p6440_gpio_4bit2));
 
-       s5p6440_gpio_add_rbank_4bit2(gpio_rbank_4bit2,
-                               ARRAY_SIZE(gpio_rbank_4bit2));
+       s5p64x0_gpio_add_rbank_4bit2(s5p6440_gpio_rbank_4bit2,
+                               ARRAY_SIZE(s5p6440_gpio_rbank_4bit2));
 
        return 0;
 }
diff --git a/arch/arm/mach-s5p64x0/include/mach/debug-macro.S b/arch/arm/mach-s5p64x0/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..79b04e6
--- /dev/null
@@ -0,0 +1,33 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/debug-macro.S
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/* pull in the relevant register and map files. */
+
+#include <plat/map-base.h>
+#include <plat/map-s5p.h>
+
+#include <plat/regs-serial.h>
+
+       .macro addruart, rp, rv
+               mov     \rp, #0xE0000000
+               orr     \rp, \rp, #0x00100000
+               ldr     \rp, [\rp, #0x118 ]
+               and     \rp, \rp, #0xff000
+               teq     \rp, #0x50000           @@ S5P6450
+               ldreq   \rp, =0xEC800000
+               movne   \rp, #0xEC000000        @@ S5P6440
+               ldrne   \rv, = S3C_VA_UART
+#if CONFIG_DEBUG_S3C_UART != 0
+               add     \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
+               add     \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
+#endif
+       .endm
+
+#include <plat/debug-macro.S>
similarity index 58%
rename from arch/arm/mach-s5p6440/include/mach/entry-macro.S
rename to arch/arm/mach-s5p64x0/include/mach/entry-macro.S
index e65f1b9672626d512d95e004aa8f740e30b4ae43..10b62b4f821177aa2c45fd2d7c91748411973d44 100644 (file)
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/entry-macro.S
+/* linux/arch/arm/mach-s5p64x0/include/mach/entry-macro.S
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
- * Low-level IRQ helper macros for the Samsung S5P6440
+ * Low-level IRQ helper macros for the Samsung S5P64X0
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-s5p64x0/include/mach/gpio.h b/arch/arm/mach-s5p64x0/include/mach/gpio.h
new file mode 100644 (file)
index 0000000..5486c8f
--- /dev/null
@@ -0,0 +1,139 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/gpio.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P64X0 - GPIO lib 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.
+*/
+
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H __FILE__
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep  __gpio_cansleep
+#define gpio_to_irq    __gpio_to_irq
+
+/* GPIO bank sizes */
+
+#define S5P6440_GPIO_A_NR      (6)
+#define S5P6440_GPIO_B_NR      (7)
+#define S5P6440_GPIO_C_NR      (8)
+#define S5P6440_GPIO_F_NR      (2)
+#define S5P6440_GPIO_G_NR      (7)
+#define S5P6440_GPIO_H_NR      (10)
+#define S5P6440_GPIO_I_NR      (16)
+#define S5P6440_GPIO_J_NR      (12)
+#define S5P6440_GPIO_N_NR      (16)
+#define S5P6440_GPIO_P_NR      (8)
+#define S5P6440_GPIO_R_NR      (15)
+
+#define S5P6450_GPIO_A_NR      (6)
+#define S5P6450_GPIO_B_NR      (7)
+#define S5P6450_GPIO_C_NR      (8)
+#define S5P6450_GPIO_D_NR      (8)
+#define S5P6450_GPIO_F_NR      (2)
+#define S5P6450_GPIO_G_NR      (14)
+#define S5P6450_GPIO_H_NR      (10)
+#define S5P6450_GPIO_I_NR      (16)
+#define S5P6450_GPIO_J_NR      (12)
+#define S5P6450_GPIO_K_NR      (5)
+#define S5P6450_GPIO_N_NR      (16)
+#define S5P6450_GPIO_P_NR      (11)
+#define S5P6450_GPIO_Q_NR      (14)
+#define S5P6450_GPIO_R_NR      (15)
+#define S5P6450_GPIO_S_NR      (8)
+
+/* GPIO bank numbers */
+
+/* CONFIG_S3C_GPIO_SPACE allows the user to select extra
+ * space for debugging purposes so that any accidental
+ * change from one gpio bank to another can be caught.
+*/
+
+#define S5P64X0_GPIO_NEXT(__gpio) \
+       ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)
+
+enum s5p6440_gpio_number {
+       S5P6440_GPIO_A_START    = 0,
+       S5P6440_GPIO_B_START    = S5P64X0_GPIO_NEXT(S5P6440_GPIO_A),
+       S5P6440_GPIO_C_START    = S5P64X0_GPIO_NEXT(S5P6440_GPIO_B),
+       S5P6440_GPIO_F_START    = S5P64X0_GPIO_NEXT(S5P6440_GPIO_C),
+       S5P6440_GPIO_G_START    = S5P64X0_GPIO_NEXT(S5P6440_GPIO_F),
+       S5P6440_GPIO_H_START    = S5P64X0_GPIO_NEXT(S5P6440_GPIO_G),
+       S5P6440_GPIO_I_START    = S5P64X0_GPIO_NEXT(S5P6440_GPIO_H),
+       S5P6440_GPIO_J_START    = S5P64X0_GPIO_NEXT(S5P6440_GPIO_I),
+       S5P6440_GPIO_N_START    = S5P64X0_GPIO_NEXT(S5P6440_GPIO_J),
+       S5P6440_GPIO_P_START    = S5P64X0_GPIO_NEXT(S5P6440_GPIO_N),
+       S5P6440_GPIO_R_START    = S5P64X0_GPIO_NEXT(S5P6440_GPIO_P),
+};
+
+enum s5p6450_gpio_number {
+       S5P6450_GPIO_A_START    = 0,
+       S5P6450_GPIO_B_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_A),
+       S5P6450_GPIO_C_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_B),
+       S5P6450_GPIO_D_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_C),
+       S5P6450_GPIO_F_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_D),
+       S5P6450_GPIO_G_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_F),
+       S5P6450_GPIO_H_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_G),
+       S5P6450_GPIO_I_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_H),
+       S5P6450_GPIO_J_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_I),
+       S5P6450_GPIO_K_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_J),
+       S5P6450_GPIO_N_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_K),
+       S5P6450_GPIO_P_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_N),
+       S5P6450_GPIO_Q_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_P),
+       S5P6450_GPIO_R_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_Q),
+       S5P6450_GPIO_S_START    = S5P64X0_GPIO_NEXT(S5P6450_GPIO_R),
+};
+
+/* GPIO number definitions */
+
+#define S5P6440_GPA(_nr)       (S5P6440_GPIO_A_START + (_nr))
+#define S5P6440_GPB(_nr)       (S5P6440_GPIO_B_START + (_nr))
+#define S5P6440_GPC(_nr)       (S5P6440_GPIO_C_START + (_nr))
+#define S5P6440_GPF(_nr)       (S5P6440_GPIO_F_START + (_nr))
+#define S5P6440_GPG(_nr)       (S5P6440_GPIO_G_START + (_nr))
+#define S5P6440_GPH(_nr)       (S5P6440_GPIO_H_START + (_nr))
+#define S5P6440_GPI(_nr)       (S5P6440_GPIO_I_START + (_nr))
+#define S5P6440_GPJ(_nr)       (S5P6440_GPIO_J_START + (_nr))
+#define S5P6440_GPN(_nr)       (S5P6440_GPIO_N_START + (_nr))
+#define S5P6440_GPP(_nr)       (S5P6440_GPIO_P_START + (_nr))
+#define S5P6440_GPR(_nr)       (S5P6440_GPIO_R_START + (_nr))
+
+#define S5P6450_GPA(_nr)       (S5P6450_GPIO_A_START + (_nr))
+#define S5P6450_GPB(_nr)       (S5P6450_GPIO_B_START + (_nr))
+#define S5P6450_GPC(_nr)       (S5P6450_GPIO_C_START + (_nr))
+#define S5P6450_GPD(_nr)       (S5P6450_GPIO_D_START + (_nr))
+#define S5P6450_GPF(_nr)       (S5P6450_GPIO_F_START + (_nr))
+#define S5P6450_GPG(_nr)       (S5P6450_GPIO_G_START + (_nr))
+#define S5P6450_GPH(_nr)       (S5P6450_GPIO_H_START + (_nr))
+#define S5P6450_GPI(_nr)       (S5P6450_GPIO_I_START + (_nr))
+#define S5P6450_GPJ(_nr)       (S5P6450_GPIO_J_START + (_nr))
+#define S5P6450_GPK(_nr)       (S5P6450_GPIO_K_START + (_nr))
+#define S5P6450_GPN(_nr)       (S5P6450_GPIO_N_START + (_nr))
+#define S5P6450_GPP(_nr)       (S5P6450_GPIO_P_START + (_nr))
+#define S5P6450_GPQ(_nr)       (S5P6450_GPIO_Q_START + (_nr))
+#define S5P6450_GPR(_nr)       (S5P6450_GPIO_R_START + (_nr))
+#define S5P6450_GPS(_nr)       (S5P6450_GPIO_S_START + (_nr))
+
+/* the end of the S5P64X0 specific gpios */
+
+#define S5P6440_GPIO_END       (S5P6440_GPR(S5P6440_GPIO_R_NR) + 1)
+#define S5P6450_GPIO_END       (S5P6450_GPS(S5P6450_GPIO_S_NR) + 1)
+
+#define S5P64X0_GPIO_END       (S5P6440_GPIO_END > S5P6450_GPIO_END ?  \
+                                S5P6440_GPIO_END : S5P6450_GPIO_END)
+
+#define S3C_GPIO_END           S5P64X0_GPIO_END
+
+/* define the number of gpios we need to the one after the last GPIO range */
+
+#define ARCH_NR_GPIOS          (S5P64X0_GPIO_END + CONFIG_SAMSUNG_GPIO_EXTRA)
+
+#include <asm-generic/gpio.h>
+
+#endif /* __ASM_ARCH_GPIO_H */
similarity index 67%
rename from arch/arm/mach-s5p6440/include/mach/hardware.h
rename to arch/arm/mach-s5p64x0/include/mach/hardware.h
index be8b26e875db5fb51211b676a34e4cb1448f2cbc..d3e87996dd9a752db134b0f790fe9fda94673933 100644 (file)
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/hardware.h
+/* linux/arch/arm/mach-s5p64x0/include/mach/hardware.h
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
- * S5P6440 - Hardware support
+ * S5P64X0 - Hardware 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
diff --git a/arch/arm/mach-s5p64x0/include/mach/i2c.h b/arch/arm/mach-s5p64x0/include/mach/i2c.h
new file mode 100644 (file)
index 0000000..887d252
--- /dev/null
@@ -0,0 +1,17 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/i2c.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P64X0 I2C configuration
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+extern void s5p6440_i2c0_cfg_gpio(struct platform_device *dev);
+extern void s5p6440_i2c1_cfg_gpio(struct platform_device *dev);
+
+extern void s5p6450_i2c0_cfg_gpio(struct platform_device *dev);
+extern void s5p6450_i2c1_cfg_gpio(struct platform_device *dev);
diff --git a/arch/arm/mach-s5p64x0/include/mach/io.h b/arch/arm/mach-s5p64x0/include/mach/io.h
new file mode 100644 (file)
index 0000000..a3e095c
--- /dev/null
@@ -0,0 +1,25 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/io.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Copyright 2008 Simtec Electronics
+ *     Ben Dooks <ben-linux@fluff.org>
+ *
+ * Default IO routines for S5P64X0 based
+ *
+ * This program is free software; you can 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_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+/* No current ISA/PCI bus support. */
+#define __io(a)                __typesafe_io(a)
+#define __mem_pci(a)   (a)
+
+#define IO_SPACE_LIMIT (0xFFFFFFFF)
+
+#endif
similarity index 71%
rename from arch/arm/mach-s5p6440/include/mach/irqs.h
rename to arch/arm/mach-s5p64x0/include/mach/irqs.h
index 16a761270de108fd76dc9159da3f2af9dbae4600..513abffc760495a1ac1cdf69fce010682d707478 100644 (file)
@@ -1,17 +1,17 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/irqs.h
+/* linux/arch/arm/mach-s5p64x0/include/mach/irqs.h
  *
- * Copyright 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
- * S5P6440 - IRQ definitions
+ * S5P64X0 - IRQ definitions
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
 */
 
-#ifndef __ASM_ARCH_S5P_IRQS_H
-#define __ASM_ARCH_S5P_IRQS_H __FILE__
+#ifndef __ASM_ARCH_IRQS_H
+#define __ASM_ARCH_IRQS_H __FILE__
 
 #include <plat/irqs.h>
 
 #define IRQ_EINT0_3            S5P_IRQ_VIC0(0)
 #define IRQ_EINT4_11           S5P_IRQ_VIC0(1)
 #define IRQ_RTC_TIC            S5P_IRQ_VIC0(2)
+#define IRQ_IIS1               S5P_IRQ_VIC0(3) /* for only S5P6450 */
+#define IRQ_IIS2               S5P_IRQ_VIC0(4) /* for only S5P6450 */
 #define IRQ_IIC1               S5P_IRQ_VIC0(5)
 #define IRQ_I2SV40             S5P_IRQ_VIC0(6)
-#define IRQ_GPS                        S5P_IRQ_VIC0(7)
-#define IRQ_POST0              S5P_IRQ_VIC0(9)
+#define IRQ_GPS                        S5P_IRQ_VIC0(7) /* for only S5P6450 */
+
 #define IRQ_2D                 S5P_IRQ_VIC0(11)
 #define IRQ_TIMER0_VIC         S5P_IRQ_VIC0(23)
 #define IRQ_TIMER1_VIC         S5P_IRQ_VIC0(24)
 
 #define IRQ_EINT12_15          S5P_IRQ_VIC1(0)
 #define IRQ_PCM0               S5P_IRQ_VIC1(2)
+#define IRQ_PCM1               S5P_IRQ_VIC1(3) /* for only S5P6450 */
+#define IRQ_PCM2               S5P_IRQ_VIC1(4) /* for only S5P6450 */
 #define IRQ_UART0              S5P_IRQ_VIC1(5)
 #define IRQ_UART1              S5P_IRQ_VIC1(6)
 #define IRQ_UART2              S5P_IRQ_VIC1(7)
 #define IRQ_UART3              S5P_IRQ_VIC1(8)
 #define IRQ_DMA0               S5P_IRQ_VIC1(9)
+#define IRQ_UART4              S5P_IRQ_VIC1(10)        /* S5P6450 */
+#define IRQ_UART5              S5P_IRQ_VIC1(11)        /* S5P6450 */
 #define IRQ_NFC                        S5P_IRQ_VIC1(13)
+#define IRQ_USI                        S5P_IRQ_VIC1(15)        /* S5P6450 */
 #define IRQ_SPI0               S5P_IRQ_VIC1(16)
 #define IRQ_SPI1               S5P_IRQ_VIC1(17)
+#define IRQ_HSMMC2             S5P_IRQ_VIC1(17)        /* Shared */
 #define IRQ_IIC                        S5P_IRQ_VIC1(18)
 #define IRQ_DISPCON3           S5P_IRQ_VIC1(19)
-#define IRQ_FIMGVG             S5P_IRQ_VIC1(20)
 #define IRQ_EINT_GROUPS                S5P_IRQ_VIC1(21)
-#define IRQ_PMU                        S5P_IRQ_VIC1(23)
+#define IRQ_PMU                        S5P_IRQ_VIC1(23)        /* S5P6440 */
 #define IRQ_HSMMC0             S5P_IRQ_VIC1(24)
 #define IRQ_HSMMC1             S5P_IRQ_VIC1(25)
-#define IRQ_HSMMC2             IRQ_SPI1        /* shared with SPI1 */
 #define IRQ_OTG                        S5P_IRQ_VIC1(26)
 #define IRQ_DSI                        S5P_IRQ_VIC1(27)
 #define IRQ_RTC_ALARM          S5P_IRQ_VIC1(28)
 #define IRQ_TC                 IRQ_PENDN
 #define IRQ_ADC                        S5P_IRQ_VIC1(31)
 
+/* UART interrupts, S5P6450 has 5 UARTs */
+#define IRQ_S5P_UART_BASE4     (96)
+#define IRQ_S5P_UART_BASE5     (100)
+
+#define IRQ_S5P_UART_RX4       (IRQ_S5P_UART_BASE4 + UART_IRQ_RXD)
+#define IRQ_S5P_UART_TX4       (IRQ_S5P_UART_BASE4 + UART_IRQ_TXD)
+#define IRQ_S5P_UART_ERR4      (IRQ_S5P_UART_BASE4 + UART_IRQ_ERR)
+
+#define IRQ_S5P_UART_RX5       (IRQ_S5P_UART_BASE5 + UART_IRQ_RXD)
+#define IRQ_S5P_UART_TX5       (IRQ_S5P_UART_BASE5 + UART_IRQ_TXD)
+#define IRQ_S5P_UART_ERR5      (IRQ_S5P_UART_BASE5 + UART_IRQ_ERR)
+
+/* S3C compatibilty defines */
+#define IRQ_S3CUART_RX4                IRQ_S5P_UART_RX4
+#define IRQ_S3CUART_RX5                IRQ_S5P_UART_RX5
+
+/* S5P6450 EINT feature will be added */
+
 /*
  * Since the IRQ_EINT(x) are a linear mapping on s5p6440 we just defined
  * them as an IRQ_EINT(x) macro from S5P_IRQ_EINT_BASE which we place
 
 #define NR_IRQS                        (IRQ_EINT_GROUP8_BASE + IRQ_EINT_GROUP8_NR + 1)
 
-#endif /* __ASM_ARCH_S5P_IRQS_H */
+#endif /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-s5p64x0/include/mach/map.h b/arch/arm/mach-s5p64x0/include/mach/map.h
new file mode 100644 (file)
index 0000000..31e5341
--- /dev/null
@@ -0,0 +1,83 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/map.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P64X0 - Memory map definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_MAP_H
+#define __ASM_ARCH_MAP_H __FILE__
+
+#include <plat/map-base.h>
+#include <plat/map-s5p.h>
+
+#define S5P64X0_PA_SDRAM       (0x20000000)
+
+#define S5P64X0_PA_CHIPID      (0xE0000000)
+#define S5P_PA_CHIPID          S5P64X0_PA_CHIPID
+
+#define S5P64X0_PA_SYSCON      (0xE0100000)
+#define S5P_PA_SYSCON          S5P64X0_PA_SYSCON
+
+#define S5P64X0_PA_GPIO                (0xE0308000)
+
+#define S5P64X0_PA_VIC0                (0xE4000000)
+#define S5P64X0_PA_VIC1                (0xE4100000)
+
+#define S5P64X0_PA_PDMA                (0xE9000000)
+
+#define S5P64X0_PA_TIMER       (0xEA000000)
+#define S5P_PA_TIMER           S5P64X0_PA_TIMER
+
+#define S5P64X0_PA_RTC         (0xEA100000)
+
+#define S5P64X0_PA_WDT         (0xEA200000)
+
+#define S5P6440_PA_UART(x)     (0xEC000000 + ((x) * S3C_UART_OFFSET))
+#define S5P6450_PA_UART(x)     ((x < 5) ? (0xEC800000 + ((x) * S3C_UART_OFFSET)) : (0xEC000000))
+
+#define S5P_PA_UART0           S5P6450_PA_UART(0)
+#define S5P_PA_UART1           S5P6450_PA_UART(1)
+#define S5P_PA_UART2           S5P6450_PA_UART(2)
+#define S5P_PA_UART3           S5P6450_PA_UART(3)
+#define S5P_PA_UART4           S5P6450_PA_UART(4)
+#define S5P_PA_UART5           S5P6450_PA_UART(5)
+
+#define S5P_SZ_UART            SZ_256
+
+#define S5P6440_PA_IIC0                (0xEC104000)
+#define S5P6440_PA_IIC1                (0xEC20F000)
+#define S5P6450_PA_IIC0                (0xEC100000)
+#define S5P6450_PA_IIC1                (0xEC200000)
+
+#define S5P64X0_PA_SPI0                (0xEC400000)
+#define S5P64X0_PA_SPI1                (0xEC500000)
+
+#define S5P64X0_PA_HSOTG       (0xED100000)
+
+#define S5P64X0_PA_HSMMC(x)    (0xED800000 + ((x) * 0x100000))
+
+#define S5P64X0_PA_I2S         (0xF2000000)
+
+#define S5P64X0_PA_PCM         (0xF2100000)
+
+#define S5P64X0_PA_ADC         (0xF3000000)
+
+/* compatibiltiy defines. */
+
+#define S3C_PA_HSMMC0          S5P64X0_PA_HSMMC(0)
+#define S3C_PA_HSMMC1          S5P64X0_PA_HSMMC(1)
+#define S3C_PA_HSMMC2          S5P64X0_PA_HSMMC(2)
+#define S3C_PA_IIC             S5P6440_PA_IIC0
+#define S3C_PA_IIC1            S5P6440_PA_IIC1
+#define S3C_PA_RTC             S5P64X0_PA_RTC
+#define S3C_PA_WDT             S5P64X0_PA_WDT
+
+#define SAMSUNG_PA_ADC         S5P64X0_PA_ADC
+
+#endif /* __ASM_ARCH_MAP_H */
similarity index 55%
rename from arch/arm/mach-s5p6440/include/mach/memory.h
rename to arch/arm/mach-s5p64x0/include/mach/memory.h
index d62910c71b566af0b5214a9eb426b55572eb541f..1b036b0a24cee858c35676e0609e744c56e3381b 100644 (file)
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/memory.h
+/* linux/arch/arm/mach-s5p64x0/include/mach/memory.h
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
- * S5P6440 - Memory definitions
+ * S5P64X0 - Memory definitions
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -11,9 +11,9 @@
 */
 
 #ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H __FILE__
 
-#define PHYS_OFFSET            UL(0x20000000)
+#define PHYS_OFFSET            UL(0x20000000)
 #define CONSISTENT_DMA_SIZE    SZ_8M
 
 #endif /* __ASM_ARCH_MEMORY_H */
similarity index 86%
rename from arch/arm/mach-s5p6440/include/mach/pwm-clock.h
rename to arch/arm/mach-s5p64x0/include/mach/pwm-clock.h
index 6a2a02fdf12a23df33ce6783c7a7181923348ddb..19fff8b701c0bf73126c93d9f1c33d6676a0b5ae 100644 (file)
@@ -1,16 +1,14 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/pwm-clock.h
+/* linux/arch/arm/mach-s5p64x0/include/mach/pwm-clock.h
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
  * Copyright 2008 Openmoko, Inc.
  * Copyright 2008 Simtec Electronics
  *      Ben Dooks <ben@simtec.co.uk>
  *      http://armlinux.simtec.co.uk/
  *
- * Based on arch/arm/mach-s3c64xx/include/mach/pwm-clock.h
- *
- * S5P6440 - pwm clock and timer support
+ * S5P64X0 - pwm clock and timer 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
diff --git a/arch/arm/mach-s5p64x0/include/mach/regs-clock.h b/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
new file mode 100644 (file)
index 0000000..58e1bc8
--- /dev/null
@@ -0,0 +1,63 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/regs-clock.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P64X0 - Clock register definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_REGS_CLOCK_H
+#define __ASM_ARCH_REGS_CLOCK_H __FILE__
+
+#include <mach/map.h>
+
+#define S5P_CLKREG(x)                  (S3C_VA_SYS + (x))
+
+#define S5P64X0_APLL_CON               S5P_CLKREG(0x0C)
+#define S5P64X0_MPLL_CON               S5P_CLKREG(0x10)
+#define S5P64X0_EPLL_CON               S5P_CLKREG(0x14)
+#define S5P64X0_EPLL_CON_K             S5P_CLKREG(0x18)
+
+#define S5P64X0_CLK_SRC0               S5P_CLKREG(0x1C)
+
+#define S5P64X0_CLK_DIV0               S5P_CLKREG(0x20)
+#define S5P64X0_CLK_DIV1               S5P_CLKREG(0x24)
+#define S5P64X0_CLK_DIV2               S5P_CLKREG(0x28)
+
+#define S5P64X0_CLK_GATE_HCLK0         S5P_CLKREG(0x30)
+#define S5P64X0_CLK_GATE_PCLK          S5P_CLKREG(0x34)
+#define S5P64X0_CLK_GATE_SCLK0         S5P_CLKREG(0x38)
+#define S5P64X0_CLK_GATE_MEM0          S5P_CLKREG(0x3C)
+
+#define S5P64X0_CLK_DIV3               S5P_CLKREG(0x40)
+
+#define S5P64X0_CLK_GATE_HCLK1         S5P_CLKREG(0x44)
+#define S5P64X0_CLK_GATE_SCLK1         S5P_CLKREG(0x48)
+
+#define S5P6450_DPLL_CON               S5P_CLKREG(0x50)
+#define S5P6450_DPLL_CON_K             S5P_CLKREG(0x54)
+
+#define S5P64X0_CLK_SRC1               S5P_CLKREG(0x10C)
+
+#define S5P64X0_SYS_ID                 S5P_CLKREG(0x118)
+#define S5P64X0_SYS_OTHERS             S5P_CLKREG(0x11C)
+
+#define S5P64X0_PWR_CFG                        S5P_CLKREG(0x804)
+#define S5P64X0_OTHERS                 S5P_CLKREG(0x900)
+
+#define S5P64X0_CLKDIV0_HCLK_SHIFT     (8)
+#define S5P64X0_CLKDIV0_HCLK_MASK      (0xF << S5P64X0_CLKDIV0_HCLK_SHIFT)
+
+#define S5P64X0_OTHERS_USB_SIG_MASK    (1 << 16)
+
+/* Compatibility defines */
+
+#define ARM_CLK_DIV                    S5P64X0_CLK_DIV0
+#define ARM_DIV_RATIO_SHIFT            0
+#define ARM_DIV_MASK                   (0xF << ARM_DIV_RATIO_SHIFT)
+
+#endif /* __ASM_ARCH_REGS_CLOCK_H */
similarity index 79%
rename from arch/arm/mach-s5p6440/include/mach/regs-gpio.h
rename to arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
index 82ff753913da73ccdc77f5dd2c6ebd4f560ffc3f..85f448e20a8b22cc537f3c844ac16e0612418f4f 100644 (file)
@@ -1,21 +1,24 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/regs-gpio.h
+/* linux/arch/arm/mach-s5p64x0/include/mach/regs-gpio.h
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
- * S5P6440 - GPIO register definitions
+ * S5P64X0 - GPIO register definitions
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
- */
+*/
 
 #ifndef __ASM_ARCH_REGS_GPIO_H
 #define __ASM_ARCH_REGS_GPIO_H __FILE__
 
 #include <mach/map.h>
 
+/* Will be implemented S5P6442 GPIOlib */
+
 /* Base addresses for each of the banks */
+
 #define S5P6440_GPA_BASE               (S5P_VA_GPIO + 0x0000)
 #define S5P6440_GPB_BASE               (S5P_VA_GPIO + 0x0020)
 #define S5P6440_GPC_BASE               (S5P_VA_GPIO + 0x0040)
@@ -27,6 +30,7 @@
 #define S5P6440_GPN_BASE               (S5P_VA_GPIO + 0x0830)
 #define S5P6440_GPP_BASE               (S5P_VA_GPIO + 0x0160)
 #define S5P6440_GPR_BASE               (S5P_VA_GPIO + 0x0290)
+
 #define S5P6440_EINT0CON0              (S5P_VA_GPIO + 0x900)
 #define S5P6440_EINT0FLTCON0           (S5P_VA_GPIO + 0x910)
 #define S5P6440_EINT0FLTCON1           (S5P_VA_GPIO + 0x914)
 #define S5P6440_EINT0PEND              (S5P_VA_GPIO + 0x924)
 
 /* for LCD */
+
 #define S5P6440_SPCON_LCD_SEL_RGB      (1 << 0)
 #define S5P6440_SPCON_LCD_SEL_MASK     (3 << 0)
 
-/* These set of macros are not really useful for the
- * GPF/GPI/GPJ/GPN/GPP,
- * useful for others set of GPIO's (4 bit)
+/*
+ * These set of macros are not really useful for the
+ * GPF/GPI/GPJ/GPN/GPP, useful for others set of GPIO's (4 bit)
  */
+
 #define S5P6440_GPIO_CONMASK(__gpio)   (0xf << ((__gpio) * 4))
 #define S5P6440_GPIO_INPUT(__gpio)     (0x0 << ((__gpio) * 4))
 #define S5P6440_GPIO_OUTPUT(__gpio)    (0x1 << ((__gpio) * 4))
 
-/* Use these macros for GPF/GPI/GPJ/GPN/GPP set of GPIO (2 bit)
- * */
+/*
+ * Use these macros for GPF/GPI/GPJ/GPN/GPP set of GPIO (2 bit)
+ */
+
 #define S5P6440_GPIO2_CONMASK(__gpio)  (0x3 << ((__gpio) * 2))
 #define S5P6440_GPIO2_INPUT(__gpio)    (0x0 << ((__gpio) * 2))
 #define S5P6440_GPIO2_OUTPUT(__gpio)   (0x1 << ((__gpio) * 2))
similarity index 66%
rename from arch/arm/mach-s5p6440/include/mach/regs-irq.h
rename to arch/arm/mach-s5p64x0/include/mach/regs-irq.h
index a961f4beeb0c2b3c0785c6cbdf4135e6803cd10d..4aaebdace55f9fe5b3cb86cd3bbf2e441f08391d 100644 (file)
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/regs-irq.h
+/* linux/arch/arm/mach-s5p64x0/include/mach/regs-irq.h
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
- * S5P6440 - IRQ register definitions
+ * S5P64X0 - IRQ register definitions
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h b/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
new file mode 100644 (file)
index 0000000..ff85b4b
--- /dev/null
@@ -0,0 +1,46 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/s5p64x0-clock.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Header file for s5p64x0 clock 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.
+*/
+
+#ifndef __ASM_ARCH_CLOCK_H
+#define __ASM_ARCH_CLOCK_H __FILE__
+
+#include <linux/clk.h>
+
+extern struct clksrc_clk clk_mout_apll;
+extern struct clksrc_clk clk_mout_mpll;
+extern struct clksrc_clk clk_mout_epll;
+
+extern int s5p64x0_epll_enable(struct clk *clk, int enable);
+extern unsigned long s5p64x0_epll_get_rate(struct clk *clk);
+
+extern unsigned long s5p64x0_armclk_get_rate(struct clk *clk);
+extern unsigned long s5p64x0_armclk_round_rate(struct clk *clk, unsigned long rate);
+extern int s5p64x0_armclk_set_rate(struct clk *clk, unsigned long rate);
+
+extern struct clk_ops s5p64x0_clkarm_ops;
+
+extern struct clksrc_clk clk_armclk;
+extern struct clksrc_clk clk_dout_mpll;
+
+extern struct clk *clkset_hclk_low_list[];
+extern struct clksrc_sources clkset_hclk_low;
+
+extern int s5p64x0_pclk_ctrl(struct clk *clk, int enable);
+extern int s5p64x0_hclk0_ctrl(struct clk *clk, int enable);
+extern int s5p64x0_hclk1_ctrl(struct clk *clk, int enable);
+extern int s5p64x0_sclk_ctrl(struct clk *clk, int enable);
+extern int s5p64x0_sclk1_ctrl(struct clk *clk, int enable);
+extern int s5p64x0_mem_ctrl(struct clk *clk, int enable);
+
+extern int s5p64x0_clk48m_ctrl(struct clk *clk, int enable);
+
+#endif /* __ASM_ARCH_CLOCK_H */
diff --git a/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h b/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
new file mode 100644 (file)
index 0000000..170a20a
--- /dev/null
@@ -0,0 +1,20 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/spi-clocks.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Copyright (C) 2010 Samsung Electronics Co. Ltd.
+ *     Jaswinder Singh <jassi.brar@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __ASM_ARCH_SPI_CLKS_H
+#define __ASM_ARCH_SPI_CLKS_H __FILE__
+
+#define S5P64X0_SPI_SRCCLK_PCLK                0
+#define S5P64X0_SPI_SRCCLK_SCLK                1
+
+#endif /* __ASM_ARCH_SPI_CLKS_H */
similarity index 69%
rename from arch/arm/mach-s5p6440/include/mach/system.h
rename to arch/arm/mach-s5p64x0/include/mach/system.h
index a359ee3fa51083b6b0314e67b16506e522ec2398..60f57532c970eca7f1c140156bcbbc2de069bb5a 100644 (file)
@@ -1,9 +1,9 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/system.h
+/* linux/arch/arm/mach-s5p64x0/include/mach/system.h
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
- * S5P6440 - system support header
+ * S5P64X0 - system support header
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
similarity index 60%
rename from arch/arm/mach-s5p6440/include/mach/tick.h
rename to arch/arm/mach-s5p64x0/include/mach/tick.h
index 2f25c7f079700bbe8c268ac65533cfbfe7388d35..00aa7f1d8e51c803e16a970df1f8b1d6b5322d6b 100644 (file)
@@ -1,9 +1,14 @@
-/* linux/arch/arm/mach-s5p6440/include/mach/tick.h
+/* linux/arch/arm/mach-s5p64x0/include/mach/tick.h
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
- * S5P6440 - Timer tick support definitions
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ *     http://armlinux.simtec.co.uk/
+ *     Ben Dooks <ben@simtec.co.uk>
+ *
+ * S5P64X0 - Timer tick support definitions
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
similarity index 80%
rename from arch/arm/mach-s5p6440/include/mach/timex.h
rename to arch/arm/mach-s5p64x0/include/mach/timex.h
index fb2e8cd4082931255fa4df5dad45a23d4939b002..4b91faa195a85546d03f68e3c97d1dfdc7f7903f 100644 (file)
@@ -1,9 +1,12 @@
-/* arch/arm/mach-s3c64xx/include/mach/timex.h
+/* linux/arch/arm/mach-s5p64x0/include/mach/timex.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
  * Copyright (c) 2003-2005 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
- * S3C6400 - time parameters
+ * S5P64X0 - time parameters
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/arch/arm/mach-s5p64x0/include/mach/uncompress.h b/arch/arm/mach-s5p64x0/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..c65b229
--- /dev/null
@@ -0,0 +1,212 @@
+/* linux/arch/arm/mach-s5p64x0/include/mach/uncompress.h
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P64X0 - uncompress 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.
+*/
+
+#ifndef __ASM_ARCH_UNCOMPRESS_H
+#define __ASM_ARCH_UNCOMPRESS_H
+
+#include <mach/map.h>
+
+/*
+ * cannot use commonly <plat/uncompress.h>
+ * because uart base of S5P6440 and S5P6450 is different
+ */
+
+typedef unsigned int upf_t;    /* cannot include linux/serial_core.h */
+
+/* uart setup */
+
+static unsigned int fifo_mask;
+static unsigned int fifo_max;
+
+/* forward declerations */
+
+static void arch_detect_cpu(void);
+
+/* defines for UART registers */
+
+#include <plat/regs-serial.h>
+#include <plat/regs-watchdog.h>
+
+/* working in physical space... */
+#undef S3C2410_WDOGREG
+#define S3C2410_WDOGREG(x) ((S3C24XX_PA_WATCHDOG + (x)))
+
+/* how many bytes we allow into the FIFO at a time in FIFO mode */
+#define FIFO_MAX        (14)
+
+static unsigned long uart_base;
+
+static __inline__ void get_uart_base(void)
+{
+       unsigned int chipid;
+
+       chipid = *(const volatile unsigned int __force *) 0xE0100118;
+
+       uart_base = S3C_UART_OFFSET * CONFIG_S3C_LOWLEVEL_UART_PORT;
+
+       if ((chipid & 0xff000) == 0x50000)
+               uart_base += 0xEC800000;
+       else
+               uart_base += 0xEC000000;
+}
+
+static __inline__ void uart_wr(unsigned int reg, unsigned int val)
+{
+       volatile unsigned int *ptr;
+
+       get_uart_base();
+       ptr = (volatile unsigned int *)(reg + uart_base);
+       *ptr = val;
+}
+
+static __inline__ unsigned int uart_rd(unsigned int reg)
+{
+       volatile unsigned int *ptr;
+
+       get_uart_base();
+       ptr = (volatile unsigned int *)(reg + uart_base);
+       return *ptr;
+}
+
+/*
+ * we can deal with the case the UARTs are being run
+ * in FIFO mode, so that we don't hold up our execution
+ * waiting for tx to happen...
+ */
+
+static void putc(int ch)
+{
+       if (uart_rd(S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE) {
+               int level;
+
+               while (1) {
+                       level = uart_rd(S3C2410_UFSTAT);
+                       level &= fifo_mask;
+
+                       if (level < fifo_max)
+                               break;
+               }
+
+       } else {
+               /* not using fifos */
+
+               while ((uart_rd(S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE) != S3C2410_UTRSTAT_TXE)
+                       barrier();
+       }
+
+       /* write byte to transmission register */
+       uart_wr(S3C2410_UTXH, ch);
+}
+
+static inline void flush(void)
+{
+}
+
+#define __raw_writel(d, ad)                    \
+       do {                                                    \
+               *((volatile unsigned int __force *)(ad)) = (d); \
+       } while (0)
+
+/*
+ * CONFIG_S3C_BOOT_WATCHDOG
+ *
+ * Simple boot-time watchdog setup, to reboot the system if there is
+ * any problem with the boot process
+ */
+
+#ifdef CONFIG_S3C_BOOT_WATCHDOG
+
+#define WDOG_COUNT (0xff00)
+
+static inline void arch_decomp_wdog(void)
+{
+       __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
+}
+
+static void arch_decomp_wdog_start(void)
+{
+       __raw_writel(WDOG_COUNT, S3C2410_WTDAT);
+       __raw_writel(WDOG_COUNT, S3C2410_WTCNT);
+       __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x80), S3C2410_WTCON);
+}
+
+#else
+#define arch_decomp_wdog_start()
+#define arch_decomp_wdog()
+#endif
+
+#ifdef CONFIG_S3C_BOOT_ERROR_RESET
+
+static void arch_decomp_error(const char *x)
+{
+       putstr("\n\n");
+       putstr(x);
+       putstr("\n\n -- System resetting\n");
+
+       __raw_writel(0x4000, S3C2410_WTDAT);
+       __raw_writel(0x4000, S3C2410_WTCNT);
+       __raw_writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x40), S3C2410_WTCON);
+
+       while(1);
+}
+
+#define arch_error arch_decomp_error
+#endif
+
+#ifdef CONFIG_S3C_BOOT_UART_FORCE_FIFO
+static inline void arch_enable_uart_fifo(void)
+{
+       u32 fifocon = uart_rd(S3C2410_UFCON);
+
+       if (!(fifocon & S3C2410_UFCON_FIFOMODE)) {
+               fifocon |= S3C2410_UFCON_RESETBOTH;
+               uart_wr(S3C2410_UFCON, fifocon);
+
+               /* wait for fifo reset to complete */
+               while (1) {
+                       fifocon = uart_rd(S3C2410_UFCON);
+                       if (!(fifocon & S3C2410_UFCON_RESETBOTH))
+                               break;
+               }
+       }
+}
+#else
+#define arch_enable_uart_fifo() do { } while(0)
+#endif
+
+static void arch_decomp_setup(void)
+{
+       /*
+        * we may need to setup the uart(s) here if we are not running
+        * on an BAST... the BAST will have left the uarts configured
+        * after calling linux.
+        */
+
+       arch_detect_cpu();
+       arch_decomp_wdog_start();
+
+       /*
+        * Enable the UART FIFOs if they where not enabled and our
+        * configuration says we should turn them on.
+        */
+
+       arch_enable_uart_fifo();
+}
+
+
+
+static void arch_detect_cpu(void)
+{
+       /* we do not need to do any cpu detection here at the moment. */
+}
+
+#endif /* __ASM_ARCH_UNCOMPRESS_H */
similarity index 74%
rename from arch/arm/mach-s5p6440/include/mach/vmalloc.h
rename to arch/arm/mach-s5p64x0/include/mach/vmalloc.h
index e3f0eebf5205b592724f9de4b5cd5fda2670396c..97a9df38f1cf5ef2438cce77a77f95c5cfad88c7 100644 (file)
@@ -1,4 +1,7 @@
-/* arch/arm/mach-s5p6440/include/mach/vmalloc.h
+/* linux/arch/arm/mach-s5p64x0/include/mach/vmalloc.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
  * Copyright 2010 Ben Dooks <ben-linux@fluff.org>
  *
diff --git a/arch/arm/mach-s5p64x0/init.c b/arch/arm/mach-s5p64x0/init.c
new file mode 100644 (file)
index 0000000..79833ca
--- /dev/null
@@ -0,0 +1,73 @@
+/* linux/arch/arm/mach-s5p64x0/init.c
+ *
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * S5P64X0 - Init support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+
+#include <mach/map.h>
+
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/s5p6440.h>
+#include <plat/s5p6450.h>
+#include <plat/regs-serial.h>
+
+static struct s3c24xx_uart_clksrc s5p64x0_serial_clocks[] = {
+       [0] = {
+               .name           = "pclk_low",
+               .divisor        = 1,
+               .min_baud       = 0,
+               .max_baud       = 0,
+       },
+       [1] = {
+               .name           = "uclk1",
+               .divisor        = 1,
+               .min_baud       = 0,
+               .max_baud       = 0,
+       },
+};
+
+/* uart registration process */
+
+void __init s5p64x0_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       struct s3c2410_uartcfg *tcfg = cfg;
+       u32 ucnt;
+
+       for (ucnt = 0; ucnt < no; ucnt++, tcfg++) {
+               if (!tcfg->clocks) {
+                       tcfg->clocks = s5p64x0_serial_clocks;
+                       tcfg->clocks_size = ARRAY_SIZE(s5p64x0_serial_clocks);
+               }
+       }
+}
+
+void __init s5p6440_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       int uart;
+
+       for (uart = 0; uart < no; uart++) {
+               s5p_uart_resources[uart].resources->start = S5P6440_PA_UART(uart);
+               s5p_uart_resources[uart].resources->end = S5P6440_PA_UART(uart) + S5P_SZ_UART;
+       }
+
+       s5p64x0_common_init_uarts(cfg, no);
+       s3c24xx_init_uartdevs("s3c6400-uart", s5p_uart_resources, cfg, no);
+}
+
+void __init s5p6450_init_uarts(struct s3c2410_uartcfg *cfg, int no)
+{
+       s5p64x0_common_init_uarts(cfg, no);
+       s3c24xx_init_uartdevs("s3c6400-uart", s5p_uart_resources, cfg, no);
+}
similarity index 67%
rename from arch/arm/mach-s5p6440/mach-smdk6440.c
rename to arch/arm/mach-s5p64x0/mach-smdk6440.c
index 9202aaac3b566d5f41f39fcc27ebcda01c007285..87c3f03c618c4c7057e052b89909df24711e91ad 100644 (file)
@@ -1,7 +1,7 @@
-/* linux/arch/arm/mach-s5p6440/mach-smdk6440.c
+/* linux/arch/arm/mach-s5p64x0/mach-smdk6440.c
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/clk.h>
+#include <linux/gpio.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
 
 #include <mach/hardware.h>
 #include <mach/map.h>
-
-#include <asm/irq.h>
-#include <asm/mach-types.h>
+#include <mach/regs-clock.h>
+#include <mach/i2c.h>
 
 #include <plat/regs-serial.h>
-
+#include <plat/gpio-cfg.h>
 #include <plat/s5p6440.h>
 #include <plat/clock.h>
-#include <mach/regs-clock.h>
 #include <plat/devs.h>
 #include <plat/cpu.h>
 #include <plat/iic.h>
 
 static struct s3c2410_uartcfg smdk6440_uartcfgs[] __initdata = {
        [0] = {
-               .hwport      = 0,
-               .flags       = 0,
-               .ucon        = SMDK6440_UCON_DEFAULT,
-               .ulcon       = SMDK6440_ULCON_DEFAULT,
-               .ufcon       = SMDK6440_UFCON_DEFAULT,
+               .hwport         = 0,
+               .flags          = 0,
+               .ucon           = SMDK6440_UCON_DEFAULT,
+               .ulcon          = SMDK6440_ULCON_DEFAULT,
+               .ufcon          = SMDK6440_UFCON_DEFAULT,
        },
        [1] = {
-               .hwport      = 1,
-               .flags       = 0,
-               .ucon        = SMDK6440_UCON_DEFAULT,
-               .ulcon       = SMDK6440_ULCON_DEFAULT,
-               .ufcon       = SMDK6440_UFCON_DEFAULT,
+               .hwport         = 1,
+               .flags          = 0,
+               .ucon           = SMDK6440_UCON_DEFAULT,
+               .ulcon          = SMDK6440_ULCON_DEFAULT,
+               .ufcon          = SMDK6440_UFCON_DEFAULT,
        },
        [2] = {
-               .hwport      = 2,
-               .flags       = 0,
-               .ucon        = SMDK6440_UCON_DEFAULT,
-               .ulcon       = SMDK6440_ULCON_DEFAULT,
-               .ufcon       = SMDK6440_UFCON_DEFAULT,
+               .hwport         = 2,
+               .flags          = 0,
+               .ucon           = SMDK6440_UCON_DEFAULT,
+               .ulcon          = SMDK6440_ULCON_DEFAULT,
+               .ufcon          = SMDK6440_UFCON_DEFAULT,
        },
        [3] = {
-               .hwport      = 3,
-               .flags       = 0,
-               .ucon        = SMDK6440_UCON_DEFAULT,
-               .ulcon       = SMDK6440_ULCON_DEFAULT,
-               .ufcon       = SMDK6440_UFCON_DEFAULT,
+               .hwport         = 3,
+               .flags          = 0,
+               .ucon           = SMDK6440_UCON_DEFAULT,
+               .ulcon          = SMDK6440_ULCON_DEFAULT,
+               .ufcon          = SMDK6440_UFCON_DEFAULT,
        },
 };
 
 static struct platform_device *smdk6440_devices[] __initdata = {
-       &s5p6440_device_iis,
        &s3c_device_adc,
        &s3c_device_rtc,
        &s3c_device_i2c0,
        &s3c_device_i2c1,
        &s3c_device_ts,
        &s3c_device_wdt,
+       &s5p6440_device_iis,
+};
+
+static struct s3c2410_platform_i2c s5p6440_i2c0_data __initdata = {
+       .flags          = 0,
+       .slave_addr     = 0x10,
+       .frequency      = 100*1000,
+       .sda_delay      = 100,
+       .cfg_gpio       = s5p6440_i2c0_cfg_gpio,
+};
+
+static struct s3c2410_platform_i2c s5p6440_i2c1_data __initdata = {
+       .flags          = 0,
+       .bus_num        = 1,
+       .slave_addr     = 0x10,
+       .frequency      = 100*1000,
+       .sda_delay      = 100,
+       .cfg_gpio       = s5p6440_i2c1_cfg_gpio,
 };
 
 static struct i2c_board_info smdk6440_i2c_devs0[] __initdata = {
@@ -113,7 +131,7 @@ static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
 
 static void __init smdk6440_map_io(void)
 {
-       s5p_init_io(NULL, 0, S5P_SYS_ID);
+       s5p_init_io(NULL, 0, S5P64X0_SYS_ID);
        s3c24xx_init_clocks(12000000);
        s3c24xx_init_uarts(smdk6440_uartcfgs, ARRAY_SIZE(smdk6440_uartcfgs));
 }
@@ -122,9 +140,8 @@ static void __init smdk6440_machine_init(void)
 {
        s3c24xx_ts_set_platdata(&s3c_ts_platform);
 
-       /* I2C */
-       s3c_i2c0_set_platdata(NULL);
-       s3c_i2c1_set_platdata(NULL);
+       s3c_i2c0_set_platdata(&s5p6440_i2c0_data);
+       s3c_i2c1_set_platdata(&s5p6440_i2c1_data);
        i2c_register_board_info(0, smdk6440_i2c_devs0,
                        ARRAY_SIZE(smdk6440_i2c_devs0));
        i2c_register_board_info(1, smdk6440_i2c_devs1,
@@ -135,9 +152,7 @@ static void __init smdk6440_machine_init(void)
 
 MACHINE_START(SMDK6440, "SMDK6440")
        /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
-       .phys_io        = S3C_PA_UART & 0xfff00000,
-       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
-       .boot_params    = S5P_PA_SDRAM + 0x100,
+       .boot_params    = S5P64X0_PA_SDRAM + 0x100,
 
        .init_irq       = s5p6440_init_irq,
        .map_io         = smdk6440_map_io,
diff --git a/arch/arm/mach-s5p64x0/mach-smdk6450.c b/arch/arm/mach-s5p64x0/mach-smdk6450.c
new file mode 100644 (file)
index 0000000..d609f5a
--- /dev/null
@@ -0,0 +1,180 @@
+/* linux/arch/arm/mach-s5p64x0/mach-smdk6450.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/serial_core.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <mach/hardware.h>
+#include <mach/map.h>
+#include <mach/regs-clock.h>
+#include <mach/i2c.h>
+
+#include <plat/regs-serial.h>
+#include <plat/gpio-cfg.h>
+#include <plat/s5p6450.h>
+#include <plat/clock.h>
+#include <plat/devs.h>
+#include <plat/cpu.h>
+#include <plat/iic.h>
+#include <plat/pll.h>
+#include <plat/adc.h>
+#include <plat/ts.h>
+
+#define SMDK6450_UCON_DEFAULT  (S3C2410_UCON_TXILEVEL |        \
+                               S3C2410_UCON_RXILEVEL |         \
+                               S3C2410_UCON_TXIRQMODE |        \
+                               S3C2410_UCON_RXIRQMODE |        \
+                               S3C2410_UCON_RXFIFO_TOI |       \
+                               S3C2443_UCON_RXERR_IRQEN)
+
+#define SMDK6450_ULCON_DEFAULT S3C2410_LCON_CS8
+
+#define SMDK6450_UFCON_DEFAULT (S3C2410_UFCON_FIFOMODE |       \
+                               S3C2440_UFCON_TXTRIG16 |        \
+                               S3C2410_UFCON_RXTRIG8)
+
+static struct s3c2410_uartcfg smdk6450_uartcfgs[] __initdata = {
+       [0] = {
+               .hwport         = 0,
+               .flags          = 0,
+               .ucon           = SMDK6450_UCON_DEFAULT,
+               .ulcon          = SMDK6450_ULCON_DEFAULT,
+               .ufcon          = SMDK6450_UFCON_DEFAULT,
+       },
+       [1] = {
+               .hwport         = 1,
+               .flags          = 0,
+               .ucon           = SMDK6450_UCON_DEFAULT,
+               .ulcon          = SMDK6450_ULCON_DEFAULT,
+               .ufcon          = SMDK6450_UFCON_DEFAULT,
+       },
+       [2] = {
+               .hwport         = 2,
+               .flags          = 0,
+               .ucon           = SMDK6450_UCON_DEFAULT,
+               .ulcon          = SMDK6450_ULCON_DEFAULT,
+               .ufcon          = SMDK6450_UFCON_DEFAULT,
+       },
+       [3] = {
+               .hwport         = 3,
+               .flags          = 0,
+               .ucon           = SMDK6450_UCON_DEFAULT,
+               .ulcon          = SMDK6450_ULCON_DEFAULT,
+               .ufcon          = SMDK6450_UFCON_DEFAULT,
+       },
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 4
+       [4] = {
+               .hwport         = 4,
+               .flags          = 0,
+               .ucon           = SMDK6450_UCON_DEFAULT,
+               .ulcon          = SMDK6450_ULCON_DEFAULT,
+               .ufcon          = SMDK6450_UFCON_DEFAULT,
+       },
+#endif
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 5
+       [5] = {
+               .hwport         = 5,
+               .flags          = 0,
+               .ucon           = SMDK6450_UCON_DEFAULT,
+               .ulcon          = SMDK6450_ULCON_DEFAULT,
+               .ufcon          = SMDK6450_UFCON_DEFAULT,
+       },
+#endif
+};
+
+static struct platform_device *smdk6450_devices[] __initdata = {
+       &s3c_device_adc,
+       &s3c_device_rtc,
+       &s3c_device_i2c0,
+       &s3c_device_i2c1,
+       &s3c_device_ts,
+       &s3c_device_wdt,
+       &s5p6450_device_iis0,
+       /* s5p6450_device_spi0 will be added */
+};
+
+static struct s3c2410_platform_i2c s5p6450_i2c0_data __initdata = {
+       .flags          = 0,
+       .slave_addr     = 0x10,
+       .frequency      = 100*1000,
+       .sda_delay      = 100,
+       .cfg_gpio       = s5p6450_i2c0_cfg_gpio,
+};
+
+static struct s3c2410_platform_i2c s5p6450_i2c1_data __initdata = {
+       .flags          = 0,
+       .bus_num        = 1,
+       .slave_addr     = 0x10,
+       .frequency      = 100*1000,
+       .sda_delay      = 100,
+       .cfg_gpio       = s5p6450_i2c1_cfg_gpio,
+};
+
+static struct i2c_board_info smdk6450_i2c_devs0[] __initdata = {
+       { I2C_BOARD_INFO("24c08", 0x50), },     /* Samsung KS24C080C EEPROM */
+};
+
+static struct i2c_board_info smdk6450_i2c_devs1[] __initdata = {
+       { I2C_BOARD_INFO("24c128", 0x57), },/* Samsung S524AD0XD1 EEPROM */
+};
+
+static struct s3c2410_ts_mach_info s3c_ts_platform __initdata = {
+       .delay                  = 10000,
+       .presc                  = 49,
+       .oversampling_shift     = 2,
+};
+
+static void __init smdk6450_map_io(void)
+{
+       s5p_init_io(NULL, 0, S5P64X0_SYS_ID);
+       s3c24xx_init_clocks(19200000);
+       s3c24xx_init_uarts(smdk6450_uartcfgs, ARRAY_SIZE(smdk6450_uartcfgs));
+}
+
+static void __init smdk6450_machine_init(void)
+{
+       s3c24xx_ts_set_platdata(&s3c_ts_platform);
+
+       s3c_i2c0_set_platdata(&s5p6450_i2c0_data);
+       s3c_i2c1_set_platdata(&s5p6450_i2c1_data);
+       i2c_register_board_info(0, smdk6450_i2c_devs0,
+                       ARRAY_SIZE(smdk6450_i2c_devs0));
+       i2c_register_board_info(1, smdk6450_i2c_devs1,
+                       ARRAY_SIZE(smdk6450_i2c_devs1));
+
+       platform_add_devices(smdk6450_devices, ARRAY_SIZE(smdk6450_devices));
+}
+
+MACHINE_START(SMDK6450, "SMDK6450")
+       /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
+       .boot_params    = S5P64X0_PA_SDRAM + 0x100,
+
+       .init_irq       = s5p6450_init_irq,
+       .map_io         = smdk6450_map_io,
+       .init_machine   = smdk6450_machine_init,
+       .timer          = &s3c24xx_timer,
+MACHINE_END
similarity index 52%
rename from arch/arm/mach-s5p6440/setup-i2c0.c
rename to arch/arm/mach-s5p64x0/setup-i2c0.c
index 2c99d14f7ac7bd55cccd8adc42eccfffdde600d8..dc4cc65a5019c3ba74321dc3fd78247003df6cae 100644 (file)
@@ -1,11 +1,11 @@
-/* linux/arch/arm/mach-s5p6440/setup-i2c0.c
+/* linux/arch/arm/mach-s5p64x0/setup-i2c0.c
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
  * I2C0 GPIO configuration.
  *
- * Based on plat-s3c64xx/setup-i2c0.c
+ * Based on plat-s3c64x0/setup-i2c0.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
 
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/gpio.h>
 
 struct platform_device; /* don't need the contents */
 
-#include <linux/gpio.h>
 #include <plat/gpio-cfg.h>
 #include <plat/iic.h>
 
-void s3c_i2c0_cfg_gpio(struct platform_device *dev)
+#include <mach/i2c.h>
+
+void s5p6440_i2c0_cfg_gpio(struct platform_device *dev)
 {
        s3c_gpio_cfgpin(S5P6440_GPB(5), S3C_GPIO_SFN(2));
        s3c_gpio_setpull(S5P6440_GPB(5), S3C_GPIO_PULL_UP);
        s3c_gpio_cfgpin(S5P6440_GPB(6), S3C_GPIO_SFN(2));
        s3c_gpio_setpull(S5P6440_GPB(6), S3C_GPIO_PULL_UP);
 }
+
+void s5p6450_i2c0_cfg_gpio(struct platform_device *dev)
+{
+       s3c_gpio_cfgpin(S5P6450_GPB(5), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5P6450_GPB(5), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5P6450_GPB(6), S3C_GPIO_SFN(2));
+       s3c_gpio_setpull(S5P6450_GPB(6), S3C_GPIO_PULL_UP);
+}
+
+void s3c_i2c0_cfg_gpio(struct platform_device *dev) { }
similarity index 55%
rename from arch/arm/mach-s5p6440/setup-i2c1.c
rename to arch/arm/mach-s5p64x0/setup-i2c1.c
index 9a1537f786e0e793f2dfbaf4fa60286cf9cbb364..2edd7912f8e405afa674b17d02e0f6a93d1ea04d 100644 (file)
@@ -1,7 +1,7 @@
-/* linux/arch/arm/mach-s5p6440/setup-i2c1.c
+/* linux/arch/arm/mach-s5p64xx/setup-i2c1.c
  *
- * Copyright (c) 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
  * I2C1 GPIO configuration.
  *
@@ -21,10 +21,22 @@ struct platform_device; /* don't need the contents */
 #include <plat/gpio-cfg.h>
 #include <plat/iic.h>
 
-void s3c_i2c1_cfg_gpio(struct platform_device *dev)
+#include <mach/i2c.h>
+
+void s5p6440_i2c1_cfg_gpio(struct platform_device *dev)
 {
        s3c_gpio_cfgpin(S5P6440_GPR(9), S3C_GPIO_SFN(6));
        s3c_gpio_setpull(S5P6440_GPR(9), S3C_GPIO_PULL_UP);
        s3c_gpio_cfgpin(S5P6440_GPR(10), S3C_GPIO_SFN(6));
        s3c_gpio_setpull(S5P6440_GPR(10), S3C_GPIO_PULL_UP);
 }
+
+void s5p6450_i2c1_cfg_gpio(struct platform_device *dev)
+{
+       s3c_gpio_cfgpin(S5P6450_GPR(9), S3C_GPIO_SFN(6));
+       s3c_gpio_setpull(S5P6450_GPR(9), S3C_GPIO_PULL_UP);
+       s3c_gpio_cfgpin(S5P6450_GPR(10), S3C_GPIO_SFN(6));
+       s3c_gpio_setpull(S5P6450_GPR(10), S3C_GPIO_PULL_UP);
+}
+
+void s3c_i2c1_cfg_gpio(struct platform_device *dev) { }
index cd1afbce83e2cfa6d006d6084e384e1705408be8..fd2708e7d8a9f4aa61bf645abad7f644149720e7 100644 (file)
@@ -1,4 +1,7 @@
 /* linux/arch/arm/mach-s5pc100/cpu.c
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
  * Copyright 2009 Samsung Electronics Co.
  *     Byungho Min <bhmin@samsung.com>
@@ -56,11 +59,31 @@ static struct map_desc s5pc100_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(S5PC100_PA_SYSTIMER),
                .length         = SZ_16K,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_GPIO,
+               .pfn            = __phys_to_pfn(S5PC100_PA_GPIO),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)VA_VIC0,
+               .pfn            = __phys_to_pfn(S5PC100_PA_VIC0),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)VA_VIC1,
+               .pfn            = __phys_to_pfn(S5PC100_PA_VIC1),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)VA_VIC2,
-               .pfn            = __phys_to_pfn(S5P_PA_VIC2),
+               .pfn            = __phys_to_pfn(S5PC100_PA_VIC2),
                .length         = SZ_16K,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_UART,
+               .pfn            = __phys_to_pfn(S3C_PA_UART),
+               .length         = SZ_512K,
+               .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)S5PC100_VA_OTHERS,
                .pfn            = __phys_to_pfn(S5PC100_PA_OTHERS),
index 70e02e91ee3c99602b2864f5a07cd8da820f8d32..b2ba95ddf8e06a0259288804160cc255bd18f8e6 100644 (file)
         * aligned and add in the offset when we load the value here.
         */
 
-       .macro addruart, rx, rtmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1
-               ldreq   \rx, = S3C_PA_UART
-               ldrne   \rx, = S3C_VA_UART
+       .macro addruart, rp, rv
+               ldr     \rp, = S3C_PA_UART
+               ldr     \rv, = S3C_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-               add     \rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
+               add     \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
+               add     \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
 #endif
        .endm
 
index 01b9134feff0d055fd33418f7b07bc68c000b885..8751ef4a6804d481d3f1d4ae2c5842dd88f4635a 100644 (file)
 #define S5PC100_PA_OTHERS      (0xE0200000)
 #define S5PC100_VA_OTHERS      (S3C_VA_SYS + 0x10000)
 
-#define S5P_PA_GPIO            (0xE0300000)
+#define S5PC100_PA_GPIO                (0xE0300000)
 #define S5PC1XX_VA_GPIO                S3C_ADDR(0x00500000)
 
 /* Interrupt */
-#define S5PC100_PA_VIC         (0xE4000000)
+#define S5PC100_PA_VIC0                (0xE4000000)
+#define S5PC100_PA_VIC1                (0xE4100000)
+#define S5PC100_PA_VIC2                (0xE4200000)
 #define S5PC100_VA_VIC         S3C_VA_IRQ
-#define S5PC100_PA_VIC_OFFSET  0x100000
 #define S5PC100_VA_VIC_OFFSET  0x10000
-#define S5PC1XX_PA_VIC(x)      (S5PC100_PA_VIC + ((x) * S5PC100_PA_VIC_OFFSET))
 #define S5PC1XX_VA_VIC(x)      (S5PC100_VA_VIC + ((x) * S5PC100_VA_VIC_OFFSET))
-#define S5P_PA_VIC0            S5PC1XX_PA_VIC(0)
-#define S5P_PA_VIC1            S5PC1XX_PA_VIC(1)
-#define S5P_PA_VIC2            S5PC1XX_PA_VIC(2)
 
 
 #define S5PC100_PA_ONENAND     (0xE7100000)
index 020c3f98f81fa0237f2c82b9694dc6a358c1c4fb..880fb075092cf3d65ed3fb7236652cb7a737caf0 100644 (file)
@@ -235,8 +235,6 @@ static void __init smdkc100_machine_init(void)
 
 MACHINE_START(SMDKC100, "SMDKC100")
        /* Maintainer: Byungho Min <bhmin@samsung.com> */
-       .phys_io        = S3C_PA_UART & 0xfff00000,
-       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S5P_PA_SDRAM + 0x100,
        .init_irq       = s5pc100_init_irq,
        .map_io         = smdkc100_map_io,
index d3a38955c7418cc626e6bfea534613b090bb0262..5315fec3db86ae31df32ff0629a91e913b66a502 100644 (file)
@@ -53,11 +53,6 @@ config S5PV210_SETUP_SDHCI_GPIO
        help
          Common setup code for SDHCI gpio.
 
-config S5PC110_DEV_ONENAND
-       bool
-       help
-         Compile in platform device definition for OneNAND1 controller
-
 menu "S5PC110 Machines"
 
 config MACH_AQUILA
@@ -71,7 +66,7 @@ config MACH_AQUILA
        select S3C_DEV_HSMMC
        select S3C_DEV_HSMMC1
        select S3C_DEV_HSMMC2
-       select S5PC110_DEV_ONENAND
+       select S5P_DEV_ONENAND
        select S5PV210_SETUP_FB_24BPP
        select S5PV210_SETUP_SDHCI
        help
@@ -88,7 +83,7 @@ config MACH_GONI
        select S3C_DEV_HSMMC
        select S3C_DEV_HSMMC1
        select S3C_DEV_HSMMC2
-       select S5PC110_DEV_ONENAND
+       select S5P_DEV_ONENAND
        select S5PV210_SETUP_FB_24BPP
        select S5PV210_SETUP_SDHCI
        help
index 05048c5aa4c6e7e7e8eb94d435b9cb8c2243ddbd..7045489124082d69715df5c9f4ec62061738763b 100644 (file)
@@ -26,7 +26,6 @@ obj-$(CONFIG_MACH_GONI)               += mach-goni.o
 
 obj-y                          += dev-audio.o
 obj-$(CONFIG_S3C64XX_DEV_SPI)  += dev-spi.o
-obj-$(CONFIG_S5PC110_DEV_ONENAND) += dev-onenand.o
 
 obj-$(CONFIG_S5PV210_SETUP_FB_24BPP)   += setup-fb-24bpp.o
 obj-$(CONFIG_S5PV210_SETUP_I2C1)       += setup-i2c1.o
index 245b82b53df4612d63d45984659e2221605d124f..2f16bfc0a116cd4bde8298b8c83ed4f076145080 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/arch/arm/mach-s5pv210/cpu.c
  *
  * Copyright (c) 2010 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ *             http://www.samsung.com
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -50,6 +50,21 @@ static struct map_desc s5pv210_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(S5PV210_PA_SYSTIMER),
                .length         = SZ_4K,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_GPIO,
+               .pfn            = __phys_to_pfn(S5PV210_PA_GPIO),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)VA_VIC0,
+               .pfn            = __phys_to_pfn(S5PV210_PA_VIC0),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)VA_VIC1,
+               .pfn            = __phys_to_pfn(S5PV210_PA_VIC1),
+               .length         = SZ_16K,
+               .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)VA_VIC2,
                .pfn            = __phys_to_pfn(S5PV210_PA_VIC2),
@@ -60,6 +75,11 @@ static struct map_desc s5pv210_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(S5PV210_PA_VIC3),
                .length         = SZ_16K,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S3C_VA_UART,
+               .pfn            = __phys_to_pfn(S3C_PA_UART),
+               .length         = SZ_512K,
+               .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)S5P_VA_SROMC,
                .pfn            = __phys_to_pfn(S5PV210_PA_SROMC),
index 7872f5c3dfc24271fb1853d8a6e86a7ad79ff051..169fe654a59eac3c2dfd91cf33c0d29d1fc8e50c 100644 (file)
         * aligned and add in the offset when we load the value here.
         */
 
-       .macro addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1
-               ldreq   \rx, = S3C_PA_UART
-               ldrne   \rx, = S3C_VA_UART
+       .macro addruart, rp, rv
+               ldr     \rp, = S3C_PA_UART
+               ldr     \rv, = S3C_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-               add     \rx, \rx, #(0x400 * CONFIG_DEBUG_S3C_UART)
+               add     \rp, \rp, #(0x400 * CONFIG_DEBUG_S3C_UART)
+               add     \rv, \rv, #(0x400 * CONFIG_DEBUG_S3C_UART)
 #endif
        .endm
 
index dd4fb6bf14b506a463fb77de68d78baa85c41106..bd9afd52466ad2cb787ed90ba394cc1f73870cb0 100644 (file)
 #include <plat/map-s5p.h>
 
 #define S5PC110_PA_ONENAND     (0xB0000000)
+#define S5P_PA_ONENAND         S5PC110_PA_ONENAND
+
 #define S5PC110_PA_ONENAND_DMA (0xB0600000)
+#define S5P_PA_ONENAND_DMA     S5PC110_PA_ONENAND_DMA
 
 #define S5PV210_PA_CHIPID      (0xE0000000)
 #define S5P_PA_CHIPID          S5PV210_PA_CHIPID
@@ -26,7 +29,6 @@
 #define S5P_PA_SYSCON          S5PV210_PA_SYSCON
 
 #define S5PV210_PA_GPIO                (0xE0200000)
-#define S5P_PA_GPIO            S5PV210_PA_GPIO
 
 /* SPI */
 #define S5PV210_PA_SPI0                0xE1300000
 #define S5PV210_PA_HSMMC(x)    (0xEB000000 + ((x) * 0x100000))
 
 #define S5PV210_PA_VIC0                (0xF2000000)
-#define S5P_PA_VIC0            S5PV210_PA_VIC0
-
 #define S5PV210_PA_VIC1                (0xF2100000)
-#define S5P_PA_VIC1            S5PV210_PA_VIC1
-
 #define S5PV210_PA_VIC2                (0xF2200000)
-#define S5P_PA_VIC2            S5PV210_PA_VIC2
-
 #define S5PV210_PA_VIC3                (0xF2300000)
-#define S5P_PA_VIC3            S5PV210_PA_VIC3
 
 #define S5PV210_PA_SDRAM       (0x20000000)
 #define S5P_PA_SDRAM           S5PV210_PA_SDRAM
index 0dda8012d6b22c029a6da035a19a934c6092e5e3..00883087363c9229acde4d81e96e7d43668c412d 100644 (file)
@@ -477,7 +477,7 @@ static struct platform_device *aquila_devices[] __initdata = {
        &aquila_i2c_gpio_pmic,
        &aquila_device_gpiokeys,
        &s3c_device_fb,
-       &s5pc110_device_onenand,
+       &s5p_device_onenand,
        &s3c_device_hsmmc0,
        &s3c_device_hsmmc1,
        &s3c_device_hsmmc2,
@@ -516,8 +516,6 @@ MACHINE_START(AQUILA, "Aquila")
        /* Maintainers:
           Marek Szyprowski <m.szyprowski@samsung.com>
           Kyungmin Park <kyungmin.park@samsung.com> */
-       .phys_io        = S3C_PA_UART & 0xfff00000,
-       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S5P_PA_SDRAM + 0x100,
        .init_irq       = s5pv210_init_irq,
        .map_io         = aquila_map_io,
index 53754d7d364ef513c233c5e77fcdee038e734635..d9ecf57fc2a5698ce0ff4067b243b052a9661efc 100644 (file)
@@ -456,7 +456,7 @@ static void goni_setup_sdhci(void)
 
 static struct platform_device *goni_devices[] __initdata = {
        &s3c_device_fb,
-       &s5pc110_device_onenand,
+       &s5p_device_onenand,
        &goni_i2c_gpio_pmic,
        &goni_device_gpiokeys,
        &s5p_device_fimc0,
@@ -491,8 +491,6 @@ static void __init goni_machine_init(void)
 
 MACHINE_START(GONI, "GONI")
        /* Maintainers: Kyungmin Park <kyungmin.park@samsung.com> */
-       .phys_io        = S3C_PA_UART & 0xfff00000,
-       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S5P_PA_SDRAM + 0x100,
        .init_irq       = s5pv210_init_irq,
        .map_io         = goni_map_io,
index 8211bb87c54bbd5a03127689a5ffc9a76f06b82d..cea9bca79d880c20bc0cb46df7dd8b77883976d8 100644 (file)
@@ -127,8 +127,6 @@ static void __init smdkc110_machine_init(void)
 
 MACHINE_START(SMDKC110, "SMDKC110")
        /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
-       .phys_io        = S3C_PA_UART & 0xfff00000,
-       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S5P_PA_SDRAM + 0x100,
        .init_irq       = s5pv210_init_irq,
        .map_io         = smdkc110_map_io,
index fbbc0a3c3738aaf2f99bab6556a139b708ee4985..83189ae9da9ad9dad00f16f6fc9ca459aaa89808 100644 (file)
@@ -165,8 +165,6 @@ static void __init smdkv210_machine_init(void)
 
 MACHINE_START(SMDKV210, "SMDKV210")
        /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
-       .phys_io        = S3C_PA_UART & 0xfff00000,
-       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S5P_PA_SDRAM + 0x100,
        .init_irq       = s5pv210_init_irq,
        .map_io         = smdkv210_map_io,
index e5b261a99ab2678e5860d9c0055d493137ef1e42..4add39853ff9dcf34f3e3c4aeeb25ea8e194da80 100644 (file)
@@ -31,29 +31,39 @@ extern void combiner_cascade_irq(unsigned int combiner_nr, unsigned int irq);
 /* Initial IO mappings */
 static struct map_desc s5pv310_iodesc[] __initdata = {
        {
-               .virtual        = (unsigned long)S5P_VA_COREPERI_BASE,
-               .pfn            = __phys_to_pfn(S5PV310_PA_COREPERI),
-               .length         = SZ_8K,
+               .virtual        = (unsigned long)S5P_VA_SYSRAM,
+               .pfn            = __phys_to_pfn(S5PV310_PA_SYSRAM),
+               .length         = SZ_4K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_CMU,
+               .pfn            = __phys_to_pfn(S5PV310_PA_CMU),
+               .length         = SZ_128K,
                .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)S5P_VA_COMBINER_BASE,
                .pfn            = __phys_to_pfn(S5PV310_PA_COMBINER),
                .length         = SZ_4K,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)S5P_VA_COREPERI_BASE,
+               .pfn            = __phys_to_pfn(S5PV310_PA_COREPERI),
+               .length         = SZ_8K,
+               .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)S5P_VA_L2CC,
                .pfn            = __phys_to_pfn(S5PV310_PA_L2CC),
                .length         = SZ_4K,
                .type           = MT_DEVICE,
        }, {
-               .virtual        = (unsigned long)S5P_VA_SYSRAM,
-               .pfn            = __phys_to_pfn(S5PV310_PA_SYSRAM),
+               .virtual        = (unsigned long)S5P_VA_GPIO,
+               .pfn            = __phys_to_pfn(S5PV310_PA_GPIO1),
                .length         = SZ_4K,
                .type           = MT_DEVICE,
        }, {
-               .virtual        = (unsigned long)S5P_VA_CMU,
-               .pfn            = __phys_to_pfn(S5PV310_PA_CMU),
-               .length         = SZ_128K,
+               .virtual        = (unsigned long)S3C_VA_UART,
+               .pfn            = __phys_to_pfn(S3C_PA_UART),
+               .length         = SZ_512K,
                .type           = MT_DEVICE,
        },
 };
index 6fb3893486bec83100c03c0cc9df3c969d3bf9fe..b0d920c474d3f4b501004ec8ef058c49bc66b002 100644 (file)
         * aligned and add in the offset when we load the value here.
         */
 
-       .macro addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1
-               ldreq   \rx, = S3C_PA_UART
-               ldrne   \rx, = S3C_VA_UART
+       .macro addruart, rp, rv
+               ldreq   \rp, = S3C_PA_UART
+               ldrne   \rv, = S3C_VA_UART
 #if CONFIG_DEBUG_S3C_UART != 0
-               add     \rx, \rx, #(0x10000 * CONFIG_DEBUG_S3C_UART)
+               add     \rp, \rp, #(0x10000 * CONFIG_DEBUG_S3C_UART)
+               add     \rv, \rv, #(0x10000 * CONFIG_DEBUG_S3C_UART)
 #endif
        .endm
 
index 4cdedda6e652b61297c877ac2c0205b81b9112ad..471fc3bb199a7a10becae92cd99fae46871ad997 100644 (file)
@@ -68,6 +68,8 @@
 
 #define IRQ_IIC                        COMBINER_IRQ(27, 0)
 
+#define IRQ_ONENAND_AUDI       COMBINER_IRQ(34, 0)
+
 /* Set the default NR_IRQS */
 
 #define NR_IRQS                        COMBINER_IRQ(MAX_COMBINER_NR, 0)
index 213e1101a3b325b60ada7c5bc5014035c1d8e74b..aff6d23624bb6d457e118ee7381a004a79968ceb 100644 (file)
 
 #define S5PV310_PA_SYSRAM              (0x02025000)
 
+#define S5PC210_PA_ONENAND             (0x0C000000)
+#define S5P_PA_ONENAND                 S5PC210_PA_ONENAND
+
+#define S5PC210_PA_ONENAND_DMA         (0x0C600000)
+#define S5P_PA_ONENAND_DMA             S5PC210_PA_ONENAND_DMA
+
 #define S5PV310_PA_CHIPID              (0x10000000)
 #define S5P_PA_CHIPID                  S5PV310_PA_CHIPID
 
@@ -46,7 +52,6 @@
 #define S5PV310_PA_GPIO1               (0x11400000)
 #define S5PV310_PA_GPIO2               (0x11000000)
 #define S5PV310_PA_GPIO3               (0x03860000)
-#define S5P_PA_GPIO                    S5PV310_PA_GPIO1
 
 #define S5PV310_PA_HSMMC(x)            (0x12510000 + ((x) * 0x10000))
 
index 990f3ba88a1fb59cee621cacd21e2ff72b263f0e..b7ec252384f47059f681ddad95c1d183ad8b39dc 100644 (file)
@@ -7,17 +7,10 @@
 #define ASM_ARCH_SMP_H __FILE__
 
 #include <asm/hardware/gic.h>
+#include <asm/smp_mpidr.h>
 
 extern void __iomem *gic_cpu_base_addr;
 
-#define hard_smp_processor_id()                        \
-       ({                                              \
-               unsigned int cpunum;                    \
-               __asm__("mrc p15, 0, %0, c0, c0, 5"     \
-                       : "=r" (cpunum));               \
-               cpunum &= 0x03;                         \
-       })
-
 /*
  * We use IRQ1 as the IPI
  */
index 0d6ab77709d263e28bd79790dd4601a4716b1eb8..46215a14b3bb49ec24ba11f9592565733a08b266 100644 (file)
@@ -82,8 +82,6 @@ static void __init smdkv310_machine_init(void)
 MACHINE_START(SMDKV310, "SMDKV310")
        /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */
        /* Maintainer: Changhwan Youn <chaos.youn@samsung.com> */
-       .phys_io        = S3C_PA_UART & 0xfff00000,
-       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S5P_PA_SDRAM + 0x100,
        .init_irq       = s5pv310_init_irq,
        .map_io         = smdkv310_map_io,
index 2388cb947936b0bcd2494ed3a9859656aee1d226..d7c2ec770f88bf1e80cc74e2749262726e10c598 100644 (file)
@@ -76,8 +76,6 @@ static void __init universal_machine_init(void)
 
 MACHINE_START(UNIVERSAL_C210, "UNIVERSAL_C210")
        /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
-       .phys_io        = S3C_PA_UART & 0xfff00000,
-       .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S5P_PA_SDRAM + 0x100,
        .init_irq       = s5pv310_init_irq,
        .map_io         = universal_map_io,
index 169e5b87dbffa5ac001dda528e282bada4c7b673..5778274a8260c8229987dac0be15cfb8d50d19fe 100644 (file)
@@ -447,8 +447,6 @@ static void __init assabet_map_io(void)
 
 
 MACHINE_START(ASSABET, "Intel-Assabet")
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .fixup          = fixup_assabet,
        .map_io         = assabet_map_io,
index 259cb2c15fffee94f679c424c9d2146bd8d36b5f..4f19ff868b00dca86d800ad7602b776a5a4b6ad2 100644 (file)
@@ -302,8 +302,6 @@ static void __init badge4_map_io(void)
 }
 
 MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = badge4_map_io,
        .init_irq       = sa1100_init_irq,
index bc950ef418af35a534bf01900482d68b8232ddf1..98d780608c7e98ffb3a64fb285301cc88731a6b5 100644 (file)
@@ -135,8 +135,6 @@ static void __init cerf_init(void)
 
 MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
        /* Maintainer: support@intrinsyc.com */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .map_io         = cerf_map_io,
        .init_irq       = cerf_init_irq,
        .timer          = &sa1100_timer,
index 16e682d5dbb7986fd1f0f038a65f87b8c2907910..d43c5ef58eb698f088820a0d0b9cc5c629dd8cc1 100644 (file)
@@ -379,8 +379,6 @@ static void __init collie_map_io(void)
 }
 
 MACHINE_START(COLLIE, "Sharp-Collie")
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .map_io         = collie_map_io,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
index 0c7cea0dc01314381137ed85070c5e678371bba2..03d7376cf8a0a57e50dca58bc56d68d7868713e8 100644 (file)
@@ -84,8 +84,6 @@ static void __init h3100_mach_init(void)
 }
 
 MACHINE_START(H3100, "Compaq iPAQ H3100")
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = h3100_map_io,
        .init_irq       = sa1100_init_irq,
index af3b71459f8d2adf794d91ac0da199d2e9eadfd5..965f64a836f8b13f22d1f26680403d26f2a9db40 100644 (file)
@@ -125,8 +125,6 @@ static void __init h3600_mach_init(void)
 }
 
 MACHINE_START(H3600, "Compaq iPAQ H3600")
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = h3600_map_io,
        .init_irq       = sa1100_init_irq,
index 51568dfc8e97187c2892b699bc5ac493d1b16008..db5e434a17dbf5de939030112149e199eb4523ff 100644 (file)
@@ -195,8 +195,6 @@ static void __init hackkit_init(void)
  */
 
 MACHINE_START(HACKKIT, "HackKit Cpu Board")
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = hackkit_map_io,
        .init_irq       = sa1100_init_irq,
index 336adccea54232ef50f7b43367f824c26bc20163..0cd0fc9635b6b3e2afb8668a43bb9a8389b9bbb1 100644 (file)
 */
 #include <mach/hardware.h>
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx, #0x80000000        @ physical base address
-               movne   \rx, #0xf8000000        @ virtual address
+               .macro  addruart, rp, rv
+               mrc     p15, 0, \rp, c1, c0
+               tst     \rp, #1                 @ MMU enabled?
+               moveq   \rp, #0x80000000        @ physical base address
+               movne   \rp, #0xf8000000        @ virtual address
 
                @ We probe for the active serial port here, coherently with
                @ the comment in arch/arm/mach-sa1100/include/mach/uncompress.h.
                @ We assume r1 can be clobbered.
 
                @ see if Ser3 is active
-               add     \rx, \rx, #0x00050000
-               ldr     r1, [\rx, #UTCR3]
-               tst     r1, #UTCR3_TXE
+               add     \rp, \rp, #0x00050000
+               ldr     \rv, [\rp, #UTCR3]
+               tst     \rv, #UTCR3_TXE
 
                @ if Ser3 is inactive, then try Ser1
-               addeq   \rx, \rx, #(0x00010000 - 0x00050000)
-               ldreq   r1, [\rx, #UTCR3]
-               tsteq   r1, #UTCR3_TXE
+               addeq   \rp, \rp, #(0x00010000 - 0x00050000)
+               ldreq   \rv, [\rp, #UTCR3]
+               tsteq   \rv, #UTCR3_TXE
 
                @ if Ser1 is inactive, then try Ser2
-               addeq   \rx, \rx, #(0x00030000 - 0x00010000)
-               ldreq   r1, [\rx, #UTCR3]
-               tsteq   r1, #UTCR3_TXE
+               addeq   \rp, \rp, #(0x00030000 - 0x00010000)
+               ldreq   \rv, [\rp, #UTCR3]
+               tsteq   \rv, #UTCR3_TXE
+
+               @ clear top bits, and generate both phys and virt addresses
+               lsl     \rp, \rp, #8
+               lsr     \rp, \rp, #8
+               orr     \rv, \rp, #0xf8000000   @ virtual
+               orr     \rp, \rp, #0x80000000   @ physical
 
-               @ if all ports are inactive, then there is nothing we can do
-               moveq   pc, lr
                .endm
 
                .macro  senduart,rd,rx
index d3ec620618f1866edf026abecc2739865dd2ad24..491ac9f20fb48c27045ecfc87be3971cdf4a54e1 100644 (file)
@@ -364,8 +364,6 @@ static void __init jornada720_mach_init(void)
 
 MACHINE_START(JORNADA720, "HP Jornada 720")
        /* Maintainer: Kristoffer Ericson <Kristoffer.Ericson@gmail.com> */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = jornada720_map_io,
        .init_irq       = sa1100_init_irq,
index 68069d6dc07a8b26d29787f0632a4895d66021ea..7b9556b59057b9c575d72a24129b60129b4be93a 100644 (file)
@@ -61,8 +61,6 @@ static void __init lart_map_io(void)
 }
 
 MACHINE_START(LART, "LART")
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = lart_map_io,
        .init_irq       = sa1100_init_irq,
index 1ccd6018d3a3a1dcec774ae0aad88108f75c9be0..42b80400c1006b8927f8c71046ab090ae536447c 100644 (file)
@@ -146,8 +146,6 @@ static void __init pleb_map_io(void)
 }
 
 MACHINE_START(PLEB, "PLEB")
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .map_io         = pleb_map_io,
        .init_irq       = sa1100_init_irq,
        .timer          = &sa1100_timer,
index 85e82bb73d7ef7b3244428954949716906ebdd8e..7917b2405579961f3e6968d241d8740b9eb4e189 100644 (file)
@@ -82,8 +82,6 @@ static void __init shannon_map_io(void)
 }
 
 MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = shannon_map_io,
        .init_irq       = sa1100_init_irq,
index 49cfd64663ac5753cec35a0db395d809baf4fc15..27692d0ffbe81c9d2a5e6931bc323f107973c7c6 100644 (file)
@@ -228,8 +228,6 @@ arch_initcall(simpad_init);
 
 MACHINE_START(SIMPAD, "Simpad")
        /* Maintainer: Holger Freyther */
-       .phys_io        = 0x80000000,
-       .io_pg_offst    = ((0xf8000000) >> 18) & 0xfffc,
        .boot_params    = 0xc0000100,
        .map_io         = simpad_map_io,
        .init_irq       = sa1100_init_irq,
index 358d875ace1478e67f8e32b03713917946650139..5cf7f94c1f3116837eeed4e15e7e03b7e8d1bb96 100644 (file)
@@ -152,8 +152,6 @@ static struct sys_timer shark_timer = {
 
 MACHINE_START(SHARK, "Shark")
        /* Maintainer: Alexander Schulz */
-       .phys_io        = 0x40000000,
-       .io_pg_offst    = ((0xe0000000) >> 18) & 0xfffc,
        .boot_params    = 0x08003000,
        .map_io         = shark_map_io,
        .init_irq       = shark_init_irq,
index 5ea24d4d1ba6e176985b16076b48412952de9aec..a473f55dc71fef28a2cbdafb5291d7ccf488ef24 100644 (file)
  *
 */
 
-               .macro  addruart, rx, tmp
-               mov     \rx, #0xe0000000
-               orr     \rx, \rx, #0x000003f8
+               .macro  addruart, rp, rv
+               mov     \rp, #0xe0000000
+               orr     \rp, \rp, #0x000003f8
+               mov     \rv, \rp
                .endm
 
                .macro  senduart,rd,rx
index f6c6837c5451888257a86601ae8031a9d0a598d5..8e845b6a7cb57a3f74b9f00c16ba12b2bc0dd6f9 100644 (file)
@@ -1,4 +1,4 @@
 /*
  * arch/arm/mach-shark/include/mach/vmalloc.h
  */
-#define VMALLOC_END       (PAGE_OFFSET + 0x10000000)
+#define VMALLOC_END       0xd0000000
index 95935c83c30654ee94d301e94086680475a6ed67..14923989ea0563831f0c176377c0400f603a6416 100644 (file)
@@ -1105,8 +1105,6 @@ static struct sys_timer ap4evb_timer = {
 };
 
 MACHINE_START(AP4EVB, "ap4evb")
-       .phys_io        = 0xe6000000,
-       .io_pg_offst    = ((0xe6000000) >> 18) & 0xfffc,
        .map_io         = ap4evb_map_io,
        .init_irq       = sh7372_init_irq,
        .init_machine   = ap4evb_init,
index a5525901e91f43e849811688d2066c6909f65ca8..3b83d6320bec808d5f4259fc4308c307f7e62f2e 100644 (file)
@@ -365,8 +365,6 @@ static struct sys_timer g3evm_timer = {
 };
 
 MACHINE_START(G3EVM, "g3evm")
-       .phys_io        = 0xe6000000,
-       .io_pg_offst    = ((0xe6000000) >> 18) & 0xfffc,
        .map_io         = g3evm_map_io,
        .init_irq       = sh7367_init_irq,
        .init_machine   = g3evm_init,
index 2c3ff6f7f34cec4909897fd13422c6ef04a65f54..5b3b582ef3f25fefd4430c071e89f42355832fb1 100644 (file)
@@ -392,8 +392,6 @@ static struct sys_timer g4evm_timer = {
 };
 
 MACHINE_START(G4EVM, "g4evm")
-       .phys_io        = 0xe6000000,
-       .io_pg_offst    = ((0xe6000000) >> 18) & 0xfffc,
        .map_io         = g4evm_map_io,
        .init_irq       = sh7377_init_irq,
        .init_machine   = g4evm_init,
index 90d8fe6f10fe996a1d71d631ccfd2d1b0cc92af1..06158848afd9584f60cb04690d33dc232d0c1fa3 100644 (file)
@@ -324,8 +324,6 @@ static void __init stmp378x_devb_init(void)
 }
 
 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,
index 394f21ab59e63485f76b4b6840e20276609d8436..311d8552d3628a7b8af45f58984e93340dfaab9d 100644 (file)
@@ -91,8 +91,6 @@ static void __init stmp37xx_devb_init(void)
 }
 
 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,
diff --git a/arch/arm/mach-tcc8k/Kconfig b/arch/arm/mach-tcc8k/Kconfig
new file mode 100644 (file)
index 0000000..ad86415
--- /dev/null
@@ -0,0 +1,11 @@
+if ARCH_TCC8K
+
+comment "TCC8000 systems:"
+
+config MACH_TCC8000_SDK
+       bool "Telechips TCC8000-SDK development kit"
+       default y
+       help
+         Support for the Telechips TCC8000-SDK board.
+
+endif
diff --git a/arch/arm/mach-tcc8k/Makefile b/arch/arm/mach-tcc8k/Makefile
new file mode 100644 (file)
index 0000000..9bacf31
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Makefile for TCC8K boards and common files.
+#
+
+# Common support
+obj-y += clock.o irq.o time.o io.o devices.o
+
+# Board specific support
+obj-$(CONFIG_MACH_TCC8000_SDK) += board-tcc8000-sdk.o
diff --git a/arch/arm/mach-tcc8k/Makefile.boot b/arch/arm/mach-tcc8k/Makefile.boot
new file mode 100644 (file)
index 0000000..f135c9d
--- /dev/null
@@ -0,0 +1,3 @@
+   zreladdr-y          := 0x20008000
+params_phys-y          := 0x20000100
+initrd_phys-y          := 0x20800000
diff --git a/arch/arm/mach-tcc8k/board-tcc8000-sdk.c b/arch/arm/mach-tcc8k/board-tcc8000-sdk.c
new file mode 100644 (file)
index 0000000..7991415
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.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/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include <mach/clock.h>
+
+#include "common.h"
+
+#define XI_FREQUENCY   12000000
+#define XTI_FREQUENCY  32768
+
+#ifdef CONFIG_MTD_NAND_TCC
+/* NAND */
+static struct tcc_nand_platform_data tcc8k_sdk_nand_data = {
+       .width = 1,
+       .hw_ecc = 0,
+};
+#endif
+
+static void __init tcc8k_init(void)
+{
+#ifdef CONFIG_MTD_NAND_TCC
+       tcc_nand_device.dev.platform_data = &tcc8k_sdk_nand_data;
+       platform_device_register(&tcc_nand_device);
+#endif
+}
+
+static void __init tcc8k_init_timer(void)
+{
+       tcc_clocks_init(XI_FREQUENCY, XTI_FREQUENCY);
+}
+
+static struct sys_timer tcc8k_timer = {
+       .init   = tcc8k_init_timer,
+};
+
+static void __init tcc8k_map_io(void)
+{
+       tcc8k_map_common_io();
+}
+
+MACHINE_START(TCC8000_SDK, "Telechips TCC8000-SDK Demo Board")
+       .boot_params    = PHYS_OFFSET + 0x00000100,
+       .map_io         = tcc8k_map_io,
+       .init_irq       = tcc8k_init_irq,
+       .init_machine   = tcc8k_init,
+       .timer          = &tcc8k_timer,
+MACHINE_END
diff --git a/arch/arm/mach-tcc8k/clock.c b/arch/arm/mach-tcc8k/clock.c
new file mode 100644 (file)
index 0000000..ba32a15
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+ * Lowlevel clock handling for Telechips TCC8xxx SoCs
+ *
+ * Copyright (C) 2010 by Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPL v2
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include <asm/clkdev.h>
+
+#include <mach/clock.h>
+#include <mach/irqs.h>
+#include <mach/tcc8k-regs.h>
+
+#include "common.h"
+
+#define BCLKCTR0       (CKC_BASE + BCLKCTR0_OFFS)
+#define BCLKCTR1       (CKC_BASE + BCLKCTR1_OFFS)
+
+#define ACLKREF                (CKC_BASE + ACLKREF_OFFS)
+#define ACLKUART0      (CKC_BASE + ACLKUART0_OFFS)
+#define ACLKUART1      (CKC_BASE + ACLKUART1_OFFS)
+#define ACLKUART2      (CKC_BASE + ACLKUART2_OFFS)
+#define ACLKUART3      (CKC_BASE + ACLKUART3_OFFS)
+#define ACLKUART4      (CKC_BASE + ACLKUART4_OFFS)
+#define ACLKI2C                (CKC_BASE + ACLKI2C_OFFS)
+#define ACLKADC                (CKC_BASE + ACLKADC_OFFS)
+#define ACLKUSBH       (CKC_BASE + ACLKUSBH_OFFS)
+#define ACLKLCD                (CKC_BASE + ACLKLCD_OFFS)
+#define ACLKSDH0       (CKC_BASE + ACLKSDH0_OFFS)
+#define ACLKSDH1       (CKC_BASE + ACLKSDH1_OFFS)
+#define ACLKSPI0       (CKC_BASE + ACLKSPI0_OFFS)
+#define ACLKSPI1       (CKC_BASE + ACLKSPI1_OFFS)
+#define ACLKSPDIF      (CKC_BASE + ACLKSPDIF_OFFS)
+#define ACLKC3DEC      (CKC_BASE + ACLKC3DEC_OFFS)
+#define ACLKCAN0       (CKC_BASE + ACLKCAN0_OFFS)
+#define ACLKCAN1       (CKC_BASE + ACLKCAN1_OFFS)
+#define ACLKGSB0       (CKC_BASE + ACLKGSB0_OFFS)
+#define ACLKGSB1       (CKC_BASE + ACLKGSB1_OFFS)
+#define ACLKGSB2       (CKC_BASE + ACLKGSB2_OFFS)
+#define ACLKGSB3       (CKC_BASE + ACLKGSB3_OFFS)
+#define ACLKUSBH       (CKC_BASE + ACLKUSBH_OFFS)
+#define ACLKTCT                (CKC_BASE + ACLKTCT_OFFS)
+#define ACLKTCX                (CKC_BASE + ACLKTCX_OFFS)
+#define ACLKTCZ                (CKC_BASE + ACLKTCZ_OFFS)
+
+/* Crystal frequencies */
+static unsigned long xi_rate, xti_rate;
+
+static void __iomem *pll_cfg_addr(int pll)
+{
+       switch (pll) {
+       case 0: return (CKC_BASE + PLL0CFG_OFFS);
+       case 1: return (CKC_BASE + PLL1CFG_OFFS);
+       case 2: return (CKC_BASE + PLL2CFG_OFFS);
+       default:
+               BUG();
+       }
+}
+
+static int pll_enable(int pll, int enable)
+{
+       u32 reg;
+       void __iomem *addr = pll_cfg_addr(pll);
+
+       reg = __raw_readl(addr);
+       if (enable)
+               reg &= ~PLLxCFG_PD;
+       else
+               reg |= PLLxCFG_PD;
+
+       __raw_writel(reg, addr);
+       return 0;
+}
+
+static int xi_enable(int enable)
+{
+       u32 reg;
+
+       reg = __raw_readl(CKC_BASE + CLKCTRL_OFFS);
+       if (enable)
+               reg |= CLKCTRL_XE;
+       else
+               reg &= ~CLKCTRL_XE;
+
+       __raw_writel(reg, CKC_BASE + CLKCTRL_OFFS);
+       return 0;
+}
+
+static int root_clk_enable(enum root_clks src)
+{
+       switch (src) {
+       case CLK_SRC_PLL0: return pll_enable(0, 1);
+       case CLK_SRC_PLL1: return pll_enable(1, 1);
+       case CLK_SRC_PLL2: return pll_enable(2, 1);
+       case CLK_SRC_XI: return xi_enable(1);
+       default:
+               BUG();
+       }
+       return 0;
+}
+
+static int root_clk_disable(enum root_clks root_src)
+{
+       switch (root_src) {
+       case CLK_SRC_PLL0: return pll_enable(0, 0);
+       case CLK_SRC_PLL1: return pll_enable(1, 0);
+       case CLK_SRC_PLL2: return pll_enable(2, 0);
+       case CLK_SRC_XI: return xi_enable(0);
+       default:
+               BUG();
+       }
+       return 0;
+}
+
+static int enable_clk(struct clk *clk)
+{
+       u32 reg;
+
+       if (clk->root_id != CLK_SRC_NOROOT)
+               return root_clk_enable(clk->root_id);
+
+       if (clk->aclkreg) {
+               reg = __raw_readl(clk->aclkreg);
+               reg |= ACLK_EN;
+               __raw_writel(reg, clk->aclkreg);
+       }
+       if (clk->bclkctr) {
+               reg = __raw_readl(clk->bclkctr);
+               reg |= 1 << clk->bclk_shift;
+               __raw_writel(reg, clk->bclkctr);
+       }
+       return 0;
+}
+
+static void disable_clk(struct clk *clk)
+{
+       u32 reg;
+
+       if (clk->root_id != CLK_SRC_NOROOT) {
+               root_clk_disable(clk->root_id);
+               return;
+       }
+
+       if (clk->bclkctr) {
+               reg = __raw_readl(clk->bclkctr);
+               reg &= ~(1 << clk->bclk_shift);
+               __raw_writel(reg, clk->bclkctr);
+       }
+       if (clk->aclkreg) {
+               reg = __raw_readl(clk->aclkreg);
+               reg &= ~ACLK_EN;
+               __raw_writel(reg, clk->aclkreg);
+       }
+}
+
+static unsigned long get_rate_pll(int pll)
+{
+       u32 reg;
+       unsigned long s, m, p;
+       void __iomem *addr = pll_cfg_addr(pll);
+
+       reg = __raw_readl(addr);
+       s = (reg >> 16) & 0x07;
+       m = (reg >> 8) & 0xff;
+       p = reg & 0x3f;
+
+       return (m * xi_rate) / (p * (1 << s));
+}
+
+static unsigned long get_rate_pll_div(int pll)
+{
+       u32 reg;
+       unsigned long div = 0;
+       void __iomem *addr;
+
+       switch (pll) {
+       case 0:
+               addr = CKC_BASE + CLKDIVC0_OFFS;
+               reg = __raw_readl(addr);
+               if (reg & CLKDIVC0_P0E)
+                       div = (reg >> 24) & 0x3f;
+               break;
+       case 1:
+               addr = CKC_BASE + CLKDIVC0_OFFS;
+               reg = __raw_readl(addr);
+               if (reg & CLKDIVC0_P1E)
+                       div = (reg >> 16) & 0x3f;
+               break;
+       case 2:
+               addr = CKC_BASE + CLKDIVC1_OFFS;
+               reg = __raw_readl(addr);
+               if (reg & CLKDIVC1_P2E)
+                       div = __raw_readl(addr) & 0x3f;
+               break;
+       }
+       return get_rate_pll(pll) / (div + 1);
+}
+
+static unsigned long get_rate_xi_div(void)
+{
+       unsigned long div = 0;
+       u32 reg = __raw_readl(CKC_BASE + CLKDIVC0_OFFS);
+
+       if (reg & CLKDIVC0_XE)
+               div = (reg >> 8) & 0x3f;
+
+       return xi_rate / (div + 1);
+}
+
+static unsigned long get_rate_xti_div(void)
+{
+       unsigned long div = 0;
+       u32 reg = __raw_readl(CKC_BASE + CLKDIVC0_OFFS);
+
+       if (reg & CLKDIVC0_XTE)
+               div = reg & 0x3f;
+
+       return xti_rate / (div + 1);
+}
+
+static unsigned long root_clk_get_rate(enum root_clks src)
+{
+       switch (src) {
+       case CLK_SRC_PLL0: return get_rate_pll(0);
+       case CLK_SRC_PLL1: return get_rate_pll(1);
+       case CLK_SRC_PLL2: return get_rate_pll(2);
+       case CLK_SRC_PLL0DIV: return get_rate_pll_div(0);
+       case CLK_SRC_PLL1DIV: return get_rate_pll_div(1);
+       case CLK_SRC_PLL2DIV: return get_rate_pll_div(2);
+       case CLK_SRC_XI: return xi_rate;
+       case CLK_SRC_XTI: return xti_rate;
+       case CLK_SRC_XIDIV: return get_rate_xi_div();
+       case CLK_SRC_XTIDIV: return get_rate_xti_div();
+       default: return 0;
+       }
+}
+
+static unsigned long aclk_get_rate(struct clk *clk)
+{
+       u32 reg;
+       unsigned long div;
+       unsigned int src;
+
+       reg = __raw_readl(clk->aclkreg);
+       div = reg & 0x0fff;
+       src = (reg >> ACLK_SEL_SHIFT) & CLK_SRC_MASK;
+       return root_clk_get_rate(src) / (div + 1);
+}
+
+static unsigned long aclk_best_div(struct clk *clk, unsigned long rate)
+{
+       unsigned long div, src, freq, r1, r2;
+
+       src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT;
+       src &= CLK_SRC_MASK;
+       freq = root_clk_get_rate(src);
+       div = freq / rate + 1;
+       r1 = freq / div;
+       r2 = freq / (div + 1);
+       if (r2 >= rate)
+               return div + 1;
+       if ((rate - r2) < (r1 - rate))
+               return div + 1;
+
+       return div;
+}
+
+static unsigned long aclk_round_rate(struct clk *clk, unsigned long rate)
+{
+       unsigned int src;
+
+       src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT;
+       src &= CLK_SRC_MASK;
+
+       return root_clk_get_rate(src) / aclk_best_div(clk, rate);
+}
+
+static int aclk_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 reg;
+
+       reg = __raw_readl(clk->aclkreg) & ~ACLK_DIV_MASK;
+       reg |= aclk_best_div(clk, rate);
+       return 0;
+}
+
+static unsigned long get_rate_sys(struct clk *clk)
+{
+       unsigned int src;
+
+       src = __raw_readl(CKC_BASE + CLKCTRL_OFFS) & CLK_SRC_MASK;
+               return root_clk_get_rate(src);
+}
+
+static unsigned long get_rate_bus(struct clk *clk)
+{
+       unsigned int div;
+
+       div = (__raw_readl(CKC_BASE + CLKCTRL_OFFS) >> 4) & 0xff;
+       return get_rate_sys(clk) / (div + 1);
+}
+
+static unsigned long get_rate_cpu(struct clk *clk)
+{
+       unsigned int reg, div, fsys, fbus;
+
+       fbus = get_rate_bus(clk);
+       reg = __raw_readl(CKC_BASE + CLKCTRL_OFFS);
+       if (reg & (1 << 29))
+               return fbus;
+       fsys = get_rate_sys(clk);
+       div = (reg >> 16) & 0x0f;
+       return fbus + ((fsys - fbus) * (div + 1)) / 16;
+}
+
+static unsigned long get_rate_root(struct clk *clk)
+{
+       return root_clk_get_rate(clk->root_id);
+}
+
+static int aclk_set_parent(struct clk *clock, struct clk *parent)
+{
+       u32 reg;
+
+       if (clock->parent == parent)
+               return 0;
+
+       clock->parent = parent;
+
+       if (!parent)
+               return 0;
+
+       if (parent->root_id == CLK_SRC_NOROOT)
+               return 0;
+       reg = __raw_readl(clock->aclkreg);
+       reg &= ~ACLK_SEL_MASK;
+       reg |= (parent->root_id << ACLK_SEL_SHIFT) & ACLK_SEL_MASK;
+       __raw_writel(reg, clock->aclkreg);
+
+       return 0;
+}
+
+#define DEFINE_ROOT_CLOCK(name, ri, p) \
+       static struct clk name = {              \
+               .root_id = ri,                  \
+               .get_rate = get_rate_root,                      \
+               .enable = enable_clk,           \
+               .disable = disable_clk,         \
+               .parent = p,                    \
+       };
+
+#define DEFINE_SPECIAL_CLOCK(name, gr, p)      \
+       static struct clk name = {              \
+               .root_id = CLK_SRC_NOROOT,      \
+               .get_rate = gr,                 \
+               .parent = p,                    \
+       };
+
+#define DEFINE_ACLOCK(name, bc, bs, ar)                \
+       static struct clk name = {              \
+               .root_id = CLK_SRC_NOROOT,      \
+               .bclkctr = bc,                  \
+               .bclk_shift = bs,               \
+               .aclkreg = ar,                  \
+               .get_rate = aclk_get_rate,      \
+               .set_rate = aclk_set_rate,      \
+               .round_rate = aclk_round_rate,  \
+               .enable = enable_clk,           \
+               .disable = disable_clk,         \
+               .set_parent = aclk_set_parent,  \
+       };
+
+#define DEFINE_BCLOCK(name, bc, bs, gr, p)     \
+       static struct clk name = {              \
+               .root_id = CLK_SRC_NOROOT,      \
+               .bclkctr = bc,                  \
+               .bclk_shift = bs,               \
+               .get_rate = gr,                 \
+               .enable = enable_clk,           \
+               .disable = disable_clk,         \
+               .parent = p,                    \
+       };
+
+DEFINE_ROOT_CLOCK(xi, CLK_SRC_XI, NULL)
+DEFINE_ROOT_CLOCK(xti, CLK_SRC_XTI, NULL)
+DEFINE_ROOT_CLOCK(xidiv, CLK_SRC_XIDIV, &xi)
+DEFINE_ROOT_CLOCK(xtidiv, CLK_SRC_XTIDIV, &xti)
+DEFINE_ROOT_CLOCK(pll0, CLK_SRC_PLL0, &xi)
+DEFINE_ROOT_CLOCK(pll1, CLK_SRC_PLL1, &xi)
+DEFINE_ROOT_CLOCK(pll2, CLK_SRC_PLL2, &xi)
+DEFINE_ROOT_CLOCK(pll0div, CLK_SRC_PLL0DIV, &pll0)
+DEFINE_ROOT_CLOCK(pll1div, CLK_SRC_PLL1DIV, &pll1)
+DEFINE_ROOT_CLOCK(pll2div, CLK_SRC_PLL2DIV, &pll2)
+
+/* The following 3 clocks are special and are initialized explicitly later */
+DEFINE_SPECIAL_CLOCK(sys, get_rate_sys, NULL)
+DEFINE_SPECIAL_CLOCK(bus, get_rate_bus, &sys)
+DEFINE_SPECIAL_CLOCK(cpu, get_rate_cpu, &sys)
+
+DEFINE_ACLOCK(tct, NULL, 0, ACLKTCT)
+DEFINE_ACLOCK(tcx, NULL, 0, ACLKTCX)
+DEFINE_ACLOCK(tcz, NULL, 0, ACLKTCZ)
+DEFINE_ACLOCK(ref, NULL, 0, ACLKREF)
+DEFINE_ACLOCK(uart0, BCLKCTR0, 5, ACLKUART0)
+DEFINE_ACLOCK(uart1, BCLKCTR0, 23, ACLKUART1)
+DEFINE_ACLOCK(uart2, BCLKCTR0, 6, ACLKUART2)
+DEFINE_ACLOCK(uart3, BCLKCTR0, 8, ACLKUART3)
+DEFINE_ACLOCK(uart4, BCLKCTR1, 6, ACLKUART4)
+DEFINE_ACLOCK(i2c, BCLKCTR0, 7, ACLKI2C)
+DEFINE_ACLOCK(adc, BCLKCTR0, 10, ACLKADC)
+DEFINE_ACLOCK(usbh0, BCLKCTR0, 11, ACLKUSBH)
+DEFINE_ACLOCK(lcd, BCLKCTR0, 13, ACLKLCD)
+DEFINE_ACLOCK(sd0, BCLKCTR0, 17, ACLKSDH0)
+DEFINE_ACLOCK(sd1, BCLKCTR1, 5, ACLKSDH1)
+DEFINE_ACLOCK(spi0, BCLKCTR0, 24, ACLKSPI0)
+DEFINE_ACLOCK(spi1, BCLKCTR0, 30, ACLKSPI1)
+DEFINE_ACLOCK(spdif, BCLKCTR1, 2, ACLKSPDIF)
+DEFINE_ACLOCK(c3dec, BCLKCTR1, 9, ACLKC3DEC)
+DEFINE_ACLOCK(can0, BCLKCTR1, 10, ACLKCAN0)
+DEFINE_ACLOCK(can1, BCLKCTR1, 11, ACLKCAN1)
+DEFINE_ACLOCK(gsb0, BCLKCTR1, 13, ACLKGSB0)
+DEFINE_ACLOCK(gsb1, BCLKCTR1, 14, ACLKGSB1)
+DEFINE_ACLOCK(gsb2, BCLKCTR1, 15, ACLKGSB2)
+DEFINE_ACLOCK(gsb3, BCLKCTR1, 16, ACLKGSB3)
+DEFINE_ACLOCK(usbh1, BCLKCTR1, 20, ACLKUSBH)
+
+DEFINE_BCLOCK(dai0, BCLKCTR0, 0, NULL, NULL)
+DEFINE_BCLOCK(pic, BCLKCTR0, 1, NULL, NULL)
+DEFINE_BCLOCK(tc, BCLKCTR0, 2, NULL, NULL)
+DEFINE_BCLOCK(gpio, BCLKCTR0, 3, NULL, NULL)
+DEFINE_BCLOCK(usbd, BCLKCTR0, 4, NULL, NULL)
+DEFINE_BCLOCK(ecc, BCLKCTR0, 9, NULL, NULL)
+DEFINE_BCLOCK(gdma0, BCLKCTR0, 12, NULL, NULL)
+DEFINE_BCLOCK(rtc, BCLKCTR0, 15, NULL, NULL)
+DEFINE_BCLOCK(nfc, BCLKCTR0, 16, NULL, NULL)
+DEFINE_BCLOCK(g2d, BCLKCTR0, 18, NULL, NULL)
+DEFINE_BCLOCK(gdma1, BCLKCTR0, 22, NULL, NULL)
+DEFINE_BCLOCK(mscl, BCLKCTR0, 25, NULL, NULL)
+DEFINE_BCLOCK(bdma, BCLKCTR1, 0, NULL, NULL)
+DEFINE_BCLOCK(adma0, BCLKCTR1, 1, NULL, NULL)
+DEFINE_BCLOCK(scfg, BCLKCTR1, 3, NULL, NULL)
+DEFINE_BCLOCK(cid, BCLKCTR1, 4, NULL, NULL)
+DEFINE_BCLOCK(dai1, BCLKCTR1, 7, NULL, NULL)
+DEFINE_BCLOCK(adma1, BCLKCTR1, 8, NULL, NULL)
+DEFINE_BCLOCK(gps, BCLKCTR1, 12, NULL, NULL)
+DEFINE_BCLOCK(gdma2, BCLKCTR1, 17, NULL, NULL)
+DEFINE_BCLOCK(gdma3, BCLKCTR1, 18, NULL, NULL)
+DEFINE_BCLOCK(ddrc, BCLKCTR1, 19, NULL, NULL)
+
+#define _REGISTER_CLOCK(d, n, c) \
+       { \
+               .dev_id = d, \
+               .con_id = n, \
+               .clk = &c, \
+       },
+
+static struct clk_lookup lookups[] = {
+       _REGISTER_CLOCK(NULL, "bus", bus)
+       _REGISTER_CLOCK(NULL, "cpu", cpu)
+       _REGISTER_CLOCK(NULL, "tct", tct)
+       _REGISTER_CLOCK(NULL, "tcx", tcx)
+       _REGISTER_CLOCK(NULL, "tcz", tcz)
+       _REGISTER_CLOCK(NULL, "ref", ref)
+       _REGISTER_CLOCK(NULL, "dai0", dai0)
+       _REGISTER_CLOCK(NULL, "pic", pic)
+       _REGISTER_CLOCK(NULL, "tc", tc)
+       _REGISTER_CLOCK(NULL, "gpio", gpio)
+       _REGISTER_CLOCK(NULL, "usbd", usbd)
+       _REGISTER_CLOCK("tcc-uart.0", NULL, uart0)
+       _REGISTER_CLOCK("tcc-uart.2", NULL, uart2)
+       _REGISTER_CLOCK("tcc-i2c", NULL, i2c)
+       _REGISTER_CLOCK("tcc-uart.3", NULL, uart3)
+       _REGISTER_CLOCK(NULL, "ecc", ecc)
+       _REGISTER_CLOCK(NULL, "adc", adc)
+       _REGISTER_CLOCK("tcc-usbh.0", "usb", usbh0)
+       _REGISTER_CLOCK(NULL, "gdma0", gdma0)
+       _REGISTER_CLOCK(NULL, "lcd", lcd)
+       _REGISTER_CLOCK(NULL, "rtc", rtc)
+       _REGISTER_CLOCK(NULL, "nfc", nfc)
+       _REGISTER_CLOCK("tcc-mmc.0", NULL, sd0)
+       _REGISTER_CLOCK(NULL, "g2d", g2d)
+       _REGISTER_CLOCK(NULL, "gdma1", gdma1)
+       _REGISTER_CLOCK("tcc-uart.1", NULL, uart1)
+       _REGISTER_CLOCK("tcc-spi.0", NULL, spi0)
+       _REGISTER_CLOCK(NULL, "mscl", mscl)
+       _REGISTER_CLOCK("tcc-spi.1", NULL, spi1)
+       _REGISTER_CLOCK(NULL, "bdma", bdma)
+       _REGISTER_CLOCK(NULL, "adma0", adma0)
+       _REGISTER_CLOCK(NULL, "spdif", spdif)
+       _REGISTER_CLOCK(NULL, "scfg", scfg)
+       _REGISTER_CLOCK(NULL, "cid", cid)
+       _REGISTER_CLOCK("tcc-mmc.1", NULL, sd1)
+       _REGISTER_CLOCK("tcc-uart.4", NULL, uart4)
+       _REGISTER_CLOCK(NULL, "dai1", dai1)
+       _REGISTER_CLOCK(NULL, "adma1", adma1)
+       _REGISTER_CLOCK(NULL, "c3dec", c3dec)
+       _REGISTER_CLOCK("tcc-can.0", NULL, can0)
+       _REGISTER_CLOCK("tcc-can.1", NULL, can1)
+       _REGISTER_CLOCK(NULL, "gps", gps)
+       _REGISTER_CLOCK("tcc-gsb.0", NULL, gsb0)
+       _REGISTER_CLOCK("tcc-gsb.1", NULL, gsb1)
+       _REGISTER_CLOCK("tcc-gsb.2", NULL, gsb2)
+       _REGISTER_CLOCK("tcc-gsb.3", NULL, gsb3)
+       _REGISTER_CLOCK(NULL, "gdma2", gdma2)
+       _REGISTER_CLOCK(NULL, "gdma3", gdma3)
+       _REGISTER_CLOCK(NULL, "ddrc", ddrc)
+       _REGISTER_CLOCK("tcc-usbh.1", "usb", usbh1)
+};
+
+static struct clk *root_clk_by_index(enum root_clks src)
+{
+       switch (src) {
+       case CLK_SRC_PLL0: return &pll0;
+       case CLK_SRC_PLL1: return &pll1;
+       case CLK_SRC_PLL2: return &pll2;
+       case CLK_SRC_PLL0DIV: return &pll0div;
+       case CLK_SRC_PLL1DIV: return &pll1div;
+       case CLK_SRC_PLL2DIV: return &pll2div;
+       case CLK_SRC_XI: return &xi;
+       case CLK_SRC_XTI: return &xti;
+       case CLK_SRC_XIDIV: return &xidiv;
+       case CLK_SRC_XTIDIV: return &xtidiv;
+       default: return NULL;
+       }
+}
+
+static void find_aclk_parent(struct clk *clk)
+{
+       unsigned int src;
+       struct clk *clock;
+
+       if (!clk->aclkreg)
+               return;
+
+       src = __raw_readl(clk->aclkreg) >> ACLK_SEL_SHIFT;
+       src &= CLK_SRC_MASK;
+
+       clock = root_clk_by_index(src);
+       if (!clock)
+               return;
+
+       clk->parent = clock;
+       clk->set_parent = aclk_set_parent;
+}
+
+void __init tcc_clocks_init(unsigned long xi_freq, unsigned long xti_freq)
+{
+       int i;
+
+       xi_rate = xi_freq;
+       xti_rate = xti_freq;
+
+       /* fixup parents and add the clock */
+       for (i = 0; i < ARRAY_SIZE(lookups); i++) {
+               find_aclk_parent(lookups[i].clk);
+               clkdev_add(&lookups[i]);
+       }
+       tcc8k_timer_init(&tcz, (void __iomem *)TIMER_BASE, INT_TC32);
+}
diff --git a/arch/arm/mach-tcc8k/common.h b/arch/arm/mach-tcc8k/common.h
new file mode 100644 (file)
index 0000000..705690a
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef MACH_TCC8K_COMMON_H
+#define MACH_TCC8K_COMMON_H
+
+#include <linux/platform_device.h>
+
+extern struct platform_device tcc_nand_device;
+
+struct clk;
+
+extern void tcc_clocks_init(unsigned long xi_freq, unsigned long xti_freq);
+extern void tcc8k_timer_init(struct clk *clock, void __iomem *base, int irq);
+extern void tcc8k_init_irq(void);
+extern void tcc8k_map_common_io(void);
+
+#endif
diff --git a/arch/arm/mach-tcc8k/devices.c b/arch/arm/mach-tcc8k/devices.c
new file mode 100644 (file)
index 0000000..6722ad7
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * linux/arch/arm/mach-tcc8k/devices.c
+ *
+ * Copyright (C) Telechips, Inc.
+ * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of GPL v2.
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/tcc8k-regs.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+static u64 tcc8k_dmamask = DMA_BIT_MASK(32);
+
+#ifdef CONFIG_MTD_NAND_TCC
+/* NAND controller */
+static struct resource tcc_nand_resources[] = {
+       {
+               .start  = (resource_size_t)NFC_BASE,
+               .end    = (resource_size_t)NFC_BASE + 0x7f,
+               .flags  = IORESOURCE_MEM,
+       }, {
+               .start  = INT_NFC,
+               .end    = INT_NFC,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device tcc_nand_device = {
+       .name = "tcc_nand",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(tcc_nand_resources),
+       .resource = tcc_nand_resources,
+};
+#endif
+
+#ifdef CONFIG_MMC_TCC8K
+/* MMC controller */
+static struct resource tcc8k_mmc0_resource[] = {
+       {
+               .start = INT_SD0,
+               .end   = INT_SD0,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource tcc8k_mmc1_resource[] = {
+       {
+               .start = INT_SD1,
+               .end   = INT_SD1,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+struct platform_device tcc8k_mmc0_device = {
+       .name           = "tcc-mmc",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(tcc8k_mmc0_resource),
+       .resource       = tcc8k_mmc0_resource,
+       .dev            = {
+               .dma_mask               = &tcc8k_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       }
+};
+
+struct platform_device tcc8k_mmc1_device = {
+       .name           = "tcc-mmc",
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(tcc8k_mmc1_resource),
+       .resource       = tcc8k_mmc1_resource,
+       .dev            = {
+               .dma_mask               = &tcc8k_dmamask,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
+       }
+};
+
+static inline void tcc8k_init_mmc(void)
+{
+       u32 reg = __raw_readl(GPIOPS_BASE + GPIOPS_FS1_OFFS);
+
+       reg |= GPIOPS_FS1_SDH0_BITS | GPIOPS_FS1_SDH1_BITS;
+       __raw_writel(reg, GPIOPS_BASE + GPIOPS_FS1_OFFS);
+
+       platform_device_register(&tcc8k_mmc0_device);
+       platform_device_register(&tcc8k_mmc1_device);
+}
+#else
+static inline void tcc8k_init_mmc(void) { }
+#endif
+
+#ifdef CONFIG_USB_OHCI_HCD
+static int tcc8k_ohci_init(struct device *dev)
+{
+       u32 reg;
+
+       /* Use GPIO PK19 as VBUS control output */
+       reg = __raw_readl(GPIOPK_BASE + GPIOPK_FS0_OFFS);
+       reg &= ~(1 << 19);
+       __raw_writel(reg, GPIOPK_BASE + GPIOPK_FS0_OFFS);
+       reg = __raw_readl(GPIOPK_BASE + GPIOPK_FS1_OFFS);
+       reg &= ~(1 << 19);
+       __raw_writel(reg, GPIOPK_BASE + GPIOPK_FS1_OFFS);
+
+       reg = __raw_readl(GPIOPK_BASE + GPIOPK_DOE_OFFS);
+       reg |= (1 << 19);
+       __raw_writel(reg, GPIOPK_BASE + GPIOPK_DOE_OFFS);
+       /* Turn on VBUS */
+       reg = __raw_readl(GPIOPK_BASE + GPIOPK_DAT_OFFS);
+       reg |= (1 << 19);
+       __raw_writel(reg, GPIOPK_BASE + GPIOPK_DAT_OFFS);
+
+       return 0;
+}
+
+static struct resource tcc8k_ohci0_resources[] = {
+       [0] = {
+               .start = (resource_size_t)USBH0_BASE,
+               .end   = (resource_size_t)USBH0_BASE + 0x5c,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = INT_USBH0,
+               .end   = INT_USBH0,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static struct resource tcc8k_ohci1_resources[] = {
+       [0] = {
+               .start = (resource_size_t)USBH1_BASE,
+               .end   = (resource_size_t)USBH1_BASE + 0x5c,
+               .flags = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start = INT_USBH1,
+               .end   = INT_USBH1,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static struct tccohci_platform_data tcc8k_ohci0_platform_data = {
+       .controller     = 0,
+       .port_mode      = PMM_PERPORT_MODE,
+       .init           = tcc8k_ohci_init,
+};
+
+static struct tccohci_platform_data tcc8k_ohci1_platform_data = {
+       .controller     = 1,
+       .port_mode      = PMM_PERPORT_MODE,
+       .init           = tcc8k_ohci_init,
+};
+
+static struct platform_device ohci0_device = {
+       .name = "tcc-ohci",
+       .id = 0,
+       .dev = {
+               .dma_mask = &tcc8k_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .platform_data = &tcc8k_ohci0_platform_data,
+       },
+       .num_resources  = ARRAY_SIZE(tcc8k_ohci0_resources),
+       .resource       = tcc8k_ohci0_resources,
+};
+
+static struct platform_device ohci1_device = {
+       .name = "tcc-ohci",
+       .id = 1,
+       .dev = {
+               .dma_mask = &tcc8k_dmamask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+               .platform_data = &tcc8k_ohci1_platform_data,
+       },
+       .num_resources  = ARRAY_SIZE(tcc8k_ohci1_resources),
+       .resource       = tcc8k_ohci1_resources,
+};
+
+static void __init tcc8k_init_usbhost(void)
+{
+       platform_device_register(&ohci0_device);
+       platform_device_register(&ohci1_device);
+}
+#else
+static void __init tcc8k_init_usbhost(void) { }
+#endif
+
+/* USB device controller*/
+#ifdef CONFIG_USB_GADGET_TCC8K
+static struct resource udc_resources[] = {
+       [0] = {
+               .start = INT_USBD,
+               .end   = INT_USBD,
+               .flags = IORESOURCE_IRQ,
+       },
+       [1] = {
+               .start = INT_UDMA,
+               .end   = INT_UDMA,
+               .flags = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device tcc8k_udc_device = {
+       .name = "tcc-udc",
+       .id = 0,
+       .resource = udc_resources,
+       .num_resources = ARRAY_SIZE(udc_resources),
+       .dev = {
+                .dma_mask = &tcc8k_dmamask,
+                .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
+static void __init tcc8k_init_usb_gadget(void)
+{
+       platform_device_register(&tcc8k_udc_device);
+}
+#else
+static void __init tcc8k_init_usb_gadget(void) { }
+#endif /* CONFIG_USB_GADGET_TCC83X */
+
+static int __init tcc8k_init_devices(void)
+{
+       tcc8k_init_mmc();
+       tcc8k_init_usbhost();
+       tcc8k_init_usb_gadget();
+       return 0;
+}
+
+arch_initcall(tcc8k_init_devices);
diff --git a/arch/arm/mach-tcc8k/io.c b/arch/arm/mach-tcc8k/io.c
new file mode 100644 (file)
index 0000000..9b39d7f
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * linux/arch/arm/mach-tcc8k/io.c
+ *
+ * (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * derived from TCC83xx io.c
+ * Copyright (C) Telechips, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/tcc8k-regs.h>
+
+/*
+ * The machine specific code may provide the extra mapping besides the
+ * default mapping provided here.
+ */
+static struct map_desc tcc8k_io_desc[] __initdata = {
+       {
+               .virtual        = (unsigned long)CS1_BASE_VIRT,
+               .pfn            = __phys_to_pfn(CS1_BASE),
+               .length         = CS1_SIZE,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)AHB_PERI_BASE_VIRT,
+               .pfn            = __phys_to_pfn(AHB_PERI_BASE),
+               .length         = AHB_PERI_SIZE,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)APB0_PERI_BASE_VIRT,
+               .pfn            = __phys_to_pfn(APB0_PERI_BASE),
+               .length         = APB0_PERI_SIZE,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)APB1_PERI_BASE_VIRT,
+               .pfn            = __phys_to_pfn(APB1_PERI_BASE),
+               .length         = APB1_PERI_SIZE,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = (unsigned long)EXT_MEM_CTRL_BASE_VIRT,
+               .pfn            = __phys_to_pfn(EXT_MEM_CTRL_BASE),
+               .length         = EXT_MEM_CTRL_SIZE,
+               .type           = MT_DEVICE,
+       },
+};
+
+/*
+ * Maps common IO regions for tcc8k.
+ *
+ */
+void __init tcc8k_map_common_io(void)
+{
+       iotable_init(tcc8k_io_desc, ARRAY_SIZE(tcc8k_io_desc));
+}
diff --git a/arch/arm/mach-tcc8k/irq.c b/arch/arm/mach-tcc8k/irq.c
new file mode 100644 (file)
index 0000000..34575c4
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) Telechips, Inc.
+ * Copyright (C) 2009-2010 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GNU GPL version 2.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <mach/tcc8k-regs.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+/* Disable IRQ */
+static void tcc8000_mask_ack_irq0(unsigned int irq)
+{
+       PIC0_IEN &= ~(1 << irq);
+       PIC0_CREQ |=  (1 << irq);
+}
+
+static void tcc8000_mask_ack_irq1(unsigned int irq)
+{
+       PIC1_IEN &= ~(1 << (irq - 32));
+       PIC1_CREQ |= (1 << (irq - 32));
+}
+
+static void tcc8000_mask_irq0(unsigned int irq)
+{
+       PIC0_IEN &= ~(1 << irq);
+}
+
+static void tcc8000_mask_irq1(unsigned int irq)
+{
+       PIC1_IEN &= ~(1 << (irq - 32));
+}
+
+static void tcc8000_ack_irq0(unsigned int irq)
+{
+       PIC0_CREQ |=  (1 << irq);
+}
+
+static void tcc8000_ack_irq1(unsigned int irq)
+{
+       PIC1_CREQ |= (1 << (irq - 32));
+}
+
+/* Enable IRQ */
+static void tcc8000_unmask_irq0(unsigned int irq)
+{
+       PIC0_IEN |= (1 << irq);
+       PIC0_INTOEN |= (1 << irq);
+}
+
+static void tcc8000_unmask_irq1(unsigned int irq)
+{
+       PIC1_IEN |= (1 << (irq - 32));
+       PIC1_INTOEN |= (1 << (irq - 32));
+}
+
+static struct irq_chip tcc8000_irq_chip0 = {
+       .name           = "tcc_irq0",
+       .mask           = tcc8000_mask_irq0,
+       .ack            = tcc8000_ack_irq0,
+       .mask_ack       = tcc8000_mask_ack_irq0,
+       .unmask         = tcc8000_unmask_irq0,
+};
+
+static struct irq_chip tcc8000_irq_chip1 = {
+       .name           = "tcc_irq1",
+       .mask           = tcc8000_mask_irq1,
+       .ack            = tcc8000_ack_irq1,
+       .mask_ack       = tcc8000_mask_ack_irq1,
+       .unmask         = tcc8000_unmask_irq1,
+};
+
+void __init tcc8k_init_irq(void)
+{
+       int irqno;
+
+       /* Mask and clear all interrupts */
+       PIC0_IEN = 0x00000000;
+       PIC0_CREQ = 0xffffffff;
+       PIC1_IEN = 0x00000000;
+       PIC1_CREQ = 0xffffffff;
+
+       PIC0_MEN0 = 0x00000003;
+       PIC1_MEN1 = 0x00000003;
+       PIC1_MEN = 0x00000003;
+
+       /* let all IRQs be level triggered */
+       PIC0_TMODE = 0xffffffff;
+       PIC1_TMODE = 0xffffffff;
+       /* all IRQs are IRQs (not FIQs) */
+       PIC0_IRQSEL = 0xffffffff;
+       PIC1_IRQSEL = 0xffffffff;
+
+       for (irqno = 0; irqno < NR_IRQS; irqno++) {
+               if (irqno < 32)
+                       set_irq_chip(irqno, &tcc8000_irq_chip0);
+               else
+                       set_irq_chip(irqno, &tcc8000_irq_chip1);
+               set_irq_handler(irqno, handle_level_irq);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+}
diff --git a/arch/arm/mach-tcc8k/time.c b/arch/arm/mach-tcc8k/time.c
new file mode 100644 (file)
index 0000000..78d0600
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * TCC8000 system timer setup
+ *
+ * (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPL version 2.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+
+#include <asm/mach/time.h>
+
+#include <mach/tcc8k-regs.h>
+#include <mach/irqs.h>
+
+#include "common.h"
+
+static void __iomem *timer_base;
+
+static cycle_t tcc_get_cycles(struct clocksource *cs)
+{
+       return __raw_readl(timer_base + TC32MCNT_OFFS);
+}
+
+static struct clocksource clocksource_tcc = {
+       .name           = "tcc_tc32",
+       .rating         = 200,
+       .read           = tcc_get_cycles,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 28,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int tcc_set_next_event(unsigned long evt,
+                             struct clock_event_device *unused)
+{
+       unsigned long reg = __raw_readl(timer_base + TC32MCNT_OFFS);
+
+       __raw_writel(reg + evt, timer_base + TC32CMP0_OFFS);
+       return 0;
+}
+
+static void tcc_set_mode(enum clock_event_mode mode,
+                               struct clock_event_device *evt)
+{
+       unsigned long tc32irq;
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_ONESHOT:
+               tc32irq = __raw_readl(timer_base + TC32IRQ_OFFS);
+               tc32irq |= TC32IRQ_IRQEN0;
+               __raw_writel(tc32irq, timer_base + TC32IRQ_OFFS);
+               break;
+       case CLOCK_EVT_MODE_SHUTDOWN:
+       case CLOCK_EVT_MODE_UNUSED:
+               tc32irq = __raw_readl(timer_base + TC32IRQ_OFFS);
+               tc32irq &= ~TC32IRQ_IRQEN0;
+               __raw_writel(tc32irq, timer_base + TC32IRQ_OFFS);
+               break;
+       case CLOCK_EVT_MODE_PERIODIC:
+       case CLOCK_EVT_MODE_RESUME:
+               break;
+       }
+}
+
+static irqreturn_t tcc8k_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = dev_id;
+
+       /* Acknowledge TC32 interrupt by reading TC32IRQ */
+       __raw_readl(timer_base + TC32IRQ_OFFS);
+
+       evt->event_handler(evt);
+
+       return IRQ_HANDLED;
+}
+
+static struct clock_event_device clockevent_tcc = {
+       .name           = "tcc_timer1",
+       .features       = CLOCK_EVT_FEAT_ONESHOT,
+       .shift          = 32,
+       .set_mode       = tcc_set_mode,
+       .set_next_event = tcc_set_next_event,
+       .rating         = 200,
+};
+
+static struct irqaction tcc8k_timer_irq = {
+       .name           = "TC32_timer",
+       .flags          = IRQF_DISABLED | IRQF_TIMER,
+       .handler        = tcc8k_timer_interrupt,
+       .dev_id         = &clockevent_tcc,
+};
+
+static int __init tcc_clockevent_init(struct clk *clock)
+{
+       unsigned int c = clk_get_rate(clock);
+
+       clocksource_tcc.mult = clocksource_hz2mult(c,
+                                       clocksource_tcc.shift);
+       clocksource_register(&clocksource_tcc);
+
+       clockevent_tcc.mult = div_sc(c, NSEC_PER_SEC,
+                                       clockevent_tcc.shift);
+       clockevent_tcc.max_delta_ns =
+                       clockevent_delta2ns(0xfffffffe, &clockevent_tcc);
+       clockevent_tcc.min_delta_ns =
+                       clockevent_delta2ns(0xff, &clockevent_tcc);
+
+       clockevent_tcc.cpumask = cpumask_of(0);
+
+       clockevents_register_device(&clockevent_tcc);
+
+       return 0;
+}
+
+void __init tcc8k_timer_init(struct clk *clock, void __iomem *base, int irq)
+{
+       u32 reg;
+
+       timer_base = base;
+       tcc8k_timer_irq.irq = irq;
+
+       /* Enable clocks */
+       clk_enable(clock);
+
+       /* Initialize 32-bit timer */
+       reg = __raw_readl(timer_base + TC32EN_OFFS);
+       reg &= ~TC32EN_ENABLE; /* Disable timer */
+       __raw_writel(reg, timer_base + TC32EN_OFFS);
+       /* Free running timer, counting from 0 to 0xffffffff */
+       __raw_writel(0, timer_base + TC32EN_OFFS);
+       __raw_writel(0, timer_base + TC32LDV_OFFS);
+       reg = __raw_readl(timer_base + TC32IRQ_OFFS);
+       reg |= TC32IRQ_IRQEN0; /* irq at match with CMP0 */
+       __raw_writel(reg, timer_base + TC32IRQ_OFFS);
+
+       __raw_writel(TC32EN_ENABLE, timer_base + TC32EN_OFFS);
+
+       tcc_clockevent_init(clock);
+       setup_irq(irq, &tcc8k_timer_irq);
+}
index 9e305de56be9ac28ab023dbfc4f748c5f260bec1..b9dbdb1289d045339df802c8c5e1c94390650b47 100644 (file)
@@ -115,8 +115,6 @@ static void __init tegra_harmony_init(void)
 
 MACHINE_START(HARMONY, "harmony")
        .boot_params  = 0x00000100,
-       .phys_io        = IO_APB_PHYS,
-       .io_pg_offst    = ((IO_APB_VIRT) >> 18) & 0xfffc,
        .fixup          = tegra_harmony_fixup,
        .init_irq       = tegra_init_irq,
        .init_machine   = tegra_harmony_init,
index 55a39564b43c476e2002b806a8bdff6f6e7c6f44..8ea3bffb4e009f39b56b2262a762b8b28131c814 100644 (file)
 
 #include <mach/io.h>
 
-       .macro  addruart,rx, tmp
-        mrc     p15, 0, \rx, c1, c0
-        tst     \rx, #1                 @ MMU enabled?
-        ldreq   \rx, =IO_APB_PHYS       @ physical
-        ldrne   \rx, =IO_APB_VIRT        @ virtual
+       .macro  addruart, rp, rv
+        ldreq   \rp, =IO_APB_PHYS       @ physical
+        ldrne   \rv, =IO_APB_VIRT        @ virtual
 #if defined(CONFIG_TEGRA_DEBUG_UART_NONE)
 #error "A debug UART must be selected in the kernel config to use DEBUG_LL"
 #elif defined(CONFIG_TEGRA_DEBUG_UARTA)
-        orr     \rx, \rx, #0x6000
+        orr     \rp, \rp, #0x6000
+        orr     \rv, \rv, #0x6000
 #elif defined(CONFIG_TEGRA_DEBUG_UARTB)
-       ldr     \tmp, =0x6040
-        orr     \rx, \rx, \tmp
+        orr     \rp, \rp, #0x6000
+       orr     \rp, \rp, #0x40
+        orr     \rv, \rv, #0x6000
+       orr     \rv, \rv, #0x40
 #elif defined(CONFIG_TEGRA_DEBUG_UARTC)
-        orr     \rx, \rx, #0x6200
+        orr     \rp, \rp, #0x6200
+        orr     \rv, \rv, #0x6200
 #elif defined(CONFIG_TEGRA_DEBUG_UARTD)
-        orr     \rx, \rx, #0x6300
+        orr     \rp, \rp, #0x6300
+        orr     \rv, \rv, #0x6300
 #elif defined(CONFIG_TEGRA_DEBUG_UARTE)
-        orr     \rx, \rx, #0x6400
+        orr     \rp, \rp, #0x6400
+        orr     \rv, \rv, #0x6400
 #endif
        .endm
 
index 8b42dab79a70ca17499b55c0ba9042e278428de5..e4a34a35a54466a1aecc7b3ea0ffe67c9dcee3df 100644 (file)
@@ -1,16 +1,8 @@
 #ifndef ASMARM_ARCH_SMP_H
 #define ASMARM_ARCH_SMP_H
 
-
 #include <asm/hardware/gic.h>
-
-#define hard_smp_processor_id()                        \
-       ({                                              \
-               unsigned int cpunum;                    \
-               __asm__("mrc p15, 0, %0, c0, c0, 5"     \
-                       : "=r" (cpunum));               \
-               cpunum &= 0x0F;                         \
-       })
+#include <asm/smp_mpidr.h>
 
 /*
  * We use IRQ1 as the IPI
index 5f55012b7c9edb99d32c5bcb89358686908773d7..03f79361259400596a790949073e1ce617e99bff 100644 (file)
@@ -46,7 +46,6 @@ static ssize_t dummy_looptest(struct device *dev,
         * struct, this is just used here to alter the behaviour of the chip
         * in order to perform tests.
         */
-       struct pl022_config_chip *chip_info = spi->controller_data;
        int status;
        u8 txbuf[14] = {0xDE, 0xAD, 0xBE, 0xEF, 0x2B, 0xAD,
                        0xCA, 0xFE, 0xBA, 0xBE, 0xB1, 0x05,
@@ -72,7 +71,7 @@ static ssize_t dummy_looptest(struct device *dev,
         * Force chip to 8 bit mode
         * WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC!
         */
-       chip_info->data_size = SSP_DATA_BITS_8;
+       spi->bits_per_word = 8;
        /* You should NOT DO THIS EITHER */
        spi->master->setup(spi);
 
@@ -159,7 +158,7 @@ static ssize_t dummy_looptest(struct device *dev,
         * Force chip to 16 bit mode
         * WARNING: NEVER DO THIS IN REAL DRIVER CODE, THIS SHOULD BE STATIC!
         */
-       chip_info->data_size = SSP_DATA_BITS_16;
+       spi->bits_per_word = 16;
        /* You should NOT DO THIS EITHER */
        spi->master->setup(spi);
 
index 92c12420256ffdc518d8a4102198e42365039032..df715707bead4144f2650974a0c8998145757877 100644 (file)
  */
 #include <mach/hardware.h>
 
-       .macro  addruart, rx, tmp
+       .macro  addruart, rp, rv
        /* If we move the address 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
+       ldr     \rp,      = U300_SLOW_PER_PHYS_BASE @ MMU off, physical address
+       ldr     \rv,      = U300_SLOW_PER_VIRT_BASE @ MMU on, virtual address
+       orr     \rp, \rp, #0x00003000
+       orr     \rv, \rv, #0x00003000
        .endm
 
 #include <asm/hardware/debug-pl01x.S>
index f0e887bea30e6b18218c2bac2e6c4f1d8a1b50bb..edb2c0d255c2a1671cae12e6704da28e6b66cb8d 100644 (file)
@@ -30,8 +30,6 @@ static void select_dummy_chip(u32 chipselect)
 }
 
 struct pl022_config_chip dummy_chip_info = {
-       /* Nominally this is LOOPBACK_DISABLED, but this is our dummy chip! */
-       .lbm = LOOPBACK_ENABLED,
        /*
         * available POLLING_TRANSFER and INTERRUPT_TRANSFER,
         * DMA_TRANSFER does not work
@@ -42,14 +40,8 @@ struct pl022_config_chip dummy_chip_info = {
        .hierarchy = SSP_MASTER,
        /* 0 = drive TX even as slave, 1 = do not drive TX as slave */
        .slave_tx_disable = 0,
-       /* LSB first */
-       .endian_tx = SSP_TX_LSB,
-       .endian_rx = SSP_RX_LSB,
-       .data_size = SSP_DATA_BITS_8, /* used to be 12 in some default */
        .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
        .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
-       .clk_phase = SSP_CLK_SECOND_EDGE,
-       .clk_pol = SSP_CLK_POL_IDLE_LOW,
        .ctrl_len = SSP_BITS_12,
        .wait_state = SSP_MWIRE_WAIT_ZERO,
        .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
@@ -75,7 +67,7 @@ static struct spi_board_info u300_spi_devices[] = {
                .bus_num        = 0, /* Only one bus on this chip */
                .chip_select    = 0,
                /* Means SPI_CS_HIGH, change if e.g low CS */
-               .mode           = 0,
+               .mode           = SPI_MODE_1 | SPI_LSB_FIRST | SPI_LOOP,
        },
 #endif
 };
index bfcda9820888b6083fd10779b63fe89580f76036..07c35a846424f5736b33f365efb70b7248f61a1e 100644 (file)
@@ -61,8 +61,6 @@ static void __init u300_init_machine(void)
 
 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,
        .reserve        = u300_reserve,
index 6625e5bbf4d6384cdbbde138dc3a22b30a66b549..2dd44a0b461562fb5062902f72c1e6c8d4da2612 100644 (file)
@@ -21,9 +21,7 @@ config MACH_U8500_MOP
        bool "U8500 Development platform"
        select UX500_SOC_DB8500
        help
-         Include support for mop500 development platform
-         based on U8500 architecture. The platform is based
-         on early drop silicon version of 8500.
+         Include support for the mop500 development platform.
 
 config MACH_U5500
        bool "U5500 Development platform"
@@ -39,4 +37,18 @@ config UX500_DEBUG_UART
          Choose the UART on which kernel low-level debug messages should be
          output.
 
+config U5500_MODEM_IRQ
+       bool "Modem IRQ support"
+       depends on MACH_U5500
+       default y
+       help
+         Add support for handling IRQ:s from modem side
+
+config U5500_MBOX
+       bool "Mailbox support"
+       depends on MACH_U5500 && U5500_MODEM_IRQ
+       default y
+       help
+         Add support for U5500 mailbox communication with modem side
+
 endif
index 4556aea9c3c5acfcd1aa9ed860dffcd9e06cabaf..9e27a84433cbd27829e3099b120c39099bee56cf 100644 (file)
@@ -4,8 +4,12 @@
 
 obj-y                          := clock.o cpu.o devices.o
 obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o
-obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
-obj-$(CONFIG_MACH_U8500_MOP)   += board-mop500.o
+obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o
+obj-$(CONFIG_MACH_U8500_MOP)   += board-mop500.o board-mop500-sdi.o
 obj-$(CONFIG_MACH_U5500)       += board-u5500.o
 obj-$(CONFIG_SMP)              += platsmp.o headsmp.o
+obj-$(CONFIG_HOTPLUG_CPU)      += hotplug.o
 obj-$(CONFIG_LOCAL_TIMERS)     += localtimer.o
+obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o
+obj-$(CONFIG_U5500_MODEM_IRQ)  += modem_irq.o
+obj-$(CONFIG_U5500_MBOX)       += mbox.o
diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c
new file mode 100644 (file)
index 0000000..1187f1f
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ * MOP500 board specific initialization for regulators
+ */
+#include <linux/kernel.h>
+#include <linux/regulator/machine.h>
+
+/* supplies to the display/camera */
+static struct regulator_init_data ab8500_vaux1_regulator = {
+       .constraints = {
+               .name = "V-DISPLAY",
+               .min_uV = 2500000,
+               .max_uV = 2900000,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+                                       REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supplies to the on-board eMMC */
+static struct regulator_init_data ab8500_vaux2_regulator = {
+       .constraints = {
+               .name = "V-eMMC1",
+               .min_uV = 1100000,
+               .max_uV = 3300000,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+                                       REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for VAUX3, supplies to SDcard slots */
+static struct regulator_init_data ab8500_vaux3_regulator = {
+       .constraints = {
+               .name = "V-MMC-SD",
+               .min_uV = 1100000,
+               .max_uV = 3300000,
+               .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE|
+                                       REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for tvout, gpadc, TVOUT LDO */
+static struct regulator_init_data ab8500_vtvout_init = {
+       .constraints = {
+               .name = "V-TVOUT",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for ab8500-vaudio, VAUDIO LDO */
+static struct regulator_init_data ab8500_vaudio_init = {
+       .constraints = {
+               .name = "V-AUD",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for v-anamic1 VAMic1-LDO */
+static struct regulator_init_data ab8500_vamic1_init = {
+       .constraints = {
+               .name = "V-AMIC1",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */
+static struct regulator_init_data ab8500_vamic2_init = {
+       .constraints = {
+               .name = "V-AMIC2",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for v-dmic, VDMIC LDO */
+static struct regulator_init_data ab8500_vdmic_init = {
+       .constraints = {
+               .name = "V-DMIC",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for v-intcore12, VINTCORE12 LDO */
+static struct regulator_init_data ab8500_vintcore_init = {
+       .constraints = {
+               .name = "V-INTCORE",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
+/* supply for U8500 CSI/DSI, VANA LDO */
+static struct regulator_init_data ab8500_vana_init = {
+       .constraints = {
+               .name = "V-CSI/DSI",
+               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+       },
+};
+
diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c
new file mode 100644 (file)
index 0000000..bac9956
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Hanumath Prasad <hanumath.prasad@stericsson.com>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/kernel.h>
+#include <linux/gpio.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/mmci.h>
+#include <linux/mmc/host.h>
+#include <linux/platform_device.h>
+
+#include <plat/pincfg.h>
+#include <mach/devices.h>
+#include <mach/hardware.h>
+
+#include "pins-db8500.h"
+#include "board-mop500.h"
+
+static pin_cfg_t mop500_sdi_pins[] = {
+       /* SDI4 (on-board eMMC) */
+       GPIO197_MC4_DAT3,
+       GPIO198_MC4_DAT2,
+       GPIO199_MC4_DAT1,
+       GPIO200_MC4_DAT0,
+       GPIO201_MC4_CMD,
+       GPIO202_MC4_FBCLK,
+       GPIO203_MC4_CLK,
+       GPIO204_MC4_DAT7,
+       GPIO205_MC4_DAT6,
+       GPIO206_MC4_DAT5,
+       GPIO207_MC4_DAT4,
+};
+
+static pin_cfg_t mop500_sdi2_pins[] = {
+       /* SDI2 (POP eMMC) */
+       GPIO128_MC2_CLK,
+       GPIO129_MC2_CMD,
+       GPIO130_MC2_FBCLK,
+       GPIO131_MC2_DAT0,
+       GPIO132_MC2_DAT1,
+       GPIO133_MC2_DAT2,
+       GPIO134_MC2_DAT3,
+       GPIO135_MC2_DAT4,
+       GPIO136_MC2_DAT5,
+       GPIO137_MC2_DAT6,
+       GPIO138_MC2_DAT7,
+};
+
+/*
+ * SDI 2 (POP eMMC, not on DB8500ed)
+ */
+
+static struct mmci_platform_data mop500_sdi2_data = {
+       .ocr_mask       = MMC_VDD_165_195,
+       .f_max          = 100000000,
+       .capabilities   = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
+       .gpio_cd        = -1,
+       .gpio_wp        = -1,
+};
+
+/*
+ * SDI 4 (on-board eMMC)
+ */
+
+static struct mmci_platform_data mop500_sdi4_data = {
+       .ocr_mask       = MMC_VDD_29_30,
+       .f_max          = 100000000,
+       .capabilities   = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA |
+                         MMC_CAP_MMC_HIGHSPEED,
+       .gpio_cd        = -1,
+       .gpio_wp        = -1,
+};
+
+void mop500_sdi_init(void)
+{
+       nmk_config_pins(mop500_sdi_pins, ARRAY_SIZE(mop500_sdi_pins));
+
+       u8500_sdi2_device.dev.platform_data = &mop500_sdi2_data;
+       u8500_sdi4_device.dev.platform_data = &mop500_sdi4_data;
+
+       if (!cpu_is_u8500ed()) {
+               nmk_config_pins(mop500_sdi2_pins, ARRAY_SIZE(mop500_sdi2_pins));
+               amba_device_register(&u8500_sdi2_device, &iomem_resource);
+       }
+
+       /* On-board eMMC */
+       amba_device_register(&u8500_sdi4_device, &iomem_resource);
+}
index 0e8fd135a57dee1d56afb200208d62bf7d756fa8..fcb587f825ccf6c7b195277365e29e5aa58d2710 100644 (file)
 #include <mach/hardware.h>
 #include <mach/setup.h>
 #include <mach/devices.h>
+#include <mach/irqs.h>
 
 #include "pins-db8500.h"
+#include "board-mop500.h"
 
 static pin_cfg_t mop500_pins[] = {
        /* SSP0 */
@@ -55,19 +57,13 @@ static void ab4500_spi_cs_control(u32 command)
 }
 
 struct pl022_config_chip ab4500_chip_info = {
-       .lbm = LOOPBACK_DISABLED,
        .com_mode = INTERRUPT_TRANSFER,
        .iface = SSP_INTERFACE_MOTOROLA_SPI,
        /* we can act as master only */
        .hierarchy = SSP_MASTER,
        .slave_tx_disable = 0,
-       .endian_rx = SSP_RX_MSB,
-       .endian_tx = SSP_TX_MSB,
-       .data_size = SSP_DATA_BITS_24,
        .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
        .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
-       .clk_phase = SSP_CLK_SECOND_EDGE,
-       .clk_pol = SSP_CLK_POL_IDLE_HIGH,
        .cs_control = ab4500_spi_cs_control,
 };
 
@@ -75,15 +71,33 @@ static struct ab8500_platform_data ab8500_platdata = {
        .irq_base       = MOP500_AB8500_IRQ_BASE,
 };
 
-static struct spi_board_info u8500_spi_devices[] = {
+static struct resource ab8500_resources[] = {
+       [0] = {
+               .start = IRQ_AB8500,
+               .end = IRQ_AB8500,
+               .flags = IORESOURCE_IRQ
+       }
+};
+
+struct platform_device ab8500_device = {
+       .name = "ab8500-i2c",
+       .id = 0,
+       .dev = {
+               .platform_data = &ab8500_platdata,
+       },
+       .num_resources = 1,
+       .resource = ab8500_resources,
+};
+
+static struct spi_board_info ab8500_spi_devices[] = {
        {
-               .modalias = "ab8500",
+               .modalias = "ab8500-spi",
                .controller_data = &ab4500_chip_info,
                .platform_data = &ab8500_platdata,
                .max_speed_hz = 12000000,
                .bus_num = 0,
                .chip_select = 0,
-               .mode = SPI_MODE_0,
+               .mode = SPI_MODE_3,
                .irq = IRQ_DB8500_AB8500,
        },
 };
@@ -163,14 +177,18 @@ static void __init u8500_init_machine(void)
 
        platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
 
-       spi_register_board_info(u8500_spi_devices,
-                       ARRAY_SIZE(u8500_spi_devices));
+       mop500_sdi_init();
+
+       /* If HW is early drop (ED) or V1.0 then use SPI to access AB8500 */
+       if (cpu_is_u8500ed() || cpu_is_u8500v10())
+               spi_register_board_info(ab8500_spi_devices,
+                       ARRAY_SIZE(ab8500_spi_devices));
+       else /* If HW is v.1.1 or later use I2C to access AB8500 */
+               platform_device_register(&ab8500_device);
 }
 
 MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
        /* Maintainer: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> */
-       .phys_io        = U8500_UART2_BASE,
-       .io_pg_offst    = (IO_ADDRESS(U8500_UART2_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x100,
        .map_io         = u8500_map_io,
        .init_irq       = ux500_init_irq,
diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h
new file mode 100644 (file)
index 0000000..2d24032
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __BOARD_MOP500_H
+#define __BOARD_MOP500_H
+
+extern void mop500_sdi_init(void);
+
+#endif
index 4430e69cf538b5b8a1b7d95950b715789c8ac1ba..1ca094a45e71df68ebd123ecd03092f8eedb89f1 100644 (file)
@@ -31,8 +31,6 @@ static void __init u5500_init_machine(void)
 }
 
 MACHINE_START(U8500, "ST-Ericsson U5500 Platform")
-       .phys_io        = UX500_UART0_BASE,
-       .io_pg_offst    = (IO_ADDRESS(UX500_UART0_BASE) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = u5500_map_io,
        .init_irq       = ux500_init_irq,
index e9278f6d67aa7529f2408fd15fd5eab1bfecdb20..2f87075e9d6f02a21a08c28f7c4ae3a04e69257e 100644 (file)
@@ -14,6 +14,7 @@
 #include <mach/hardware.h>
 #include <mach/devices.h>
 #include <mach/setup.h>
+#include <mach/irqs.h>
 
 static struct map_desc u5500_io_desc[] __initdata = {
        __IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K),
@@ -24,6 +25,90 @@ static struct map_desc u5500_io_desc[] __initdata = {
        __IO_DEV_DESC(U5500_PRCMU_BASE, SZ_4K),
 };
 
+static struct resource mbox0_resources[] = {
+       {
+               .name = "mbox_peer",
+               .start = U5500_MBOX0_PEER_START,
+               .end = U5500_MBOX0_PEER_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_local",
+               .start = U5500_MBOX0_LOCAL_START,
+               .end = U5500_MBOX0_LOCAL_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_irq",
+               .start = MBOX_PAIR0_VIRT_IRQ,
+               .end = MBOX_PAIR0_VIRT_IRQ,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static struct resource mbox1_resources[] = {
+       {
+               .name = "mbox_peer",
+               .start = U5500_MBOX1_PEER_START,
+               .end = U5500_MBOX1_PEER_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_local",
+               .start = U5500_MBOX1_LOCAL_START,
+               .end = U5500_MBOX1_LOCAL_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_irq",
+               .start = MBOX_PAIR1_VIRT_IRQ,
+               .end = MBOX_PAIR1_VIRT_IRQ,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static struct resource mbox2_resources[] = {
+       {
+               .name = "mbox_peer",
+               .start = U5500_MBOX2_PEER_START,
+               .end = U5500_MBOX2_PEER_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_local",
+               .start = U5500_MBOX2_LOCAL_START,
+               .end = U5500_MBOX2_LOCAL_END,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .name = "mbox_irq",
+               .start = MBOX_PAIR2_VIRT_IRQ,
+               .end = MBOX_PAIR2_VIRT_IRQ,
+               .flags = IORESOURCE_IRQ,
+       }
+};
+
+static struct platform_device mbox0_device = {
+       .id = 0,
+       .name = "mbox",
+       .resource = mbox0_resources,
+       .num_resources = ARRAY_SIZE(mbox0_resources),
+};
+
+static struct platform_device mbox1_device = {
+       .id = 1,
+       .name = "mbox",
+       .resource = mbox1_resources,
+       .num_resources = ARRAY_SIZE(mbox1_resources),
+};
+
+static struct platform_device mbox2_device = {
+       .id = 2,
+       .name = "mbox",
+       .resource = mbox2_resources,
+       .num_resources = ARRAY_SIZE(mbox2_resources),
+};
+
 static struct platform_device *u5500_platform_devs[] __initdata = {
        &u5500_gpio_devs[0],
        &u5500_gpio_devs[1],
@@ -33,6 +118,9 @@ static struct platform_device *u5500_platform_devs[] __initdata = {
        &u5500_gpio_devs[5],
        &u5500_gpio_devs[6],
        &u5500_gpio_devs[7],
+       &mbox0_device,
+       &mbox1_device,
+       &mbox2_device,
 };
 
 void __init u5500_map_io(void)
index f21c444edd99f76db8b78ccd1b1bcfc1464c181b..4acab7544b3c1e95ea9a9f2c73cf0f1ffd34847d 100644 (file)
@@ -38,10 +38,12 @@ static struct platform_device *platform_devs[] __initdata = {
 /* minimum static i/o mapping required to boot U8500 platforms */
 static struct map_desc u8500_io_desc[] __initdata = {
        __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
+       __IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
        __IO_DEV_DESC(U8500_GPIO3_BASE, SZ_4K),
+       __MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M),
 };
 
 static struct map_desc u8500ed_io_desc[] __initdata = {
@@ -53,6 +55,69 @@ static struct map_desc u8500v1_io_desc[] __initdata = {
        __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K),
 };
 
+/*
+ * Functions to differentiate between later ASICs
+ * We look into the end of the ROM to locate the hardcoded ASIC ID.
+ * This is only needed to differentiate between minor revisions and
+ * process variants of an ASIC, the major revisions are encoded in
+ * the cpuid.
+ */
+#define U8500_ASIC_ID_LOC_ED_V1        (U8500_BOOT_ROM_BASE + 0x1FFF4)
+#define U8500_ASIC_ID_LOC_V2   (U8500_BOOT_ROM_BASE + 0x1DBF4)
+#define U8500_ASIC_REV_ED      0x01
+#define U8500_ASIC_REV_V10     0xA0
+#define U8500_ASIC_REV_V11     0xA1
+#define U8500_ASIC_REV_V20     0xB0
+
+/**
+ * struct db8500_asic_id - fields of the ASIC ID
+ * @process: the manufacturing process, 0x40 is 40 nm
+ *  0x00 is "standard"
+ * @partnumber: hithereto 0x8500 for DB8500
+ * @revision: version code in the series
+ * This field definion is not formally defined but makes
+ * sense.
+ */
+struct db8500_asic_id {
+       u8 process;
+       u16 partnumber;
+       u8 revision;
+};
+
+/* This isn't going to change at runtime */
+static struct db8500_asic_id db8500_id;
+
+static void __init get_db8500_asic_id(void)
+{
+       u32 asicid;
+
+       if (cpu_is_u8500v1() || cpu_is_u8500ed())
+               asicid = readl(__io_address(U8500_ASIC_ID_LOC_ED_V1));
+       else if (cpu_is_u8500v2())
+               asicid = readl(__io_address(U8500_ASIC_ID_LOC_V2));
+       else
+               BUG();
+
+       db8500_id.process = (asicid >> 24);
+       db8500_id.partnumber = (asicid >> 16) & 0xFFFFU;
+       db8500_id.revision = asicid & 0xFFU;
+}
+
+bool cpu_is_u8500v10(void)
+{
+       return (db8500_id.revision == U8500_ASIC_REV_V10);
+}
+
+bool cpu_is_u8500v11(void)
+{
+       return (db8500_id.revision == U8500_ASIC_REV_V11);
+}
+
+bool cpu_is_u8500v20(void)
+{
+       return (db8500_id.revision == U8500_ASIC_REV_V20);
+}
+
 void __init u8500_map_io(void)
 {
        ux500_map_io();
@@ -63,6 +128,9 @@ void __init u8500_map_io(void)
                iotable_init(u8500ed_io_desc, ARRAY_SIZE(u8500ed_io_desc));
        else
                iotable_init(u8500v1_io_desc, ARRAY_SIZE(u8500v1_io_desc));
+
+       /* Read out the ASIC ID as early as we can */
+       get_db8500_asic_id();
 }
 
 /*
@@ -70,6 +138,20 @@ void __init u8500_map_io(void)
  */
 void __init u8500_init_devices(void)
 {
+       /* Display some ASIC boilerplate */
+       pr_info("DB8500: process: %02x, revision ID: 0x%02x\n",
+               db8500_id.process, db8500_id.revision);
+       if (cpu_is_u8500ed())
+               pr_info("DB8500: Early Drop (ED)\n");
+       else if (cpu_is_u8500v10())
+               pr_info("DB8500: version 1.0\n");
+       else if (cpu_is_u8500v11())
+               pr_info("DB8500: version 1.1\n");
+       else if (cpu_is_u8500v20())
+               pr_info("DB8500: version 2.0\n");
+       else
+               pr_warning("ASIC: UNKNOWN SILICON VERSION!\n");
+
        ux500_init_devices();
 
        if (cpu_is_u8500ed())
index 9280d25611117d1224ad48811c7bc85597c18fce..40032fecbc165538c9822fac801d7e72780d4c3b 100644 (file)
@@ -110,6 +110,82 @@ struct platform_device u8500_i2c4_device = {
        .num_resources  = ARRAY_SIZE(u8500_i2c4_resources),
 };
 
+/*
+ * SD/MMC
+ */
+
+struct amba_device u8500_sdi0_device = {
+       .dev            = {
+               .init_name = "sdi0",
+       },
+       .res            = {
+               .start  = U8500_SDI0_BASE,
+               .end    = U8500_SDI0_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC0, NO_IRQ},
+};
+
+struct amba_device u8500_sdi1_device = {
+       .dev            = {
+               .init_name = "sdi1",
+       },
+       .res            = {
+               .start  = U8500_SDI1_BASE,
+               .end    = U8500_SDI1_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC1, NO_IRQ},
+};
+
+struct amba_device u8500_sdi2_device = {
+       .dev            = {
+               .init_name = "sdi2",
+       },
+       .res            = {
+               .start  = U8500_SDI2_BASE,
+               .end    = U8500_SDI2_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC2, NO_IRQ},
+};
+
+struct amba_device u8500_sdi3_device = {
+       .dev            = {
+               .init_name = "sdi3",
+       },
+       .res            = {
+               .start  = U8500_SDI3_BASE,
+               .end    = U8500_SDI3_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC3, NO_IRQ},
+};
+
+struct amba_device u8500_sdi4_device = {
+       .dev            = {
+               .init_name = "sdi4",
+       },
+       .res            = {
+               .start  = U8500_SDI4_BASE,
+               .end    = U8500_SDI4_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC4, NO_IRQ},
+};
+
+struct amba_device u8500_sdi5_device = {
+       .dev            = {
+               .init_name = "sdi5",
+       },
+       .res            = {
+               .start  = U8500_SDI5_BASE,
+               .end    = U8500_SDI5_BASE + SZ_4K - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+       .irq            = {IRQ_DB8500_SDMMC5, NO_IRQ},
+};
+
 static struct resource dma40_resources[] = {
        [0] = {
                .start = U8500_DMA_BASE,
@@ -170,23 +246,23 @@ struct stedma40_chan_cfg dma40_memcpy_conf_log = {
  * Mapping between destination event lines and physical device address.
  * The event line is tied to a device and therefor the address is constant.
  */
-static const dma_addr_t dma40_tx_map[STEDMA40_NR_DEV];
+static const dma_addr_t dma40_tx_map[DB8500_DMA_NR_DEV];
 
 /* Mapping between source event lines and physical device address */
-static const dma_addr_t dma40_rx_map[STEDMA40_NR_DEV];
+static const dma_addr_t dma40_rx_map[DB8500_DMA_NR_DEV];
 
 /* Reserved event lines for memcpy only */
 static int dma40_memcpy_event[] = {
-       STEDMA40_MEMCPY_TX_0,
-       STEDMA40_MEMCPY_TX_1,
-       STEDMA40_MEMCPY_TX_2,
-       STEDMA40_MEMCPY_TX_3,
-       STEDMA40_MEMCPY_TX_4,
-       STEDMA40_MEMCPY_TX_5,
+       DB8500_DMA_MEMCPY_TX_0,
+       DB8500_DMA_MEMCPY_TX_1,
+       DB8500_DMA_MEMCPY_TX_2,
+       DB8500_DMA_MEMCPY_TX_3,
+       DB8500_DMA_MEMCPY_TX_4,
+       DB8500_DMA_MEMCPY_TX_5,
 };
 
 static struct stedma40_platform_data dma40_plat_data = {
-       .dev_len = STEDMA40_NR_DEV,
+       .dev_len = DB8500_DMA_NR_DEV,
        .dev_rx = dma40_rx_map,
        .dev_tx = dma40_tx_map,
        .memcpy = dma40_memcpy_event,
diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c
new file mode 100644 (file)
index 0000000..b782a03
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *     Based on ARM realview platform
+ *
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/smp.h>
+#include <linux/completion.h>
+
+#include <asm/cacheflush.h>
+
+extern volatile int pen_release;
+
+static DECLARE_COMPLETION(cpu_killed);
+
+static inline void platform_do_lowpower(unsigned int cpu)
+{
+       flush_cache_all();
+
+       /* we put the platform to just WFI */
+       for (;;) {
+               __asm__ __volatile__("dsb\n\t" "wfi\n\t"
+                               : : : "memory");
+               if (pen_release == cpu) {
+                       /*
+                        * OK, proper wakeup, we're done
+                        */
+                       break;
+               }
+       }
+}
+
+int platform_cpu_kill(unsigned int cpu)
+{
+       return wait_for_completion_timeout(&cpu_killed, 5000);
+}
+
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+void platform_cpu_die(unsigned int cpu)
+{
+#ifdef DEBUG
+       unsigned int this_cpu = hard_smp_processor_id();
+
+       if (cpu != this_cpu) {
+               printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n",
+                          this_cpu, cpu);
+               BUG();
+       }
+#endif
+
+       printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
+       complete(&cpu_killed);
+
+       /* directly enter low power state, skipping secure registers */
+       platform_do_lowpower(cpu);
+}
+
+int platform_cpu_disable(unsigned int cpu)
+{
+       /*
+        * we don't allow CPU 0 to be shutdown (it is still too special
+        * e.g. clock tick interrupts)
+        */
+       return cpu == 0 ? -EPERM : 0;
+}
index 545c80fc802484250f1eb9e7550f456a4e07b800..3eafc0e24ba58d75671221a60bdcafbb68388a27 100644 (file)
 #define U5500_GPIOBANK6_BASE   (U5500_GPIO4_BASE + 0x80)
 #define U5500_GPIOBANK7_BASE   (U5500_GPIO4_BASE + 0x100)
 
+#define U5500_MBOX_BASE                (U5500_MODEM_BASE + 0xFFD1000)
+#define U5500_MBOX0_PEER_START (U5500_MBOX_BASE + 0x40)
+#define U5500_MBOX0_PEER_END   (U5500_MBOX_BASE + 0x5F)
+#define U5500_MBOX0_LOCAL_START        (U5500_MBOX_BASE + 0x60)
+#define U5500_MBOX0_LOCAL_END  (U5500_MBOX_BASE + 0x7F)
+#define U5500_MBOX1_PEER_START (U5500_MBOX_BASE + 0x80)
+#define U5500_MBOX1_PEER_END   (U5500_MBOX_BASE + 0x9F)
+#define U5500_MBOX1_LOCAL_START        (U5500_MBOX_BASE + 0xA0)
+#define U5500_MBOX1_LOCAL_END  (U5500_MBOX_BASE + 0xBF)
+#define U5500_MBOX2_PEER_START (U5500_MBOX_BASE + 0x00)
+#define U5500_MBOX2_PEER_END   (U5500_MBOX_BASE + 0x1F)
+#define U5500_MBOX2_LOCAL_START        (U5500_MBOX_BASE + 0x20)
+#define U5500_MBOX2_LOCAL_END  (U5500_MBOX_BASE + 0x3F)
+
 #endif
index f000218210c947ea406692ee1663ee7ac5395ab9..f07d0986409d2341771a39e1298538d466192f36 100644 (file)
@@ -30,8 +30,6 @@
 #define U8500_ICN_BASE         0x81000000
 
 #define U8500_BOOT_ROM_BASE    0x90000000
-/* ASIC ID is at 0xff4 offset within this region */
-#define U8500_ASIC_ID_BASE     0x9001F000
 
 #define U8500_PER6_BASE                0xa03c0000
 #define U8500_PER5_BASE                0xa03e0000
index c5203b7ea5521596f929bde20cd35708a2419e5c..be7c0f14e310abed1fd65267f07142beda12ee0c 100644 (file)
 #define UX500_UART(n)  __UX500_UART(n)
 #define UART_BASE      UX500_UART(CONFIG_UX500_DEBUG_UART)
 
-       .macro  addruart, rx, tmp
-       mrc     p15, 0, \rx, c1, c0
-       tst     \rx, #1                                 @ MMU enabled?
-       ldreq   \rx, =UART_BASE                         @ no, physical address
-       ldrne   \rx, =IO_ADDRESS(UART_BASE)             @ yes, virtual address
+       .macro  addruart, rp, rv
+       ldr     \rp, =UART_BASE                         @ no, physical address
+       ldr     \rv, =IO_ADDRESS(UART_BASE)             @ yes, virtual address
        .endm
 
 #include <asm/hardware/debug-pl01x.S>
index c2b2f257494760ae33d4d41645d85395c12dac1a..33a120c2e82eaf0749e480149cdd2539c671aab8 100644 (file)
@@ -27,6 +27,13 @@ extern struct platform_device u8500_i2c0_device;
 extern struct platform_device u8500_i2c4_device;
 extern struct platform_device u8500_dma40_device;
 
+extern struct amba_device u8500_sdi0_device;
+extern struct amba_device u8500_sdi1_device;
+extern struct amba_device u8500_sdi2_device;
+extern struct amba_device u8500_sdi3_device;
+extern struct amba_device u8500_sdi4_device;
+extern struct amba_device u8500_sdi5_device;
+
 void dma40_u8500ed_fixup(void);
 
 #endif
index 8656379a83093c475c9eaf3b40b8cabb051f771d..32e883a8f2a22af6f122a9d529a6d85541d70b64 100644 (file)
@@ -104,16 +104,35 @@ static inline bool cpu_is_u8500(void)
 #endif
 }
 
+#define CPUID_DB8500ED 0x410fc090
+#define CPUID_DB8500V1 0x411fc091
+#define CPUID_DB8500V2 0x412fc091
+
 static inline bool cpu_is_u8500ed(void)
 {
-       return cpu_is_u8500() && (read_cpuid_id() & 15) == 0;
+       return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500ED);
 }
 
 static inline bool cpu_is_u8500v1(void)
 {
-       return cpu_is_u8500() && (read_cpuid_id() & 15) == 1;
+       return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V1);
+}
+
+static inline bool cpu_is_u8500v2(void)
+{
+       return cpu_is_u8500() && (read_cpuid_id() == CPUID_DB8500V2);
 }
 
+#ifdef CONFIG_UX500_SOC_DB8500
+bool cpu_is_u8500v10(void);
+bool cpu_is_u8500v11(void);
+bool cpu_is_u8500v20(void);
+#else
+static inline bool cpu_is_u8500v10(void) { return false; }
+static inline bool cpu_is_u8500v11(void) { return false; }
+static inline bool cpu_is_u8500v20(void) { return false; }
+#endif
+
 static inline bool cpu_is_u5500(void)
 {
 #ifdef CONFIG_UX500_SOC_DB5500
index 6fbfe5e2065a76618f8fa88dcb24e5918ad205f6..bfa123dbec3b15d993d76f24509773c7e9777141 100644 (file)
@@ -61,6 +61,7 @@
 #define IRQ_DB5500_SDMMC0              (IRQ_SHPI_START + 60)
 #define IRQ_DB5500_HSEM                        (IRQ_SHPI_START + 61)
 #define IRQ_DB5500_SBAG                        (IRQ_SHPI_START + 63)
+#define IRQ_DB5500_MODEM               (IRQ_SHPI_START + 65)
 #define IRQ_DB5500_SPI1                        (IRQ_SHPI_START + 96)
 #define IRQ_DB5500_MSP2                        (IRQ_SHPI_START + 98)
 #define IRQ_DB5500_SRPTIMER            (IRQ_SHPI_START + 101)
index 10385bdc2b7760506af333077fd1fd34fe5972fc..693aa57de88d995375db54b3d9cefbffc25679c1 100644 (file)
@@ -40,7 +40,8 @@
 #define IRQ_HSIR_CH1_OVRRUN    (IRQ_SHPI_START + 33)
 #define IRQ_HSIR_CH2_OVRRUN    (IRQ_SHPI_START + 34)
 #define IRQ_HSIR_CH3_OVRRUN    (IRQ_SHPI_START + 35)
-#define IRQ_AB4500             (IRQ_SHPI_START + 40)
+#define IRQ_AB8500             (IRQ_SHPI_START + 40)
+#define IRQ_PRCMU               (IRQ_SHPI_START + 47)
 #define IRQ_DISP               (IRQ_SHPI_START + 48)
 #define IRQ_SiPI3              (IRQ_SHPI_START + 49)
 #define IRQ_I2C4               (IRQ_SHPI_START + 51)
 #include <mach/irqs-board-mop500.h>
 #endif
 
-#define NR_IRQS                                IRQ_BOARD_END
+/*
+ * After the board specific IRQ:s we reserve a range of IRQ:s in which virtual
+ * IRQ:s representing modem IRQ:s can be allocated
+ */
+#define IRQ_MODEM_EVENTS_BASE (IRQ_BOARD_END + 1)
+#define IRQ_MODEM_EVENTS_NBR 72
+#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
+
+/* List of virtual IRQ:s that are allocated from the range above */
+#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
+#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
+#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
+
+#define NR_IRQS                                IRQ_MODEM_EVENTS_END
 
 #endif /* ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-ux500/include/mach/mbox.h b/arch/arm/mach-ux500/include/mach/mbox.h
new file mode 100644 (file)
index 0000000..7f9da4d
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef __INC_STE_MBOX_H
+#define __INC_STE_MBOX_H
+
+#define MBOX_BUF_SIZE 16
+#define MBOX_NAME_SIZE 8
+
+/**
+  * mbox_recv_cb_t - Definition of the mailbox callback.
+  * @mbox_msg: The mailbox message.
+  * @priv:     The clients private data as specified in the call to mbox_setup.
+  *
+  * This function will be called upon reception of new mailbox messages.
+  */
+typedef void mbox_recv_cb_t (u32 mbox_msg, void *priv);
+
+/**
+  * struct mbox - Mailbox instance struct
+  * @list:             Linked list head.
+  * @pdev:             Pointer to device struct.
+  * @cb:               Callback function. Will be called
+  *                    when new data is received.
+  * @client_data:      Clients private data. Will be sent back
+  *                    in the callback function.
+  * @virtbase_peer:    Virtual address for outgoing mailbox.
+  * @virtbase_local:   Virtual address for incoming mailbox.
+  * @buffer:           Then internal queue for outgoing messages.
+  * @name:             Name of this mailbox.
+  * @buffer_available: Completion variable to achieve "blocking send".
+  *                    This variable will be signaled when there is
+  *                    internal buffer space available.
+  * @client_blocked:   To keep track if any client is currently
+  *                    blocked.
+  * @lock:             Spinlock to protect this mailbox instance.
+  * @write_index:      Index in internal buffer to write to.
+  * @read_index:       Index in internal buffer to read from.
+  * @allocated:                Indicates whether this particular mailbox
+  *                    id has been allocated by someone.
+  */
+struct mbox {
+       struct list_head list;
+       struct platform_device *pdev;
+       mbox_recv_cb_t *cb;
+       void *client_data;
+       void __iomem *virtbase_peer;
+       void __iomem *virtbase_local;
+       u32 buffer[MBOX_BUF_SIZE];
+       char name[MBOX_NAME_SIZE];
+       struct completion buffer_available;
+       u8 client_blocked;
+       spinlock_t lock;
+       u8 write_index;
+       u8 read_index;
+       bool allocated;
+};
+
+/**
+  * mbox_setup - Set up a mailbox and return its instance.
+  * @mbox_id:  The ID number of the mailbox. 0 or 1 for modem CPU,
+  *            2 for modem DSP.
+  * @mbox_cb:  Pointer to the callback function to be called when a new message
+  *            is received.
+  * @priv:     Client user data which will be returned in the callback.
+  *
+  * Returns a mailbox instance to be specified in subsequent calls to mbox_send.
+  */
+struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv);
+
+/**
+  * mbox_send - Send a mailbox message.
+  * @mbox:     Mailbox instance (returned by mbox_setup)
+  * @mbox_msg: The mailbox message to send.
+  * @block:    Specifies whether this call will block until send is possible,
+  *            or return an error if the mailbox buffer is full.
+  *
+  * Returns 0 on success or a negative error code on error. -ENOMEM indicates
+  * that the internal buffer is full and you have to try again later (or
+  * specify "block" in order to block until send is possible).
+  */
+int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block);
+
+#endif /*INC_STE_MBOX_H*/
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-regs.h b/arch/arm/mach-ux500/include/mach/prcmu-regs.h
new file mode 100644 (file)
index 0000000..8885f39
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2009 ST-Ericsson SA
+ *
+ * This program is free software; you can 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_PRCMU_REGS_H
+#define __MACH_PRCMU_REGS_H
+
+#include <mach/hardware.h>
+
+#define _PRCMU_BASE            IO_ADDRESS(U8500_PRCMU_BASE)
+
+#define PRCM_ARM_PLLDIVPS      (_PRCMU_BASE + 0x118)
+#define PRCM_ARM_CHGCLKREQ     (_PRCMU_BASE + 0x114)
+#define PRCM_PLLARM_ENABLE     (_PRCMU_BASE + 0x98)
+#define PRCM_ARMCLKFIX_MGT     (_PRCMU_BASE + 0x0)
+#define PRCM_A9_RESETN_CLR     (_PRCMU_BASE + 0x1f4)
+#define PRCM_A9_RESETN_SET     (_PRCMU_BASE + 0x1f0)
+#define PRCM_ARM_LS_CLAMP      (_PRCMU_BASE + 0x30c)
+#define PRCM_SRAM_A9           (_PRCMU_BASE + 0x308)
+
+/* ARM WFI Standby signal register */
+#define PRCM_ARM_WFI_STANDBY    (_PRCMU_BASE + 0x130)
+#define PRCMU_IOCR              (_PRCMU_BASE + 0x310)
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL      (_PRCMU_BASE + 0x0fc)
+#define PRCM_MBOX_CPU_SET      (_PRCMU_BASE + 0x100)
+#define PRCM_MBOX_CPU_CLR      (_PRCMU_BASE + 0x104)
+
+/* Dual A9 core interrupt management unit registers */
+#define PRCM_A9_MASK_REQ       (_PRCMU_BASE + 0x328)
+#define PRCM_A9_MASK_ACK       (_PRCMU_BASE + 0x32c)
+#define PRCM_ARMITMSK31TO0     (_PRCMU_BASE + 0x11c)
+#define PRCM_ARMITMSK63TO32    (_PRCMU_BASE + 0x120)
+#define PRCM_ARMITMSK95TO64    (_PRCMU_BASE + 0x124)
+#define PRCM_ARMITMSK127TO96   (_PRCMU_BASE + 0x128)
+#define PRCM_POWER_STATE_VAL   (_PRCMU_BASE + 0x25C)
+#define PRCM_ARMITVAL31TO0     (_PRCMU_BASE + 0x260)
+#define PRCM_ARMITVAL63TO32    (_PRCMU_BASE + 0x264)
+#define PRCM_ARMITVAL95TO64    (_PRCMU_BASE + 0x268)
+#define PRCM_ARMITVAL127TO96   (_PRCMU_BASE + 0x26C)
+
+#define PRCM_HOSTACCESS_REQ    (_PRCMU_BASE + 0x334)
+#define ARM_WAKEUP_MODEM       0x1
+
+#define PRCM_ARM_IT1_CLEAR     (_PRCMU_BASE + 0x48C)
+#define PRCM_ARM_IT1_VAL       (_PRCMU_BASE + 0x494)
+#define PRCM_HOLD_EVT          (_PRCMU_BASE + 0x174)
+
+#define PRCM_ITSTATUS0         (_PRCMU_BASE + 0x148)
+#define PRCM_ITSTATUS1         (_PRCMU_BASE + 0x150)
+#define PRCM_ITSTATUS2         (_PRCMU_BASE + 0x158)
+#define PRCM_ITSTATUS3         (_PRCMU_BASE + 0x160)
+#define PRCM_ITSTATUS4         (_PRCMU_BASE + 0x168)
+#define PRCM_ITSTATUS5         (_PRCMU_BASE + 0x484)
+#define PRCM_ITCLEAR5          (_PRCMU_BASE + 0x488)
+#define PRCM_ARMIT_MASKXP70_IT (_PRCMU_BASE + 0x1018)
+
+/* System reset register */
+#define PRCM_APE_SOFTRST       (_PRCMU_BASE + 0x228)
+
+/* Level shifter and clamp control registers */
+#define PRCM_MMIP_LS_CLAMP_SET     (_PRCMU_BASE + 0x420)
+#define PRCM_MMIP_LS_CLAMP_CLR     (_PRCMU_BASE + 0x424)
+
+/* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLDSI_FREQ           (_PRCMU_BASE + 0x500)
+#define PRCM_PLLDSI_ENABLE         (_PRCMU_BASE + 0x504)
+#define PRCM_LCDCLK_MGT            (_PRCMU_BASE + 0x044)
+#define PRCM_MCDECLK_MGT           (_PRCMU_BASE + 0x064)
+#define PRCM_HDMICLK_MGT           (_PRCMU_BASE + 0x058)
+#define PRCM_TVCLK_MGT             (_PRCMU_BASE + 0x07c)
+#define PRCM_DSI_PLLOUT_SEL        (_PRCMU_BASE + 0x530)
+#define PRCM_DSITVCLK_DIV          (_PRCMU_BASE + 0x52C)
+#define PRCM_APE_RESETN_SET        (_PRCMU_BASE + 0x1E4)
+#define PRCM_APE_RESETN_CLR        (_PRCMU_BASE + 0x1E8)
+
+/* ePOD and memory power signal control registers */
+#define PRCM_EPOD_C_SET            (_PRCMU_BASE + 0x410)
+#define PRCM_SRAM_LS_SLEEP         (_PRCMU_BASE + 0x304)
+
+/* Debug power control unit registers */
+#define PRCM_POWER_STATE_SET       (_PRCMU_BASE + 0x254)
+
+/* Miscellaneous unit registers */
+#define PRCM_DSI_SW_RESET          (_PRCMU_BASE + 0x324)
+
+#endif /* __MACH_PRCMU__REGS_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h
new file mode 100644 (file)
index 0000000..549843f
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * PRCMU f/w APIs
+ */
+#ifndef __MACH_PRCMU_H
+#define __MACH_PRCMU_H
+
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
+
+#endif /* __MACH_PRCMU_H */
index e978dbd9e2109a042c5984ad3e64edc87ffd81a0..54bbe648bf583575d390866d6b405e58a899abec 100644 (file)
@@ -38,4 +38,11 @@ extern struct sys_timer ux500_timer;
        .type           = MT_DEVICE,            \
 }
 
+#define __MEM_DEV_DESC(x, sz)  {               \
+       .virtual        = IO_ADDRESS(x),        \
+       .pfn            = __phys_to_pfn(x),     \
+       .length         = sz,                   \
+       .type           = MT_MEMORY,            \
+}
+
 #endif /*  __ASM_ARCH_SETUP_H */
index b59f7bc9725d251812f102b0443f1f714270afe8..197e8417375e17f38942e443a963a686cb90905b 100644 (file)
 #define ASMARM_ARCH_SMP_H
 
 #include <asm/hardware/gic.h>
+#include <asm/smp_mpidr.h>
 
 /* This is required to wakeup the secondary core */
 extern void u8500_secondary_startup(void);
 
-#define hard_smp_processor_id()                                \
-       ({                                              \
-               unsigned int cpunum;                    \
-               __asm__("mrc p15, 0, %0, c0, c0, 5"     \
-                       : "=r" (cpunum));               \
-               cpunum &= 0x0F;                         \
-       })
-
 /*
  * We use IRQ1 as the IPI
  */
diff --git a/arch/arm/mach-ux500/mbox.c b/arch/arm/mach-ux500/mbox.c
new file mode 100644 (file)
index 0000000..6343538
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+/*
+ * Mailbox nomenclature:
+ *
+ *       APE           MODEM
+ *           mbox pairX
+ *   ..........................
+ *   .                       .
+ *   .           peer        .
+ *   .     send  ----        .
+ *   .      -->  |  |        .
+ *   .           |  |        .
+ *   .           ----        .
+ *   .                       .
+ *   .           local       .
+ *   .     rec   ----        .
+ *   .           |  | <--    .
+ *   .           |  |        .
+ *   .           ----        .
+ *   .........................
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/completion.h>
+#include <mach/mbox.h>
+
+#define MBOX_NAME "mbox"
+
+#define MBOX_FIFO_DATA        0x000
+#define MBOX_FIFO_ADD         0x004
+#define MBOX_FIFO_REMOVE      0x008
+#define MBOX_FIFO_THRES_FREE  0x00C
+#define MBOX_FIFO_THRES_OCCUP 0x010
+#define MBOX_FIFO_STATUS      0x014
+
+#define MBOX_DISABLE_IRQ 0x4
+#define MBOX_ENABLE_IRQ  0x0
+#define MBOX_LATCH 1
+
+/* Global list of all mailboxes */
+static struct list_head mboxs = LIST_HEAD_INIT(mboxs);
+
+static struct mbox *get_mbox_with_id(u8 id)
+{
+       u8 i;
+       struct list_head *pos = &mboxs;
+       for (i = 0; i <= id; i++)
+               pos = pos->next;
+
+       return (struct mbox *) list_entry(pos, struct mbox, list);
+}
+
+int mbox_send(struct mbox *mbox, u32 mbox_msg, bool block)
+{
+       int res = 0;
+
+       spin_lock(&mbox->lock);
+
+       dev_dbg(&(mbox->pdev->dev),
+               "About to buffer 0x%X to mailbox 0x%X."
+               " ri = %d, wi = %d\n",
+               mbox_msg, (u32)mbox, mbox->read_index,
+               mbox->write_index);
+
+       /* Check if write buffer is full */
+       while (((mbox->write_index + 1) % MBOX_BUF_SIZE) == mbox->read_index) {
+               if (!block) {
+                       dev_dbg(&(mbox->pdev->dev),
+                       "Buffer full in non-blocking call! "
+                       "Returning -ENOMEM!\n");
+                       res = -ENOMEM;
+                       goto exit;
+               }
+               spin_unlock(&mbox->lock);
+               dev_dbg(&(mbox->pdev->dev),
+                       "Buffer full in blocking call! Sleeping...\n");
+               mbox->client_blocked = 1;
+               wait_for_completion(&mbox->buffer_available);
+               dev_dbg(&(mbox->pdev->dev),
+                       "Blocking send was woken up! Trying again...\n");
+               spin_lock(&mbox->lock);
+       }
+
+       mbox->buffer[mbox->write_index] = mbox_msg;
+       mbox->write_index = (mbox->write_index + 1) % MBOX_BUF_SIZE;
+
+       /*
+        * Indicate that we want an IRQ as soon as there is a slot
+        * in the FIFO
+        */
+       writel(MBOX_ENABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+
+exit:
+       spin_unlock(&mbox->lock);
+       return res;
+}
+EXPORT_SYMBOL(mbox_send);
+
+#if defined(CONFIG_DEBUG_FS)
+/*
+ * Expected input: <value> <nbr sends>
+ * Example: "echo 0xdeadbeef 4 > mbox-node" sends 0xdeadbeef 4 times
+ */
+static ssize_t mbox_write_fifo(struct device *dev,
+                              struct device_attribute *attr,
+                              const char *buf,
+                              size_t count)
+{
+       unsigned long mbox_mess;
+       unsigned long nbr_sends;
+       unsigned long i;
+       char int_buf[16];
+       char *token;
+       char *val;
+
+       struct mbox *mbox = (struct mbox *) dev->platform_data;
+
+       strncpy((char *) &int_buf, buf, sizeof(int_buf));
+       token = (char *) &int_buf;
+
+       /* Parse message */
+       val = strsep(&token, " ");
+       if ((val == NULL) || (strict_strtoul(val, 16, &mbox_mess) != 0))
+               mbox_mess = 0xDEADBEEF;
+
+       val = strsep(&token, " ");
+       if ((val == NULL) || (strict_strtoul(val, 10, &nbr_sends) != 0))
+               nbr_sends = 1;
+
+       dev_dbg(dev, "Will write 0x%lX %ld times using data struct at 0x%X\n",
+               mbox_mess, nbr_sends, (u32) mbox);
+
+       for (i = 0; i < nbr_sends; i++)
+               mbox_send(mbox, mbox_mess, true);
+
+       return count;
+}
+
+static ssize_t mbox_read_fifo(struct device *dev,
+                             struct device_attribute *attr,
+                             char *buf)
+{
+       int mbox_value;
+       struct mbox *mbox = (struct mbox *) dev->platform_data;
+
+       if ((readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7) <= 0)
+               return sprintf(buf, "Mailbox is empty\n");
+
+       mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
+       writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
+
+       return sprintf(buf, "0x%X\n", mbox_value);
+}
+
+static DEVICE_ATTR(fifo, S_IWUGO | S_IRUGO, mbox_read_fifo, mbox_write_fifo);
+
+static int mbox_show(struct seq_file *s, void *data)
+{
+       struct list_head *pos;
+       u8 mbox_index = 0;
+
+       list_for_each(pos, &mboxs) {
+               struct mbox *m =
+                       (struct mbox *) list_entry(pos, struct mbox, list);
+               if (m == NULL) {
+                       seq_printf(s,
+                                  "Unable to retrieve mailbox %d\n",
+                                  mbox_index);
+                       continue;
+               }
+
+               spin_lock(&m->lock);
+               if ((m->virtbase_peer == NULL) || (m->virtbase_local == NULL)) {
+                       seq_printf(s, "MAILBOX %d not setup or corrupt\n",
+                                  mbox_index);
+                       spin_unlock(&m->lock);
+                       continue;
+               }
+
+               seq_printf(s,
+               "===========================\n"
+               " MAILBOX %d\n"
+               " PEER MAILBOX DUMP\n"
+               "---------------------------\n"
+               "FIFO:                 0x%X (%d)\n"
+               "Free     Threshold:   0x%.2X (%d)\n"
+               "Occupied Threshold:   0x%.2X (%d)\n"
+               "Status:               0x%.2X (%d)\n"
+               "   Free spaces  (ot):    %d (%d)\n"
+               "   Occup spaces (ot):    %d (%d)\n"
+               "===========================\n"
+               " LOCAL MAILBOX DUMP\n"
+               "---------------------------\n"
+               "FIFO:                 0x%.X (%d)\n"
+               "Free     Threshold:   0x%.2X (%d)\n"
+               "Occupied Threshold:   0x%.2X (%d)\n"
+               "Status:               0x%.2X (%d)\n"
+               "   Free spaces  (ot):    %d (%d)\n"
+               "   Occup spaces (ot):    %d (%d)\n"
+               "===========================\n"
+               "write_index: %d\n"
+               "read_index : %d\n"
+               "===========================\n"
+               "\n",
+               mbox_index,
+               readl(m->virtbase_peer + MBOX_FIFO_DATA),
+               readl(m->virtbase_peer + MBOX_FIFO_DATA),
+               readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
+               readl(m->virtbase_peer + MBOX_FIFO_THRES_FREE),
+               readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
+               readl(m->virtbase_peer + MBOX_FIFO_THRES_OCCUP),
+               readl(m->virtbase_peer + MBOX_FIFO_STATUS),
+               readl(m->virtbase_peer + MBOX_FIFO_STATUS),
+               (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 4) & 0x7,
+               (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 7) & 0x1,
+               (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 0) & 0x7,
+               (readl(m->virtbase_peer + MBOX_FIFO_STATUS) >> 3) & 0x1,
+               readl(m->virtbase_local + MBOX_FIFO_DATA),
+               readl(m->virtbase_local + MBOX_FIFO_DATA),
+               readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
+               readl(m->virtbase_local + MBOX_FIFO_THRES_FREE),
+               readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
+               readl(m->virtbase_local + MBOX_FIFO_THRES_OCCUP),
+               readl(m->virtbase_local + MBOX_FIFO_STATUS),
+               readl(m->virtbase_local + MBOX_FIFO_STATUS),
+               (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 4) & 0x7,
+               (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 7) & 0x1,
+               (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 0) & 0x7,
+               (readl(m->virtbase_local + MBOX_FIFO_STATUS) >> 3) & 0x1,
+               m->write_index, m->read_index);
+               mbox_index++;
+               spin_unlock(&m->lock);
+       }
+
+       return 0;
+}
+
+static int mbox_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, mbox_show, NULL);
+}
+
+static const struct file_operations mbox_operations = {
+       .owner = THIS_MODULE,
+       .open = mbox_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+#endif
+
+static irqreturn_t mbox_irq(int irq, void *arg)
+{
+       u32 mbox_value;
+       int nbr_occup;
+       int nbr_free;
+       struct mbox *mbox = (struct mbox *) arg;
+
+       spin_lock(&mbox->lock);
+
+       dev_dbg(&(mbox->pdev->dev),
+               "mbox IRQ [%d] received. ri = %d, wi = %d\n",
+               irq, mbox->read_index, mbox->write_index);
+
+       /*
+        * Check if we have any outgoing messages, and if there is space for
+        * them in the FIFO.
+        */
+       if (mbox->read_index != mbox->write_index) {
+               /*
+                * Check by reading FREE for LOCAL since that indicates
+                * OCCUP for PEER
+                */
+               nbr_free = (readl(mbox->virtbase_local + MBOX_FIFO_STATUS)
+                           >> 4) & 0x7;
+               dev_dbg(&(mbox->pdev->dev),
+                       "Status indicates %d empty spaces in the FIFO!\n",
+                       nbr_free);
+
+               while ((nbr_free > 0) &&
+                      (mbox->read_index != mbox->write_index)) {
+                       /* Write the message and latch it into the FIFO */
+                       writel(mbox->buffer[mbox->read_index],
+                              (mbox->virtbase_peer + MBOX_FIFO_DATA));
+                       writel(MBOX_LATCH,
+                              (mbox->virtbase_peer + MBOX_FIFO_ADD));
+                       dev_dbg(&(mbox->pdev->dev),
+                               "Wrote message 0x%X to addr 0x%X\n",
+                               mbox->buffer[mbox->read_index],
+                               (u32) (mbox->virtbase_peer + MBOX_FIFO_DATA));
+
+                       nbr_free--;
+                       mbox->read_index =
+                               (mbox->read_index + 1) % MBOX_BUF_SIZE;
+               }
+
+               /*
+                * Check if we still want IRQ:s when there is free
+                * space to send
+                */
+               if (mbox->read_index != mbox->write_index) {
+                       dev_dbg(&(mbox->pdev->dev),
+                               "Still have messages to send, but FIFO full. "
+                               "Request IRQ again!\n");
+                       writel(MBOX_ENABLE_IRQ,
+                              mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+               } else {
+                       dev_dbg(&(mbox->pdev->dev),
+                               "No more messages to send. "
+                               "Do not request IRQ again!\n");
+                       writel(MBOX_DISABLE_IRQ,
+                              mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+               }
+
+               /*
+                * Check if we can signal any blocked clients that it is OK to
+                * start buffering again
+                */
+               if (mbox->client_blocked &&
+                   (((mbox->write_index + 1) % MBOX_BUF_SIZE)
+                    != mbox->read_index)) {
+                       dev_dbg(&(mbox->pdev->dev),
+                               "Waking up blocked client\n");
+                       complete(&mbox->buffer_available);
+                       mbox->client_blocked = 0;
+               }
+       }
+
+       /* Check if we have any incoming messages */
+       nbr_occup = readl(mbox->virtbase_local + MBOX_FIFO_STATUS) & 0x7;
+       if (nbr_occup == 0)
+               goto exit;
+
+       if (mbox->cb == NULL) {
+               dev_dbg(&(mbox->pdev->dev), "No receive callback registered, "
+                       "leaving %d incoming messages in fifo!\n", nbr_occup);
+               goto exit;
+       }
+
+       /* Read and acknowledge the message */
+       mbox_value = readl(mbox->virtbase_local + MBOX_FIFO_DATA);
+       writel(MBOX_LATCH, (mbox->virtbase_local + MBOX_FIFO_REMOVE));
+
+       /* Notify consumer of new mailbox message */
+       dev_dbg(&(mbox->pdev->dev), "Calling callback for message 0x%X!\n",
+               mbox_value);
+       mbox->cb(mbox_value, mbox->client_data);
+
+exit:
+       dev_dbg(&(mbox->pdev->dev), "Exit mbox IRQ. ri = %d, wi = %d\n",
+               mbox->read_index, mbox->write_index);
+       spin_unlock(&mbox->lock);
+
+       return IRQ_HANDLED;
+}
+
+/* Setup is executed once for each mbox pair */
+struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv)
+{
+       struct resource *resource;
+       int irq;
+       int res;
+       struct mbox *mbox;
+
+       mbox = get_mbox_with_id(mbox_id);
+       if (mbox == NULL) {
+               dev_err(&(mbox->pdev->dev), "Incorrect mailbox id: %d!\n",
+                       mbox_id);
+               goto exit;
+       }
+
+       /*
+        * Check if mailbox has been allocated to someone else,
+        * otherwise allocate it
+        */
+       if (mbox->allocated) {
+               dev_err(&(mbox->pdev->dev), "Mailbox number %d is busy!\n",
+                       mbox_id);
+               mbox = NULL;
+               goto exit;
+       }
+       mbox->allocated = true;
+
+       dev_dbg(&(mbox->pdev->dev), "Initiating mailbox number %d: 0x%X...\n",
+               mbox_id, (u32)mbox);
+
+       mbox->client_data = priv;
+       mbox->cb = mbox_cb;
+
+       /* Get addr for peer mailbox and ioremap it */
+       resource = platform_get_resource_byname(mbox->pdev,
+                                               IORESOURCE_MEM,
+                                               "mbox_peer");
+       if (resource == NULL) {
+               dev_err(&(mbox->pdev->dev),
+                       "Unable to retrieve mbox peer resource\n");
+               mbox = NULL;
+               goto exit;
+       }
+       dev_dbg(&(mbox->pdev->dev),
+               "Resource name: %s start: 0x%X, end: 0x%X\n",
+               resource->name, resource->start, resource->end);
+       mbox->virtbase_peer =
+               ioremap(resource->start, resource->end - resource->start);
+       if (!mbox->virtbase_peer) {
+               dev_err(&(mbox->pdev->dev), "Unable to ioremap peer mbox\n");
+               mbox = NULL;
+               goto exit;
+       }
+       dev_dbg(&(mbox->pdev->dev),
+               "ioremapped peer physical: (0x%X-0x%X) to virtual: 0x%X\n",
+               resource->start, resource->end, (u32) mbox->virtbase_peer);
+
+       /* Get addr for local mailbox and ioremap it */
+       resource = platform_get_resource_byname(mbox->pdev,
+                                               IORESOURCE_MEM,
+                                               "mbox_local");
+       if (resource == NULL) {
+               dev_err(&(mbox->pdev->dev),
+                       "Unable to retrieve mbox local resource\n");
+               mbox = NULL;
+               goto exit;
+       }
+       dev_dbg(&(mbox->pdev->dev),
+               "Resource name: %s start: 0x%X, end: 0x%X\n",
+               resource->name, resource->start, resource->end);
+       mbox->virtbase_local =
+               ioremap(resource->start, resource->end - resource->start);
+       if (!mbox->virtbase_local) {
+               dev_err(&(mbox->pdev->dev), "Unable to ioremap local mbox\n");
+               mbox = NULL;
+               goto exit;
+       }
+       dev_dbg(&(mbox->pdev->dev),
+               "ioremapped local physical: (0x%X-0x%X) to virtual: 0x%X\n",
+               resource->start, resource->end, (u32) mbox->virtbase_peer);
+
+       init_completion(&mbox->buffer_available);
+       mbox->client_blocked = 0;
+
+       /* Get IRQ for mailbox and allocate it */
+       irq = platform_get_irq_byname(mbox->pdev, "mbox_irq");
+       if (irq < 0) {
+               dev_err(&(mbox->pdev->dev),
+                       "Unable to retrieve mbox irq resource\n");
+               mbox = NULL;
+               goto exit;
+       }
+
+       dev_dbg(&(mbox->pdev->dev), "Allocating irq %d...\n", irq);
+       res = request_irq(irq, mbox_irq, 0, mbox->name, (void *) mbox);
+       if (res < 0) {
+               dev_err(&(mbox->pdev->dev),
+                       "Unable to allocate mbox irq %d\n", irq);
+               mbox = NULL;
+               goto exit;
+       }
+
+       /* Set up mailbox to not launch IRQ on free space in mailbox */
+       writel(MBOX_DISABLE_IRQ, mbox->virtbase_peer + MBOX_FIFO_THRES_FREE);
+
+       /*
+        * Set up mailbox to launch IRQ on new message if we have
+        * a callback set. If not, do not raise IRQ, but keep message
+        * in FIFO for manual retrieval
+        */
+       if (mbox_cb != NULL)
+               writel(MBOX_ENABLE_IRQ,
+                      mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
+       else
+               writel(MBOX_DISABLE_IRQ,
+                      mbox->virtbase_local + MBOX_FIFO_THRES_OCCUP);
+
+#if defined(CONFIG_DEBUG_FS)
+       res = device_create_file(&(mbox->pdev->dev), &dev_attr_fifo);
+       if (res != 0)
+               dev_warn(&(mbox->pdev->dev),
+                        "Unable to create mbox sysfs entry");
+
+       (void) debugfs_create_file("mbox", S_IFREG | S_IRUGO, NULL,
+                                  NULL, &mbox_operations);
+#endif
+
+       dev_info(&(mbox->pdev->dev),
+                "Mailbox driver with index %d initated!\n", mbox_id);
+
+exit:
+       return mbox;
+}
+EXPORT_SYMBOL(mbox_setup);
+
+
+int __init mbox_probe(struct platform_device *pdev)
+{
+       struct mbox local_mbox;
+       struct mbox *mbox;
+       int res = 0;
+       dev_dbg(&(pdev->dev), "Probing mailbox (pdev = 0x%X)...\n", (u32) pdev);
+
+       memset(&local_mbox, 0x0, sizeof(struct mbox));
+
+       /* Associate our mbox data with the platform device */
+       res = platform_device_add_data(pdev,
+                                      (void *) &local_mbox,
+                                      sizeof(struct mbox));
+       if (res != 0) {
+               dev_err(&(pdev->dev),
+                       "Unable to allocate driver platform data!\n");
+               goto exit;
+       }
+
+       mbox = (struct mbox *) pdev->dev.platform_data;
+       mbox->pdev = pdev;
+       mbox->write_index = 0;
+       mbox->read_index = 0;
+
+       INIT_LIST_HEAD(&(mbox->list));
+       list_add_tail(&(mbox->list), &mboxs);
+
+       sprintf(mbox->name, "%s", MBOX_NAME);
+       spin_lock_init(&mbox->lock);
+
+       dev_info(&(pdev->dev), "Mailbox driver loaded\n");
+
+exit:
+       return res;
+}
+
+static struct platform_driver mbox_driver = {
+       .driver = {
+               .name = MBOX_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+static int __init mbox_init(void)
+{
+       return platform_driver_probe(&mbox_driver, mbox_probe);
+}
+
+module_init(mbox_init);
+
+void __exit mbox_exit(void)
+{
+       platform_driver_unregister(&mbox_driver);
+}
+
+module_exit(mbox_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MBOX driver");
diff --git a/arch/arm/mach-ux500/modem_irq.c b/arch/arm/mach-ux500/modem_irq.c
new file mode 100644 (file)
index 0000000..3187f88
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Stefan Nilsson <stefan.xk.nilsson@stericsson.com> for ST-Ericsson.
+ * Author: Martin Persson <martin.persson@stericsson.com> for ST-Ericsson.
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#define MODEM_INTCON_BASE_ADDR 0xBFFD3000
+#define MODEM_INTCON_SIZE 0xFFF
+
+#define DEST_IRQ41_OFFSET 0x2A4
+#define DEST_IRQ43_OFFSET 0x2AC
+#define DEST_IRQ45_OFFSET 0x2B4
+
+#define PRIO_IRQ41_OFFSET 0x6A4
+#define PRIO_IRQ43_OFFSET 0x6AC
+#define PRIO_IRQ45_OFFSET 0x6B4
+
+#define ALLOW_IRQ_OFFSET 0x104
+
+#define MODEM_INTCON_CPU_NBR 0x1
+#define MODEM_INTCON_PRIO_HIGH 0x0
+
+#define MODEM_INTCON_ALLOW_IRQ41 0x0200
+#define MODEM_INTCON_ALLOW_IRQ43 0x0800
+#define MODEM_INTCON_ALLOW_IRQ45 0x2000
+
+#define MODEM_IRQ_REG_OFFSET 0x4
+
+struct modem_irq {
+       void __iomem *modem_intcon_base;
+};
+
+
+static void setup_modem_intcon(void __iomem *modem_intcon_base)
+{
+       /* IC_DESTINATION_BASE_ARRAY - Which CPU to receive the IRQ */
+       writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ41_OFFSET);
+       writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ43_OFFSET);
+       writel(MODEM_INTCON_CPU_NBR, modem_intcon_base + DEST_IRQ45_OFFSET);
+
+       /* IC_PRIORITY_BASE_ARRAY - IRQ priority in modem IRQ controller */
+       writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ41_OFFSET);
+       writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ43_OFFSET);
+       writel(MODEM_INTCON_PRIO_HIGH, modem_intcon_base + PRIO_IRQ45_OFFSET);
+
+       /* IC_ALLOW_ARRAY - IRQ enable */
+       writel(MODEM_INTCON_ALLOW_IRQ41 |
+                  MODEM_INTCON_ALLOW_IRQ43 |
+                  MODEM_INTCON_ALLOW_IRQ45,
+                  modem_intcon_base + ALLOW_IRQ_OFFSET);
+}
+
+static irqreturn_t modem_cpu_irq_handler(int irq, void *data)
+{
+       int real_irq;
+       int virt_irq;
+       struct modem_irq *mi = (struct modem_irq *)data;
+
+       /* Read modem side IRQ number from modem IRQ controller */
+       real_irq = readl(mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET) & 0xFF;
+       virt_irq = IRQ_MODEM_EVENTS_BASE + real_irq;
+
+       pr_debug("modem_irq: Worker read addr 0x%X and got value 0x%X "
+                "which will be 0x%X (%d) which translates to "
+                "virtual IRQ 0x%X (%d)!\n",
+                  (u32)mi->modem_intcon_base + MODEM_IRQ_REG_OFFSET,
+                  real_irq,
+                  real_irq & 0xFF,
+                  real_irq & 0xFF,
+                  virt_irq,
+                  virt_irq);
+
+       if (virt_irq != 0)
+               generic_handle_irq(virt_irq);
+
+       pr_debug("modem_irq: Done handling virtual IRQ %d!\n", virt_irq);
+
+       return IRQ_HANDLED;
+}
+
+static void create_virtual_irq(int irq, struct irq_chip *modem_irq_chip)
+{
+       set_irq_chip(irq, modem_irq_chip);
+       set_irq_handler(irq, handle_simple_irq);
+       set_irq_flags(irq, IRQF_VALID);
+
+       pr_debug("modem_irq: Created virtual IRQ %d\n", irq);
+}
+
+static int modem_irq_init(void)
+{
+       int err;
+       static struct irq_chip  modem_irq_chip;
+       struct modem_irq *mi;
+
+       pr_info("modem_irq: Set up IRQ handler for incoming modem IRQ %d\n",
+                  IRQ_DB5500_MODEM);
+
+       mi = kmalloc(sizeof(struct modem_irq), GFP_KERNEL);
+       if (!mi) {
+               pr_err("modem_irq: Could not allocate device\n");
+               return -ENOMEM;
+       }
+
+       mi->modem_intcon_base =
+               ioremap(MODEM_INTCON_BASE_ADDR, MODEM_INTCON_SIZE);
+       pr_debug("modem_irq: ioremapped modem_intcon_base from "
+                "phy 0x%x to virt 0x%x\n", MODEM_INTCON_BASE_ADDR,
+                (u32)mi->modem_intcon_base);
+
+       setup_modem_intcon(mi->modem_intcon_base);
+
+       modem_irq_chip = dummy_irq_chip;
+       modem_irq_chip.name = "modem_irq";
+
+       /* Create the virtual IRQ:s needed */
+       create_virtual_irq(MBOX_PAIR0_VIRT_IRQ, &modem_irq_chip);
+       create_virtual_irq(MBOX_PAIR1_VIRT_IRQ, &modem_irq_chip);
+       create_virtual_irq(MBOX_PAIR2_VIRT_IRQ, &modem_irq_chip);
+
+       err = request_threaded_irq(IRQ_DB5500_MODEM, NULL,
+                                  modem_cpu_irq_handler, IRQF_ONESHOT,
+                                  "modem_irq", mi);
+       if (err)
+               pr_err("modem_irq: Could not register IRQ %d\n",
+                      IRQ_DB5500_MODEM);
+
+       return 0;
+}
+
+arch_initcall(modem_irq_init);
diff --git a/arch/arm/mach-ux500/pins-db5500.h b/arch/arm/mach-ux500/pins-db5500.h
new file mode 100644 (file)
index 0000000..bf50c21
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com>
+ */
+
+#ifndef __MACH_DB5500_PINS_H
+#define __MACH_DB5500_PINS_H
+
+#define GPIO0_GPIO             PIN_CFG(0, GPIO)
+#define GPIO0_SM_CS3n          PIN_CFG(0, ALT_A)
+
+#define GPIO1_GPIO             PIN_CFG(1, GPIO)
+#define GPIO1_SM_A3            PIN_CFG(1, ALT_A)
+
+#define GPIO2_GPIO             PIN_CFG(2, GPIO)
+#define GPIO2_SM_A4            PIN_CFG(2, ALT_A)
+#define GPIO2_SM_AVD           PIN_CFG(2, ALT_B)
+
+#define GPIO3_GPIO             PIN_CFG(3, GPIO)
+#define GPIO3_I2C1_SCL         PIN_CFG(3, ALT_A)
+
+#define GPIO4_GPIO             PIN_CFG(4, GPIO)
+#define GPIO4_I2C1_SDA         PIN_CFG(4, ALT_A)
+
+#define GPIO5_GPIO             PIN_CFG(5, GPIO)
+#define GPIO5_MC0_DAT0         PIN_CFG(5, ALT_A)
+#define GPIO5_SM_ADQ8          PIN_CFG(5, ALT_B)
+
+#define GPIO6_GPIO             PIN_CFG(6, GPIO)
+#define GPIO6_MC0_DAT1         PIN_CFG(6, ALT_A)
+#define GPIO6_SM_ADQ0          PIN_CFG(6, ALT_B)
+
+#define GPIO7_GPIO             PIN_CFG(7, GPIO)
+#define GPIO7_MC0_DAT2         PIN_CFG(7, ALT_A)
+#define GPIO7_SM_ADQ9          PIN_CFG(7, ALT_B)
+
+#define GPIO8_GPIO             PIN_CFG(8, GPIO)
+#define GPIO8_MC0_DAT3         PIN_CFG(8, ALT_A)
+#define GPIO8_SM_ADQ1          PIN_CFG(8, ALT_B)
+
+#define GPIO9_GPIO             PIN_CFG(9, GPIO)
+#define GPIO9_MC0_DAT4         PIN_CFG(9, ALT_A)
+#define GPIO9_SM_ADQ10         PIN_CFG(9, ALT_B)
+
+#define GPIO10_GPIO            PIN_CFG(10, GPIO)
+#define GPIO10_MC0_DAT5                PIN_CFG(10, ALT_A)
+#define GPIO10_SM_ADQ2         PIN_CFG(10, ALT_B)
+
+#define GPIO11_GPIO            PIN_CFG(11, GPIO)
+#define GPIO11_MC0_DAT6                PIN_CFG(11, ALT_A)
+#define GPIO11_SM_ADQ11                PIN_CFG(11, ALT_B)
+
+#define GPIO12_GPIO            PIN_CFG(12, GPIO)
+#define GPIO12_MC0_DAT7                PIN_CFG(12, ALT_A)
+#define GPIO12_SM_ADQ3         PIN_CFG(12, ALT_B)
+
+#define GPIO13_GPIO            PIN_CFG(13, GPIO)
+#define GPIO13_MC0_CMD         PIN_CFG(13, ALT_A)
+#define GPIO13_SM_BUSY0n       PIN_CFG(13, ALT_B)
+#define GPIO13_SM_WAIT0n       PIN_CFG(13, ALT_C)
+
+#define GPIO14_GPIO            PIN_CFG(14, GPIO)
+#define GPIO14_MC0_CLK         PIN_CFG(14, ALT_A)
+#define GPIO14_SM_CS1n         PIN_CFG(14, ALT_B)
+#define GPIO14_SM_CKO          PIN_CFG(14, ALT_C)
+
+#define GPIO15_GPIO            PIN_CFG(15, GPIO)
+#define GPIO15_SM_A5           PIN_CFG(15, ALT_A)
+#define GPIO15_SM_CLE          PIN_CFG(15, ALT_B)
+
+#define GPIO16_GPIO            PIN_CFG(16, GPIO)
+#define GPIO16_MC2_CMD         PIN_CFG(16, ALT_A)
+#define GPIO16_SM_OEn          PIN_CFG(16, ALT_B)
+
+#define GPIO17_GPIO            PIN_CFG(17, GPIO)
+#define GPIO17_MC2_CLK         PIN_CFG(17, ALT_A)
+#define GPIO17_SM_WEn          PIN_CFG(17, ALT_B)
+
+#define GPIO18_GPIO            PIN_CFG(18, GPIO)
+#define GPIO18_SM_A6           PIN_CFG(18, ALT_A)
+#define GPIO18_SM_ALE          PIN_CFG(18, ALT_B)
+#define GPIO18_SM_AVDn         PIN_CFG(18, ALT_C)
+
+#define GPIO19_GPIO            PIN_CFG(19, GPIO)
+#define GPIO19_MC2_DAT1                PIN_CFG(19, ALT_A)
+#define GPIO19_SM_ADQ4         PIN_CFG(19, ALT_B)
+
+#define GPIO20_GPIO            PIN_CFG(20, GPIO)
+#define GPIO20_MC2_DAT3                PIN_CFG(20, ALT_A)
+#define GPIO20_SM_ADQ5         PIN_CFG(20, ALT_B)
+
+#define GPIO21_GPIO            PIN_CFG(21, GPIO)
+#define GPIO21_MC2_DAT5                PIN_CFG(21, ALT_A)
+#define GPIO21_SM_ADQ6         PIN_CFG(21, ALT_B)
+
+#define GPIO22_GPIO            PIN_CFG(22, GPIO)
+#define GPIO22_MC2_DAT7                PIN_CFG(22, ALT_A)
+#define GPIO22_SM_ADQ7         PIN_CFG(22, ALT_B)
+
+#define GPIO23_GPIO            PIN_CFG(23, GPIO)
+#define GPIO23_MC2_DAT0                PIN_CFG(23, ALT_A)
+#define GPIO23_SM_ADQ12                PIN_CFG(23, ALT_B)
+#define GPIO23_MC0_DAT1                PIN_CFG(23, ALT_C)
+
+#define GPIO24_GPIO            PIN_CFG(24, GPIO)
+#define GPIO24_MC2_DAT2                PIN_CFG(24, ALT_A)
+#define GPIO24_SM_ADQ13                PIN_CFG(24, ALT_B)
+#define GPIO24_MC0_DAT3                PIN_CFG(24, ALT_C)
+
+#define GPIO25_GPIO            PIN_CFG(25, GPIO)
+#define GPIO25_MC2_DAT4                PIN_CFG(25, ALT_A)
+#define GPIO25_SM_ADQ14                PIN_CFG(25, ALT_B)
+#define GPIO25_MC0_CMD         PIN_CFG(25, ALT_C)
+
+#define GPIO26_GPIO            PIN_CFG(26, GPIO)
+#define GPIO26_MC2_DAT6                PIN_CFG(26, ALT_A)
+#define GPIO26_SM_ADQ15                PIN_CFG(26, ALT_B)
+
+#define GPIO27_GPIO            PIN_CFG(27, GPIO)
+#define GPIO27_SM_CS0n         PIN_CFG(27, ALT_A)
+#define GPIO27_SM_PS0n         PIN_CFG(27, ALT_B)
+
+#define GPIO28_GPIO            PIN_CFG(28, GPIO)
+#define GPIO28_U0_TXD          PIN_CFG(28, ALT_A)
+#define GPIO28_SM_A0           PIN_CFG(28, ALT_B)
+
+#define GPIO29_GPIO            PIN_CFG(29, GPIO)
+#define GPIO29_U0_RXD          PIN_CFG(29, ALT_A)
+#define GPIO29_SM_A1           PIN_CFG(29, ALT_B)
+#define GPIO29_PWM_0           PIN_CFG(29, ALT_C)
+
+#define GPIO30_GPIO            PIN_CFG(30, GPIO)
+#define GPIO30_MC0_DAT5                PIN_CFG(30, ALT_A)
+#define GPIO30_SM_A2           PIN_CFG(30, ALT_B)
+#define GPIO30_PWM_1           PIN_CFG(30, ALT_C)
+
+#define GPIO31_GPIO            PIN_CFG(31, GPIO)
+#define GPIO31_MC0_DAT7                PIN_CFG(31, ALT_A)
+#define GPIO31_SM_CS2n         PIN_CFG(31, ALT_B)
+#define GPIO31_PWM_2           PIN_CFG(31, ALT_C)
+
+#define GPIO32_GPIO            PIN_CFG(32, GPIO)
+#define GPIO32_MSP0_TCK                PIN_CFG(32, ALT_A)
+#define GPIO32_ACCI2S0_SCK     PIN_CFG(32, ALT_B)
+
+#define GPIO33_GPIO            PIN_CFG(33, GPIO)
+#define GPIO33_MSP0_TFS                PIN_CFG(33, ALT_A)
+#define GPIO33_ACCI2S0_WS      PIN_CFG(33, ALT_B)
+
+#define GPIO34_GPIO            PIN_CFG(34, GPIO)
+#define GPIO34_MSP0_TXD                PIN_CFG(34, ALT_A)
+#define GPIO34_ACCI2S0_DLD     PIN_CFG(34, ALT_B)
+
+#define GPIO35_GPIO            PIN_CFG(35, GPIO)
+#define GPIO35_MSP0_RXD                PIN_CFG(35, ALT_A)
+#define GPIO35_ACCI2S0_ULD     PIN_CFG(35, ALT_B)
+
+#define GPIO64_GPIO            PIN_CFG(64, GPIO)
+#define GPIO64_USB_DAT0                PIN_CFG(64, ALT_A)
+#define GPIO64_U0_TXD          PIN_CFG(64, ALT_B)
+
+#define GPIO65_GPIO            PIN_CFG(65, GPIO)
+#define GPIO65_USB_DAT1                PIN_CFG(65, ALT_A)
+#define GPIO65_U0_RXD          PIN_CFG(65, ALT_B)
+
+#define GPIO66_GPIO            PIN_CFG(66, GPIO)
+#define GPIO66_USB_DAT2                PIN_CFG(66, ALT_A)
+
+#define GPIO67_GPIO            PIN_CFG(67, GPIO)
+#define GPIO67_USB_DAT3                PIN_CFG(67, ALT_A)
+
+#define GPIO68_GPIO            PIN_CFG(68, GPIO)
+#define GPIO68_USB_DAT4                PIN_CFG(68, ALT_A)
+
+#define GPIO69_GPIO            PIN_CFG(69, GPIO)
+#define GPIO69_USB_DAT5                PIN_CFG(69, ALT_A)
+
+#define GPIO70_GPIO            PIN_CFG(70, GPIO)
+#define GPIO70_USB_DAT6                PIN_CFG(70, ALT_A)
+
+#define GPIO71_GPIO            PIN_CFG(71, GPIO)
+#define GPIO71_USB_DAT7                PIN_CFG(71, ALT_A)
+
+#define GPIO72_GPIO            PIN_CFG(72, GPIO)
+#define GPIO72_USB_STP         PIN_CFG(72, ALT_A)
+
+#define GPIO73_GPIO            PIN_CFG(73, GPIO)
+#define GPIO73_USB_DIR         PIN_CFG(73, ALT_A)
+
+#define GPIO74_GPIO            PIN_CFG(74, GPIO)
+#define GPIO74_USB_NXT         PIN_CFG(74, ALT_A)
+
+#define GPIO75_GPIO            PIN_CFG(75, GPIO)
+#define GPIO75_USB_XCLK                PIN_CFG(75, ALT_A)
+
+#define GPIO76_GPIO            PIN_CFG(76, GPIO)
+
+#define GPIO77_GPIO            PIN_CFG(77, GPIO)
+#define GPIO77_ACCTX_ON                PIN_CFG(77, ALT_A)
+
+#define GPIO78_GPIO            PIN_CFG(78, GPIO)
+#define GPIO78_IRQn            PIN_CFG(78, ALT_A)
+
+#define GPIO79_GPIO            PIN_CFG(79, GPIO)
+#define GPIO79_ACCSIM_Clk      PIN_CFG(79, ALT_A)
+
+#define GPIO80_GPIO            PIN_CFG(80, GPIO)
+#define GPIO80_ACCSIM_Da       PIN_CFG(80, ALT_A)
+
+#define GPIO81_GPIO            PIN_CFG(81, GPIO)
+#define GPIO81_ACCSIM_Reset    PIN_CFG(81, ALT_A)
+
+#define GPIO82_GPIO            PIN_CFG(82, GPIO)
+#define GPIO82_ACCSIM_DDir     PIN_CFG(82, ALT_A)
+
+#define GPIO96_GPIO            PIN_CFG(96, GPIO)
+#define GPIO96_MSP1_TCK                PIN_CFG(96, ALT_A)
+#define GPIO96_PRCMU_DEBUG3    PIN_CFG(96, ALT_B)
+#define GPIO96_PRCMU_DEBUG7    PIN_CFG(96, ALT_C)
+
+#define GPIO97_GPIO            PIN_CFG(97, GPIO)
+#define GPIO97_MSP1_TFS                PIN_CFG(97, ALT_A)
+#define GPIO97_PRCMU_DEBUG2    PIN_CFG(97, ALT_B)
+#define GPIO97_PRCMU_DEBUG6    PIN_CFG(97, ALT_C)
+
+#define GPIO98_GPIO            PIN_CFG(98, GPIO)
+#define GPIO98_MSP1_TXD                PIN_CFG(98, ALT_A)
+#define GPIO98_PRCMU_DEBUG1    PIN_CFG(98, ALT_B)
+#define GPIO98_PRCMU_DEBUG5    PIN_CFG(98, ALT_C)
+
+#define GPIO99_GPIO            PIN_CFG(99, GPIO)
+#define GPIO99_MSP1_RXD                PIN_CFG(99, ALT_A)
+#define GPIO99_PRCMU_DEBUG0    PIN_CFG(99, ALT_B)
+#define GPIO99_PRCMU_DEBUG4    PIN_CFG(99, ALT_C)
+
+#define GPIO100_GPIO           PIN_CFG(100, GPIO)
+#define GPIO100_I2C0_SCL       PIN_CFG(100, ALT_A)
+
+#define GPIO101_GPIO           PIN_CFG(101, GPIO)
+#define GPIO101_I2C0_SDA       PIN_CFG(101, ALT_A)
+
+#define GPIO128_GPIO           PIN_CFG(128, GPIO)
+#define GPIO128_KP_I0          PIN_CFG(128, ALT_A)
+#define GPIO128_BUSMON_D0      PIN_CFG(128, ALT_B)
+
+#define GPIO129_GPIO           PIN_CFG(129, GPIO)
+#define GPIO129_KP_O0          PIN_CFG(129, ALT_A)
+#define GPIO129_BUSMON_D1      PIN_CFG(129, ALT_B)
+
+#define GPIO130_GPIO           PIN_CFG(130, GPIO)
+#define GPIO130_KP_I1          PIN_CFG(130, ALT_A)
+#define GPIO130_BUSMON_D2      PIN_CFG(130, ALT_B)
+
+#define GPIO131_GPIO           PIN_CFG(131, GPIO)
+#define GPIO131_KP_O1          PIN_CFG(131, ALT_A)
+#define GPIO131_BUSMON_D3      PIN_CFG(131, ALT_B)
+
+#define GPIO132_GPIO           PIN_CFG(132, GPIO)
+#define GPIO132_KP_I2          PIN_CFG(132, ALT_A)
+#define GPIO132_ETM_D15                PIN_CFG(132, ALT_B)
+#define GPIO132_STMAPE_CLK     PIN_CFG(132, ALT_C)
+
+#define GPIO133_GPIO           PIN_CFG(133, GPIO)
+#define GPIO133_KP_O2          PIN_CFG(133, ALT_A)
+#define GPIO133_ETM_D14                PIN_CFG(133, ALT_B)
+#define GPIO133_U0_RXD         PIN_CFG(133, ALT_C)
+
+#define GPIO134_GPIO           PIN_CFG(134, GPIO)
+#define GPIO134_KP_I3          PIN_CFG(134, ALT_A)
+#define GPIO134_ETM_D13                PIN_CFG(134, ALT_B)
+#define GPIO134_STMAPE_DAT0    PIN_CFG(134, ALT_C)
+
+#define GPIO135_GPIO           PIN_CFG(135, GPIO)
+#define GPIO135_KP_O3          PIN_CFG(135, ALT_A)
+#define GPIO135_ETM_D12                PIN_CFG(135, ALT_B)
+#define GPIO135_STMAPE_DAT1    PIN_CFG(135, ALT_C)
+
+#define GPIO136_GPIO           PIN_CFG(136, GPIO)
+#define GPIO136_KP_I4          PIN_CFG(136, ALT_A)
+#define GPIO136_ETM_D11                PIN_CFG(136, ALT_B)
+#define GPIO136_STMAPE_DAT2    PIN_CFG(136, ALT_C)
+
+#define GPIO137_GPIO           PIN_CFG(137, GPIO)
+#define GPIO137_KP_O4          PIN_CFG(137, ALT_A)
+#define GPIO137_ETM_D10                PIN_CFG(137, ALT_B)
+#define GPIO137_STMAPE_DAT3    PIN_CFG(137, ALT_C)
+
+#define GPIO138_GPIO           PIN_CFG(138, GPIO)
+#define GPIO138_KP_I5          PIN_CFG(138, ALT_A)
+#define GPIO138_ETM_D9         PIN_CFG(138, ALT_B)
+#define GPIO138_U0_TXD         PIN_CFG(138, ALT_C)
+
+#define GPIO139_GPIO           PIN_CFG(139, GPIO)
+#define GPIO139_KP_O5          PIN_CFG(139, ALT_A)
+#define GPIO139_ETM_D8         PIN_CFG(139, ALT_B)
+#define GPIO139_BUSMON_D11     PIN_CFG(139, ALT_C)
+
+#define GPIO140_GPIO           PIN_CFG(140, GPIO)
+#define GPIO140_KP_I6          PIN_CFG(140, ALT_A)
+#define GPIO140_ETM_D7         PIN_CFG(140, ALT_B)
+#define GPIO140_STMAPE_CLK     PIN_CFG(140, ALT_C)
+
+#define GPIO141_GPIO           PIN_CFG(141, GPIO)
+#define GPIO141_KP_O6          PIN_CFG(141, ALT_A)
+#define GPIO141_ETM_D6         PIN_CFG(141, ALT_B)
+#define GPIO141_U0_RXD         PIN_CFG(141, ALT_C)
+
+#define GPIO142_GPIO           PIN_CFG(142, GPIO)
+#define GPIO142_KP_I7          PIN_CFG(142, ALT_A)
+#define GPIO142_ETM_D5         PIN_CFG(142, ALT_B)
+#define GPIO142_STMAPE_DAT0    PIN_CFG(142, ALT_C)
+
+#define GPIO143_GPIO           PIN_CFG(143, GPIO)
+#define GPIO143_KP_O7          PIN_CFG(143, ALT_A)
+#define GPIO143_ETM_D4         PIN_CFG(143, ALT_B)
+#define GPIO143_STMAPE_DAT1    PIN_CFG(143, ALT_C)
+
+#define GPIO144_GPIO           PIN_CFG(144, GPIO)
+#define GPIO144_I2C3_SCL       PIN_CFG(144, ALT_A)
+#define GPIO144_ETM_D3         PIN_CFG(144, ALT_B)
+#define GPIO144_STMAPE_DAT2    PIN_CFG(144, ALT_C)
+
+#define GPIO145_GPIO           PIN_CFG(145, GPIO)
+#define GPIO145_I2C3_SDA       PIN_CFG(145, ALT_A)
+#define GPIO145_ETM_D2         PIN_CFG(145, ALT_B)
+#define GPIO145_STMAPE_DAT3    PIN_CFG(145, ALT_C)
+
+#define GPIO146_GPIO           PIN_CFG(146, GPIO)
+#define GPIO146_PWM_0          PIN_CFG(146, ALT_A)
+#define GPIO146_ETM_D1         PIN_CFG(146, ALT_B)
+
+#define GPIO147_GPIO           PIN_CFG(147, GPIO)
+#define GPIO147_PWM_1          PIN_CFG(147, ALT_A)
+#define GPIO147_ETM_D0         PIN_CFG(147, ALT_B)
+
+#define GPIO148_GPIO           PIN_CFG(148, GPIO)
+#define GPIO148_PWM_2          PIN_CFG(148, ALT_A)
+#define GPIO148_ETM_CLK                PIN_CFG(148, ALT_B)
+
+#define GPIO160_GPIO           PIN_CFG(160, GPIO)
+#define GPIO160_CLKOUT_REQn    PIN_CFG(160, ALT_A)
+
+#define GPIO161_GPIO           PIN_CFG(161, GPIO)
+#define GPIO161_CLKOUT_0       PIN_CFG(161, ALT_A)
+
+#define GPIO162_GPIO           PIN_CFG(162, GPIO)
+#define GPIO162_CLKOUT_1       PIN_CFG(162, ALT_A)
+
+#define GPIO163_GPIO           PIN_CFG(163, GPIO)
+
+#define GPIO164_GPIO           PIN_CFG(164, GPIO)
+#define GPIO164_GPS_START      PIN_CFG(164, ALT_A)
+
+#define GPIO165_GPIO           PIN_CFG(165, GPIO)
+#define GPIO165_SPI1_CS2n      PIN_CFG(165, ALT_A)
+#define GPIO165_U3_RXD         PIN_CFG(165, ALT_B)
+#define GPIO165_BUSMON_D20     PIN_CFG(165, ALT_C)
+
+#define GPIO166_GPIO           PIN_CFG(166, GPIO)
+#define GPIO166_SPI1_CS1n      PIN_CFG(166, ALT_A)
+#define GPIO166_U3_TXD         PIN_CFG(166, ALT_B)
+#define GPIO166_BUSMON_D21     PIN_CFG(166, ALT_C)
+
+#define GPIO167_GPIO           PIN_CFG(167, GPIO)
+#define GPIO167_SPI1_CS0n      PIN_CFG(167, ALT_A)
+#define GPIO167_U3_RTSn                PIN_CFG(167, ALT_B)
+#define GPIO167_BUSMON_D22     PIN_CFG(167, ALT_C)
+
+#define GPIO168_GPIO           PIN_CFG(168, GPIO)
+#define GPIO168_SPI1_RXD       PIN_CFG(168, ALT_A)
+#define GPIO168_U3_CTSn                PIN_CFG(168, ALT_B)
+#define GPIO168_BUSMON_D23     PIN_CFG(168, ALT_C)
+
+#define GPIO169_GPIO           PIN_CFG(169, GPIO)
+#define GPIO169_SPI1_TXD       PIN_CFG(169, ALT_A)
+#define GPIO169_DDR_RC         PIN_CFG(169, ALT_B)
+#define GPIO169_BUSMON_D24     PIN_CFG(169, ALT_C)
+
+#define GPIO170_GPIO           PIN_CFG(170, GPIO)
+#define GPIO170_SPI1_CLK       PIN_CFG(170, ALT_A)
+
+#define GPIO171_GPIO           PIN_CFG(171, GPIO)
+#define GPIO171_MC3_DAT0       PIN_CFG(171, ALT_A)
+#define GPIO171_SPI3_RXD       PIN_CFG(171, ALT_B)
+#define GPIO171_BUSMON_D25     PIN_CFG(171, ALT_C)
+
+#define GPIO172_GPIO           PIN_CFG(172, GPIO)
+#define GPIO172_MC3_DAT1       PIN_CFG(172, ALT_A)
+#define GPIO172_SPI3_CS1n      PIN_CFG(172, ALT_B)
+#define GPIO172_BUSMON_D26     PIN_CFG(172, ALT_C)
+
+#define GPIO173_GPIO           PIN_CFG(173, GPIO)
+#define GPIO173_MC3_DAT2       PIN_CFG(173, ALT_A)
+#define GPIO173_SPI3_CS2n      PIN_CFG(173, ALT_B)
+#define GPIO173_BUSMON_D27     PIN_CFG(173, ALT_C)
+
+#define GPIO174_GPIO           PIN_CFG(174, GPIO)
+#define GPIO174_MC3_DAT3       PIN_CFG(174, ALT_A)
+#define GPIO174_SPI3_CS0n      PIN_CFG(174, ALT_B)
+#define GPIO174_BUSMON_D28     PIN_CFG(174, ALT_C)
+
+#define GPIO175_GPIO           PIN_CFG(175, GPIO)
+#define GPIO175_MC3_CMD                PIN_CFG(175, ALT_A)
+#define GPIO175_SPI3_TXD       PIN_CFG(175, ALT_B)
+#define GPIO175_BUSMON_D29     PIN_CFG(175, ALT_C)
+
+#define GPIO176_GPIO           PIN_CFG(176, GPIO)
+#define GPIO176_MC3_CLK                PIN_CFG(176, ALT_A)
+#define GPIO176_SPI3_CLK       PIN_CFG(176, ALT_B)
+
+#define GPIO177_GPIO           PIN_CFG(177, GPIO)
+#define GPIO177_U2_RXD         PIN_CFG(177, ALT_A)
+#define GPIO177_I2C3_SCL       PIN_CFG(177, ALT_B)
+#define GPIO177_BUSMON_D30     PIN_CFG(177, ALT_C)
+
+#define GPIO178_GPIO           PIN_CFG(178, GPIO)
+#define GPIO178_U2_TXD         PIN_CFG(178, ALT_A)
+#define GPIO178_I2C3_SDA       PIN_CFG(178, ALT_B)
+#define GPIO178_BUSMON_D31     PIN_CFG(178, ALT_C)
+
+#define GPIO179_GPIO           PIN_CFG(179, GPIO)
+#define GPIO179_U2_CTSn                PIN_CFG(179, ALT_A)
+#define GPIO179_U3_RXD         PIN_CFG(179, ALT_B)
+#define GPIO179_BUSMON_D32     PIN_CFG(179, ALT_C)
+
+#define GPIO180_GPIO           PIN_CFG(180, GPIO)
+#define GPIO180_U2_RTSn                PIN_CFG(180, ALT_A)
+#define GPIO180_U3_TXD         PIN_CFG(180, ALT_B)
+#define GPIO180_BUSMON_D33     PIN_CFG(180, ALT_C)
+
+#define GPIO185_GPIO           PIN_CFG(185, GPIO)
+#define GPIO185_SPI3_CS2n      PIN_CFG(185, ALT_A)
+#define GPIO185_MC4_DAT0       PIN_CFG(185, ALT_B)
+
+#define GPIO186_GPIO           PIN_CFG(186, GPIO)
+#define GPIO186_SPI3_CS1n      PIN_CFG(186, ALT_A)
+#define GPIO186_MC4_DAT1       PIN_CFG(186, ALT_B)
+
+#define GPIO187_GPIO           PIN_CFG(187, GPIO)
+#define GPIO187_SPI3_CS0n      PIN_CFG(187, ALT_A)
+#define GPIO187_MC4_DAT2       PIN_CFG(187, ALT_B)
+
+#define GPIO188_GPIO           PIN_CFG(188, GPIO)
+#define GPIO188_SPI3_RXD       PIN_CFG(188, ALT_A)
+#define GPIO188_MC4_DAT3       PIN_CFG(188, ALT_B)
+
+#define GPIO189_GPIO           PIN_CFG(189, GPIO)
+#define GPIO189_SPI3_TXD       PIN_CFG(189, ALT_A)
+#define GPIO189_MC4_CMD                PIN_CFG(189, ALT_B)
+
+#define GPIO190_GPIO           PIN_CFG(190, GPIO)
+#define GPIO190_SPI3_CLK       PIN_CFG(190, ALT_A)
+#define GPIO190_MC4_CLK                PIN_CFG(190, ALT_B)
+
+#define GPIO191_GPIO           PIN_CFG(191, GPIO)
+#define GPIO191_MC1_DAT0       PIN_CFG(191, ALT_A)
+#define GPIO191_MC4_DAT4       PIN_CFG(191, ALT_B)
+#define GPIO191_STMAPE_DAT0    PIN_CFG(191, ALT_C)
+
+#define GPIO192_GPIO           PIN_CFG(192, GPIO)
+#define GPIO192_MC1_DAT1       PIN_CFG(192, ALT_A)
+#define GPIO192_MC4_DAT5       PIN_CFG(192, ALT_B)
+#define GPIO192_STMAPE_DAT1    PIN_CFG(192, ALT_C)
+
+#define GPIO193_GPIO           PIN_CFG(193, GPIO)
+#define GPIO193_MC1_DAT2       PIN_CFG(193, ALT_A)
+#define GPIO193_MC4_DAT6       PIN_CFG(193, ALT_B)
+#define GPIO193_STMAPE_DAT2    PIN_CFG(193, ALT_C)
+
+#define GPIO194_GPIO           PIN_CFG(194, GPIO)
+#define GPIO194_MC1_DAT3       PIN_CFG(194, ALT_A)
+#define GPIO194_MC4_DAT7       PIN_CFG(194, ALT_B)
+#define GPIO194_STMAPE_DAT3    PIN_CFG(194, ALT_C)
+
+#define GPIO195_GPIO           PIN_CFG(195, GPIO)
+#define GPIO195_MC1_CLK                PIN_CFG(195, ALT_A)
+#define GPIO195_STMAPE_CLK     PIN_CFG(195, ALT_B)
+#define GPIO195_BUSMON_CLK     PIN_CFG(195, ALT_C)
+
+#define GPIO196_GPIO           PIN_CFG(196, GPIO)
+#define GPIO196_MC1_CMD                PIN_CFG(196, ALT_A)
+#define GPIO196_U0_RXD         PIN_CFG(196, ALT_B)
+#define GPIO196_BUSMON_D38     PIN_CFG(196, ALT_C)
+
+#define GPIO197_GPIO           PIN_CFG(197, GPIO)
+#define GPIO197_MC1_CMDDIR     PIN_CFG(197, ALT_A)
+#define GPIO197_BUSMON_D39     PIN_CFG(197, ALT_B)
+
+#define GPIO198_GPIO           PIN_CFG(198, GPIO)
+#define GPIO198_MC1_FBCLK      PIN_CFG(198, ALT_A)
+
+#define GPIO199_GPIO           PIN_CFG(199, GPIO)
+#define GPIO199_MC1_DAT0DIR    PIN_CFG(199, ALT_A)
+#define GPIO199_BUSMON_D40     PIN_CFG(199, ALT_B)
+
+#define GPIO200_GPIO           PIN_CFG(200, GPIO)
+#define GPIO200_U1_TXD         PIN_CFG(200, ALT_A)
+#define GPIO200_ACCU0_RTSn     PIN_CFG(200, ALT_B)
+
+#define GPIO201_GPIO           PIN_CFG(201, GPIO)
+#define GPIO201_U1_RXD         PIN_CFG(201, ALT_A)
+#define GPIO201_ACCU0_CTSn     PIN_CFG(201, ALT_B)
+
+#define GPIO202_GPIO           PIN_CFG(202, GPIO)
+#define GPIO202_U1_CTSn                PIN_CFG(202, ALT_A)
+#define GPIO202_ACCU0_RXD      PIN_CFG(202, ALT_B)
+
+#define GPIO203_GPIO           PIN_CFG(203, GPIO)
+#define GPIO203_U1_RTSn                PIN_CFG(203, ALT_A)
+#define GPIO203_ACCU0_TXD      PIN_CFG(203, ALT_B)
+
+#define GPIO204_GPIO           PIN_CFG(204, GPIO)
+#define GPIO204_SPI0_CS2n      PIN_CFG(204, ALT_A)
+#define GPIO204_ACCGPIO_000    PIN_CFG(204, ALT_B)
+#define GPIO204_LCD_VSI1       PIN_CFG(204, ALT_C)
+
+#define GPIO205_GPIO           PIN_CFG(205, GPIO)
+#define GPIO205_SPI0_CS1n      PIN_CFG(205, ALT_A)
+#define GPIO205_ACCGPIO_001    PIN_CFG(205, ALT_B)
+#define GPIO205_LCD_D3         PIN_CFG(205, ALT_C)
+
+#define GPIO206_GPIO           PIN_CFG(206, GPIO)
+#define GPIO206_SPI0_CS0n      PIN_CFG(206, ALT_A)
+#define GPIO206_ACCGPIO_002    PIN_CFG(206, ALT_B)
+#define GPIO206_LCD_D2         PIN_CFG(206, ALT_C)
+
+#define GPIO207_GPIO           PIN_CFG(207, GPIO)
+#define GPIO207_SPI0_RXD       PIN_CFG(207, ALT_A)
+#define GPIO207_ACCGPIO_003    PIN_CFG(207, ALT_B)
+#define GPIO207_LCD_D1         PIN_CFG(207, ALT_C)
+
+#define GPIO208_GPIO           PIN_CFG(208, GPIO)
+#define GPIO208_SPI0_TXD       PIN_CFG(208, ALT_A)
+#define GPIO208_ACCGPIO_004    PIN_CFG(208, ALT_B)
+#define GPIO208_LCD_D0         PIN_CFG(208, ALT_C)
+
+#define GPIO209_GPIO           PIN_CFG(209, GPIO)
+#define GPIO209_SPI0_CLK       PIN_CFG(209, ALT_A)
+#define GPIO209_ACCGPIO_005    PIN_CFG(209, ALT_B)
+#define GPIO209_LCD_CLK                PIN_CFG(209, ALT_C)
+
+#define GPIO210_GPIO           PIN_CFG(210, GPIO)
+#define GPIO210_LCD_VSO                PIN_CFG(210, ALT_A)
+#define GPIO210_PRCMU_PWRCTRL1 PIN_CFG(210, ALT_B)
+
+#define GPIO211_GPIO           PIN_CFG(211, GPIO)
+#define GPIO211_LCD_VSI0       PIN_CFG(211, ALT_A)
+#define GPIO211_PRCMU_PWRCTRL2 PIN_CFG(211, ALT_B)
+
+#define GPIO212_GPIO           PIN_CFG(212, GPIO)
+#define GPIO212_SPI2_CS2n      PIN_CFG(212, ALT_A)
+#define GPIO212_LCD_HSO                PIN_CFG(212, ALT_B)
+
+#define GPIO213_GPIO           PIN_CFG(213, GPIO)
+#define GPIO213_SPI2_CS1n      PIN_CFG(213, ALT_A)
+#define GPIO213_LCD_DE         PIN_CFG(213, ALT_B)
+#define GPIO213_BUSMON_D16     PIN_CFG(213, ALT_C)
+
+#define GPIO214_GPIO           PIN_CFG(214, GPIO)
+#define GPIO214_SPI2_CS0n      PIN_CFG(214, ALT_A)
+#define GPIO214_LCD_D7         PIN_CFG(214, ALT_B)
+#define GPIO214_BUSMON_D17     PIN_CFG(214, ALT_C)
+
+#define GPIO215_GPIO           PIN_CFG(215, GPIO)
+#define GPIO215_SPI2_RXD       PIN_CFG(215, ALT_A)
+#define GPIO215_LCD_D6         PIN_CFG(215, ALT_B)
+#define GPIO215_BUSMON_D18     PIN_CFG(215, ALT_C)
+
+#define GPIO216_GPIO           PIN_CFG(216, GPIO)
+#define GPIO216_SPI2_CLK       PIN_CFG(216, ALT_A)
+#define GPIO216_LCD_D5         PIN_CFG(216, ALT_B)
+
+#define GPIO217_GPIO           PIN_CFG(217, GPIO)
+#define GPIO217_SPI2_TXD       PIN_CFG(217, ALT_A)
+#define GPIO217_LCD_D4         PIN_CFG(217, ALT_B)
+#define GPIO217_BUSMON_D19     PIN_CFG(217, ALT_C)
+
+#define GPIO218_GPIO           PIN_CFG(218, GPIO)
+#define GPIO218_I2C2_SCL       PIN_CFG(218, ALT_A)
+#define GPIO218_LCD_VSO                PIN_CFG(218, ALT_B)
+
+#define GPIO219_GPIO           PIN_CFG(219, GPIO)
+#define GPIO219_I2C2_SDA       PIN_CFG(219, ALT_A)
+#define GPIO219_LCD_D3         PIN_CFG(219, ALT_B)
+
+#define GPIO220_GPIO           PIN_CFG(220, GPIO)
+#define GPIO220_MSP2_TCK       PIN_CFG(220, ALT_A)
+#define GPIO220_LCD_D2         PIN_CFG(220, ALT_B)
+
+#define GPIO221_GPIO           PIN_CFG(221, GPIO)
+#define GPIO221_MSP2_TFS       PIN_CFG(221, ALT_A)
+#define GPIO221_LCD_D1         PIN_CFG(221, ALT_B)
+
+#define GPIO222_GPIO           PIN_CFG(222, GPIO)
+#define GPIO222_MSP2_TXD       PIN_CFG(222, ALT_A)
+#define GPIO222_LCD_D0         PIN_CFG(222, ALT_B)
+
+#define GPIO223_GPIO           PIN_CFG(223, GPIO)
+#define GPIO223_MSP2_RXD       PIN_CFG(223, ALT_A)
+#define GPIO223_LCD_CLK                PIN_CFG(223, ALT_B)
+
+#define GPIO224_GPIO           PIN_CFG(224, GPIO)
+#define GPIO224_PRCMU_PWRCTRL0 PIN_CFG(224, ALT_A)
+#define GPIO224_LCD_VSI1       PIN_CFG(224, ALT_B)
+
+#define GPIO225_GPIO           PIN_CFG(225, GPIO)
+#define GPIO225_PRCMU_PWRCTRL1 PIN_CFG(225, ALT_A)
+#define GPIO225_IRDA_RXD       PIN_CFG(225, ALT_B)
+
+#define GPIO226_GPIO           PIN_CFG(226, GPIO)
+#define GPIO226_PRCMU_PWRCTRL2 PIN_CFG(226, ALT_A)
+#define GPIO226_IRRC_DAT       PIN_CFG(226, ALT_B)
+
+#define GPIO227_GPIO           PIN_CFG(227, GPIO)
+#define GPIO227_IRRC_DAT       PIN_CFG(227, ALT_A)
+#define GPIO227_IRDA_TXD       PIN_CFG(227, ALT_B)
+
+#endif
index 9055d5d3233c90c906ded7b8030c54db64289839..66f8761cc823cfd5a3670c773da50b087822bb94 100644 (file)
 #define GPIO17_SLIM0_CLK       PIN_CFG(17, ALT_C)
 
 #define GPIO18_GPIO            PIN_CFG(18, GPIO)
-#define GPIO18_MC0_CMDDIR      PIN_CFG(18, ALT_A)
+#define GPIO18_MC0_CMDDIR      PIN_CFG_PULL(18, ALT_A, UP)
 #define GPIO18_U2_RXD          PIN_CFG(18, ALT_B)
 #define GPIO18_MS_IEP          PIN_CFG(18, ALT_C)
 
 #define GPIO19_GPIO            PIN_CFG(19, GPIO)
-#define GPIO19_MC0_DAT0DIR     PIN_CFG(19, ALT_A)
+#define GPIO19_MC0_DAT0DIR     PIN_CFG_PULL(19, ALT_A, UP)
 #define GPIO19_U2_TXD          PIN_CFG(19, ALT_B)
 #define GPIO19_MS_DAT0DIR      PIN_CFG(19, ALT_C)
 
 #define GPIO20_GPIO            PIN_CFG(20, GPIO)
-#define GPIO20_MC0_DAT2DIR     PIN_CFG(20, ALT_A)
+#define GPIO20_MC0_DAT2DIR     PIN_CFG_PULL(20, ALT_A, UP)
 #define GPIO20_UARTMOD_TXD     PIN_CFG(20, ALT_B)
 #define GPIO20_IP_TRIGOUT      PIN_CFG(20, ALT_C)
 
 #define GPIO21_GPIO            PIN_CFG(21, GPIO)
-#define GPIO21_MC0_DAT31DIR    PIN_CFG(21, ALT_A)
+#define GPIO21_MC0_DAT31DIR    PIN_CFG_PULL(21, ALT_A, UP)
 #define GPIO21_MSP0_SCK                PIN_CFG(21, ALT_B)
 #define GPIO21_MS_DAT31DIR     PIN_CFG(21, ALT_C)
 
 #define GPIO22_GPIO            PIN_CFG(22, GPIO)
-#define GPIO22_MC0_FBCLK       PIN_CFG(22, ALT_A)
+#define GPIO22_MC0_FBCLK       PIN_CFG_PULL(22, ALT_A, UP)
 #define GPIO22_UARTMOD_RXD     PIN_CFG(22, ALT_B)
 #define GPIO22_MS_FBCLK                PIN_CFG(22, ALT_C)
 
 #define GPIO23_GPIO            PIN_CFG(23, GPIO)
-#define GPIO23_MC0_CLK         PIN_CFG(23, ALT_A)
+#define GPIO23_MC0_CLK         PIN_CFG_PULL(23, ALT_A, UP)
 #define GPIO23_STMMOD_CLK      PIN_CFG(23, ALT_B)
 #define GPIO23_MS_CLK          PIN_CFG(23, ALT_C)
 
 #define GPIO24_GPIO            PIN_CFG(24, GPIO)
-#define GPIO24_MC0_CMD         PIN_CFG(24, ALT_A)
+#define GPIO24_MC0_CMD         PIN_CFG_PULL(24, ALT_A, UP)
 #define GPIO24_UARTMOD_RXD     PIN_CFG(24, ALT_B)
 #define GPIO24_MS_BS           PIN_CFG(24, ALT_C)
 
 #define GPIO25_GPIO            PIN_CFG(25, GPIO)
-#define GPIO25_MC0_DAT0                PIN_CFG(25, ALT_A)
+#define GPIO25_MC0_DAT0                PIN_CFG_PULL(25, ALT_A, UP)
 #define GPIO25_STMMOD_DAT0     PIN_CFG(25, ALT_B)
 #define GPIO25_MS_DAT0         PIN_CFG(25, ALT_C)
 
 #define GPIO26_GPIO            PIN_CFG(26, GPIO)
-#define GPIO26_MC0_DAT1                PIN_CFG(26, ALT_A)
+#define GPIO26_MC0_DAT1                PIN_CFG_PULL(26, ALT_A, UP)
 #define GPIO26_STMMOD_DAT1     PIN_CFG(26, ALT_B)
 #define GPIO26_MS_DAT1         PIN_CFG(26, ALT_C)
 
 #define GPIO27_GPIO            PIN_CFG(27, GPIO)
-#define GPIO27_MC0_DAT2                PIN_CFG(27, ALT_A)
+#define GPIO27_MC0_DAT2                PIN_CFG_PULL(27, ALT_A, UP)
 #define GPIO27_STMMOD_DAT2     PIN_CFG(27, ALT_B)
 #define GPIO27_MS_DAT2         PIN_CFG(27, ALT_C)
 
 #define GPIO28_GPIO            PIN_CFG(28, GPIO)
-#define GPIO28_MC0_DAT3                PIN_CFG(28, ALT_A)
+#define GPIO28_MC0_DAT3                PIN_CFG_PULL(28, ALT_A, UP)
 #define GPIO28_STMMOD_DAT3     PIN_CFG(28, ALT_B)
 #define GPIO28_MS_DAT3         PIN_CFG(28, ALT_C)
 
 #define GPIO97_MC5_DAT7                PIN_CFG(97, ALT_C)
 
 #define GPIO128_GPIO           PIN_CFG(128, GPIO)
-#define GPIO128_MC2_CLK                PIN_CFG(128, ALT_A)
+#define GPIO128_MC2_CLK                PIN_CFG_PULL(128, ALT_A, UP)
 #define GPIO128_SM_CKO         PIN_CFG(128, ALT_B)
 
 #define GPIO129_GPIO           PIN_CFG(129, GPIO)
-#define GPIO129_MC2_CMD                PIN_CFG(129, ALT_A)
+#define GPIO129_MC2_CMD                PIN_CFG_PULL(129, ALT_A, UP)
 #define GPIO129_SM_WAIT0n      PIN_CFG(129, ALT_B)
 
 #define GPIO130_GPIO           PIN_CFG(130, GPIO)
-#define GPIO130_MC2_FBCLK      PIN_CFG(130, ALT_A)
+#define GPIO130_MC2_FBCLK      PIN_CFG_PULL(130, ALT_A, UP)
 #define GPIO130_SM_FBCLK       PIN_CFG(130, ALT_B)
 #define GPIO130_MC2_RSTN       PIN_CFG(130, ALT_C)
 
 #define GPIO131_GPIO           PIN_CFG(131, GPIO)
-#define GPIO131_MC2_DAT0       PIN_CFG(131, ALT_A)
+#define GPIO131_MC2_DAT0       PIN_CFG_PULL(131, ALT_A, UP)
 #define GPIO131_SM_ADQ8                PIN_CFG(131, ALT_B)
 
 #define GPIO132_GPIO           PIN_CFG(132, GPIO)
-#define GPIO132_MC2_DAT1       PIN_CFG(132, ALT_A)
+#define GPIO132_MC2_DAT1       PIN_CFG_PULL(132, ALT_A, UP)
 #define GPIO132_SM_ADQ9                PIN_CFG(132, ALT_B)
 
 #define GPIO133_GPIO           PIN_CFG(133, GPIO)
-#define GPIO133_MC2_DAT2       PIN_CFG(133, ALT_A)
+#define GPIO133_MC2_DAT2       PIN_CFG_PULL(133, ALT_A, UP)
 #define GPIO133_SM_ADQ10       PIN_CFG(133, ALT_B)
 
 #define GPIO134_GPIO           PIN_CFG(134, GPIO)
-#define GPIO134_MC2_DAT3       PIN_CFG(134, ALT_A)
+#define GPIO134_MC2_DAT3       PIN_CFG_PULL(134, ALT_A, UP)
 #define GPIO134_SM_ADQ11       PIN_CFG(134, ALT_B)
 
 #define GPIO135_GPIO           PIN_CFG(135, GPIO)
-#define GPIO135_MC2_DAT4       PIN_CFG(135, ALT_A)
+#define GPIO135_MC2_DAT4       PIN_CFG_PULL(135, ALT_A, UP)
 #define GPIO135_SM_ADQ12       PIN_CFG(135, ALT_B)
 
 #define GPIO136_GPIO           PIN_CFG(136, GPIO)
-#define GPIO136_MC2_DAT5       PIN_CFG(136, ALT_A)
+#define GPIO136_MC2_DAT5       PIN_CFG_PULL(136, ALT_A, UP)
 #define GPIO136_SM_ADQ13       PIN_CFG(136, ALT_B)
 
 #define GPIO137_GPIO           PIN_CFG(137, GPIO)
-#define GPIO137_MC2_DAT6       PIN_CFG(137, ALT_A)
+#define GPIO137_MC2_DAT6       PIN_CFG_PULL(137, ALT_A, UP)
 #define GPIO137_SM_ADQ14       PIN_CFG(137, ALT_B)
 
 #define GPIO138_GPIO           PIN_CFG(138, GPIO)
-#define GPIO138_MC2_DAT7       PIN_CFG(138, ALT_A)
+#define GPIO138_MC2_DAT7       PIN_CFG_PULL(138, ALT_A, UP)
 #define GPIO138_SM_ADQ15       PIN_CFG(138, ALT_B)
 
 #define GPIO139_GPIO           PIN_CFG(139, GPIO)
 #define GPIO196_MSP2_RXD       PIN_CFG(196, ALT_A)
 
 #define GPIO197_GPIO           PIN_CFG(197, GPIO)
-#define GPIO197_MC4_DAT3       PIN_CFG(197, ALT_A)
+#define GPIO197_MC4_DAT3       PIN_CFG_PULL(197, ALT_A, UP)
 
 #define GPIO198_GPIO           PIN_CFG(198, GPIO)
-#define GPIO198_MC4_DAT2       PIN_CFG(198, ALT_A)
+#define GPIO198_MC4_DAT2       PIN_CFG_PULL(198, ALT_A, UP)
 
 #define GPIO199_GPIO           PIN_CFG(199, GPIO)
-#define GPIO199_MC4_DAT1       PIN_CFG(199, ALT_A)
+#define GPIO199_MC4_DAT1       PIN_CFG_PULL(199, ALT_A, UP)
 
 #define GPIO200_GPIO           PIN_CFG(200, GPIO)
-#define GPIO200_MC4_DAT0       PIN_CFG(200, ALT_A)
+#define GPIO200_MC4_DAT0       PIN_CFG_PULL(200, ALT_A, UP)
 
 #define GPIO201_GPIO           PIN_CFG(201, GPIO)
-#define GPIO201_MC4_CMD                PIN_CFG(201, ALT_A)
+#define GPIO201_MC4_CMD                PIN_CFG_PULL(201, ALT_A, UP)
 
 #define GPIO202_GPIO           PIN_CFG(202, GPIO)
-#define GPIO202_MC4_FBCLK      PIN_CFG(202, ALT_A)
+#define GPIO202_MC4_FBCLK      PIN_CFG_PULL(202, ALT_A, UP)
 #define GPIO202_PWL            PIN_CFG(202, ALT_B)
 #define GPIO202_MC4_RSTN       PIN_CFG(202, ALT_C)
 
 #define GPIO203_GPIO           PIN_CFG(203, GPIO)
-#define GPIO203_MC4_CLK                PIN_CFG(203, ALT_A)
+#define GPIO203_MC4_CLK                PIN_CFG_PULL(203, ALT_A, UP)
 
 #define GPIO204_GPIO           PIN_CFG(204, GPIO)
-#define GPIO204_MC4_DAT7       PIN_CFG(204, ALT_A)
+#define GPIO204_MC4_DAT7       PIN_CFG_PULL(204, ALT_A, UP)
 
 #define GPIO205_GPIO           PIN_CFG(205, GPIO)
-#define GPIO205_MC4_DAT6       PIN_CFG(205, ALT_A)
+#define GPIO205_MC4_DAT6       PIN_CFG_PULL(205, ALT_A, UP)
 
 #define GPIO206_GPIO           PIN_CFG(206, GPIO)
-#define GPIO206_MC4_DAT5       PIN_CFG(206, ALT_A)
+#define GPIO206_MC4_DAT5       PIN_CFG_PULL(206, ALT_A, UP)
 
 #define GPIO207_GPIO           PIN_CFG(207, GPIO)
-#define GPIO207_MC4_DAT4       PIN_CFG(207, ALT_A)
+#define GPIO207_MC4_DAT4       PIN_CFG_PULL(207, ALT_A, UP)
 
 #define GPIO208_GPIO           PIN_CFG(208, GPIO)
 #define GPIO208_MC1_CLK                PIN_CFG(208, ALT_A)
index 438ef16aec901e2e11a4d0b6ebb9b5bae165fb1b..9e4c678de78593a248c9010a4eb8e0edcb4cb4dc 100644 (file)
@@ -78,6 +78,8 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
        __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
        outer_clean_range(__pa(&pen_release), __pa(&pen_release) + 1);
 
+       smp_cross_call(cpumask_of(cpu));
+
        timeout = jiffies + (1 * HZ);
        while (time_before(jiffies, timeout)) {
                if (pen_release == -1)
diff --git a/arch/arm/mach-ux500/prcmu.c b/arch/arm/mach-ux500/prcmu.c
new file mode 100644 (file)
index 0000000..293274d
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) ST Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U8500 PRCMU driver.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+
+#include <mach/hardware.h>
+#include <mach/prcmu-regs.h>
+
+#define PRCMU_TCDM_BASE __io_address(U8500_PRCMU_TCDM_BASE)
+
+#define REQ_MB5 (PRCMU_TCDM_BASE + 0xE44)
+#define ACK_MB5 (PRCMU_TCDM_BASE + 0xDF4)
+
+#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5)
+#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1)
+#define REQ_MB5_I2C_REG (REQ_MB5 + 2)
+#define REQ_MB5_I2C_VAL (REQ_MB5 + 3)
+
+#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
+#define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
+
+#define I2C_WRITE(slave) ((slave) << 1)
+#define I2C_READ(slave) (((slave) << 1) | BIT(0))
+#define I2C_STOP_EN BIT(3)
+
+enum ack_mb5_status {
+       I2C_WR_OK = 0x01,
+       I2C_RD_OK = 0x02,
+};
+
+#define MBOX_BIT BIT
+#define NUM_MBOX 8
+
+static struct {
+       struct mutex lock;
+       struct completion work;
+       bool failed;
+       struct {
+               u8 status;
+               u8 value;
+       } ack;
+} mb5_transfer;
+
+/**
+ * prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The read out value(s).
+ * @size:      The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if (size != 1)
+               return -EINVAL;
+
+       r = mutex_lock_interruptible(&mb5_transfer.lock);
+       if (r)
+               return r;
+
+       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+
+       writeb(I2C_READ(slave), REQ_MB5_I2C_SLAVE_OP);
+       writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
+       writeb(reg, REQ_MB5_I2C_REG);
+
+       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+       if (!wait_for_completion_timeout(&mb5_transfer.work,
+                       msecs_to_jiffies(500))) {
+               pr_err("prcmu: prcmu_abb_read timed out.\n");
+               r = -EIO;
+               goto unlock_and_return;
+       }
+       r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
+       if (!r)
+               *value = mb5_transfer.ack.value;
+
+unlock_and_return:
+       mutex_unlock(&mb5_transfer.lock);
+       return r;
+}
+EXPORT_SYMBOL(prcmu_abb_read);
+
+/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave:     The I2C slave address.
+ * @reg:       The (start) register address.
+ * @value:     The value(s) to write.
+ * @size:      The number of registers to write.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+       int r;
+
+       if (size != 1)
+               return -EINVAL;
+
+       r = mutex_lock_interruptible(&mb5_transfer.lock);
+       if (r)
+               return r;
+
+
+       while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+               cpu_relax();
+
+       writeb(I2C_WRITE(slave), REQ_MB5_I2C_SLAVE_OP);
+       writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
+       writeb(reg, REQ_MB5_I2C_REG);
+       writeb(*value, REQ_MB5_I2C_VAL);
+
+       writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+       if (!wait_for_completion_timeout(&mb5_transfer.work,
+                       msecs_to_jiffies(500))) {
+               pr_err("prcmu: prcmu_abb_write timed out.\n");
+               r = -EIO;
+               goto unlock_and_return;
+       }
+       r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
+
+unlock_and_return:
+       mutex_unlock(&mb5_transfer.lock);
+       return r;
+}
+EXPORT_SYMBOL(prcmu_abb_write);
+
+static void read_mailbox_0(void)
+{
+       writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_1(void)
+{
+       writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_2(void)
+{
+       writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_3(void)
+{
+       writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_4(void)
+{
+       writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_5(void)
+{
+       mb5_transfer.ack.status = readb(ACK_MB5_I2C_STATUS);
+       mb5_transfer.ack.value = readb(ACK_MB5_I2C_VAL);
+       complete(&mb5_transfer.work);
+       writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_6(void)
+{
+       writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
+}
+
+static void read_mailbox_7(void)
+{
+       writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
+}
+
+static void (* const read_mailbox[NUM_MBOX])(void) = {
+       read_mailbox_0,
+       read_mailbox_1,
+       read_mailbox_2,
+       read_mailbox_3,
+       read_mailbox_4,
+       read_mailbox_5,
+       read_mailbox_6,
+       read_mailbox_7
+};
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+       u32 bits;
+       u8 n;
+
+       bits = (readl(PRCM_ARM_IT1_VAL) & (MBOX_BIT(NUM_MBOX) - 1));
+       if (unlikely(!bits))
+               return IRQ_NONE;
+
+       for (n = 0; bits; n++) {
+               if (bits & MBOX_BIT(n)) {
+                       bits -= MBOX_BIT(n);
+                       read_mailbox[n]();
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+static int __init prcmu_init(void)
+{
+       mutex_init(&mb5_transfer.lock);
+       init_completion(&mb5_transfer.work);
+
+       /* Clean up the mailbox interrupts after pre-kernel code. */
+       writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR);
+
+       return request_irq(IRQ_PRCMU, prcmu_irq_handler, 0, "prcmu", NULL);
+}
+
+arch_initcall(prcmu_init);
diff --git a/arch/arm/mach-ux500/ste-dma40-db5500.h b/arch/arm/mach-ux500/ste-dma40-db5500.h
new file mode 100644 (file)
index 0000000..cb2110c
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * DB5500-SoC-specific configuration for DMA40
+ */
+
+#ifndef STE_DMA40_DB5500_H
+#define STE_DMA40_DB5500_H
+
+#define DB5500_DMA_NR_DEV 64
+
+enum dma_src_dev_type {
+       DB5500_DMA_DEV0_SPI0_RX = 0,
+       DB5500_DMA_DEV1_SPI1_RX = 1,
+       DB5500_DMA_DEV2_SPI2_RX = 2,
+       DB5500_DMA_DEV3_SPI3_RX = 3,
+       DB5500_DMA_DEV4_USB_OTG_IEP_1_9 = 4,
+       DB5500_DMA_DEV5_USB_OTG_IEP_2_10 = 5,
+       DB5500_DMA_DEV6_USB_OTG_IEP_3_11 = 6,
+       DB5500_DMA_DEV7_IRDA_RFS = 7,
+       DB5500_DMA_DEV8_IRDA_FIFO_RX = 8,
+       DB5500_DMA_DEV9_MSP0_RX = 9,
+       DB5500_DMA_DEV10_MSP1_RX = 10,
+       DB5500_DMA_DEV11_MSP2_RX = 11,
+       DB5500_DMA_DEV12_UART0_RX = 12,
+       DB5500_DMA_DEV13_UART1_RX = 13,
+       DB5500_DMA_DEV14_UART2_RX = 14,
+       DB5500_DMA_DEV15_UART3_RX = 15,
+       DB5500_DMA_DEV16_USB_OTG_IEP_8 = 16,
+       DB5500_DMA_DEV17_USB_OTG_IEP_1_9 = 17,
+       DB5500_DMA_DEV18_USB_OTG_IEP_2_10 = 18,
+       DB5500_DMA_DEV19_USB_OTG_IEP_3_11 = 19,
+       DB5500_DMA_DEV20_USB_OTG_IEP_4_12 = 20,
+       DB5500_DMA_DEV21_USB_OTG_IEP_5_13 = 21,
+       DB5500_DMA_DEV22_USB_OTG_IEP_6_14 = 22,
+       DB5500_DMA_DEV23_USB_OTG_IEP_7_15 = 23,
+       DB5500_DMA_DEV24_SDMMC0_RX = 24,
+       DB5500_DMA_DEV25_SDMMC1_RX = 25,
+       DB5500_DMA_DEV26_SDMMC2_RX = 26,
+       DB5500_DMA_DEV27_SDMMC3_RX = 27,
+       DB5500_DMA_DEV28_SDMMC4_RX = 28,
+       /* 29 - 32 not used */
+       DB5500_DMA_DEV33_SDMMC0_RX = 33,
+       DB5500_DMA_DEV34_SDMMC1_RX = 34,
+       DB5500_DMA_DEV35_SDMMC2_RX = 35,
+       DB5500_DMA_DEV36_SDMMC3_RX = 36,
+       DB5500_DMA_DEV37_SDMMC4_RX = 37,
+       DB5500_DMA_DEV38_USB_OTG_IEP_8 = 38,
+       DB5500_DMA_DEV39_USB_OTG_IEP_1_9 = 39,
+       DB5500_DMA_DEV40_USB_OTG_IEP_2_10 = 40,
+       DB5500_DMA_DEV41_USB_OTG_IEP_3_11 = 41,
+       DB5500_DMA_DEV42_USB_OTG_IEP_4_12 = 42,
+       DB5500_DMA_DEV43_USB_OTG_IEP_5_13 = 43,
+       DB5500_DMA_DEV44_USB_OTG_IEP_6_14 = 44,
+       DB5500_DMA_DEV45_USB_OTG_IEP_7_15 = 45,
+       /* 46 not used */
+       DB5500_DMA_DEV47_MCDE_RX = 47,
+       DB5500_DMA_DEV48_CRYPTO1_RX = 48,
+       /* 49, 50 not used */
+       DB5500_DMA_DEV49_I2C1_RX = 51,
+       DB5500_DMA_DEV50_I2C3_RX = 52,
+       DB5500_DMA_DEV51_I2C2_RX = 53,
+       /* 54 - 60 not used */
+       DB5500_DMA_DEV61_CRYPTO0_RX = 61,
+       /* 62, 63 not used */
+};
+
+enum dma_dest_dev_type {
+       DB5500_DMA_DEV0_SPI0_TX = 0,
+       DB5500_DMA_DEV1_SPI1_TX = 1,
+       DB5500_DMA_DEV2_SPI2_TX = 2,
+       DB5500_DMA_DEV3_SPI3_TX = 3,
+       DB5500_DMA_DEV4_USB_OTG_OEP_1_9 = 4,
+       DB5500_DMA_DEV5_USB_OTG_OEP_2_10 = 5,
+       DB5500_DMA_DEV6_USB_OTG_OEP_3_11 = 6,
+       DB5500_DMA_DEV7_IRRC_TX = 7,
+       DB5500_DMA_DEV8_IRDA_FIFO_TX = 8,
+       DB5500_DMA_DEV9_MSP0_TX = 9,
+       DB5500_DMA_DEV10_MSP1_TX = 10,
+       DB5500_DMA_DEV11_MSP2_TX = 11,
+       DB5500_DMA_DEV12_UART0_TX = 12,
+       DB5500_DMA_DEV13_UART1_TX = 13,
+       DB5500_DMA_DEV14_UART2_TX = 14,
+       DB5500_DMA_DEV15_UART3_TX = 15,
+       DB5500_DMA_DEV16_USB_OTG_OEP_8 = 16,
+       DB5500_DMA_DEV17_USB_OTG_OEP_1_9 = 17,
+       DB5500_DMA_DEV18_USB_OTG_OEP_2_10 = 18,
+       DB5500_DMA_DEV19_USB_OTG_OEP_3_11 = 19,
+       DB5500_DMA_DEV20_USB_OTG_OEP_4_12 = 20,
+       DB5500_DMA_DEV21_USB_OTG_OEP_5_13 = 21,
+       DB5500_DMA_DEV22_USB_OTG_OEP_6_14 = 22,
+       DB5500_DMA_DEV23_USB_OTG_OEP_7_15 = 23,
+       DB5500_DMA_DEV24_SDMMC0_TX = 24,
+       DB5500_DMA_DEV25_SDMMC1_TX = 25,
+       DB5500_DMA_DEV26_SDMMC2_TX = 26,
+       DB5500_DMA_DEV27_SDMMC3_TX = 27,
+       DB5500_DMA_DEV28_SDMMC4_TX = 28,
+       /* 29 - 31 not used */
+       DB5500_DMA_DEV32_FSMC_TX = 32,
+       DB5500_DMA_DEV33_SDMMC0_TX = 33,
+       DB5500_DMA_DEV34_SDMMC1_TX = 34,
+       DB5500_DMA_DEV35_SDMMC2_TX = 35,
+       DB5500_DMA_DEV36_SDMMC3_TX = 36,
+       DB5500_DMA_DEV37_SDMMC4_TX = 37,
+       DB5500_DMA_DEV38_USB_OTG_OEP_8 = 38,
+       DB5500_DMA_DEV39_USB_OTG_OEP_1_9 = 39,
+       DB5500_DMA_DEV40_USB_OTG_OEP_2_10 = 40,
+       DB5500_DMA_DEV41_USB_OTG_OEP_3_11 = 41,
+       DB5500_DMA_DEV42_USB_OTG_OEP_4_12 = 42,
+       DB5500_DMA_DEV43_USB_OTG_OEP_5_13 = 43,
+       DB5500_DMA_DEV44_USB_OTG_OEP_6_14 = 44,
+       DB5500_DMA_DEV45_USB_OTG_OEP_7_15 = 45,
+       /* 46 not used */
+       DB5500_DMA_DEV47_STM_TX = 47,
+       DB5500_DMA_DEV48_CRYPTO1_TX = 48,
+       DB5500_DMA_DEV49_CRYPTO1_TX_HASH1_TX = 49,
+       DB5500_DMA_DEV50_HASH1_TX = 50,
+       DB5500_DMA_DEV51_I2C1_TX = 51,
+       DB5500_DMA_DEV52_I2C3_TX = 52,
+       DB5500_DMA_DEV53_I2C2_TX = 53,
+       /* 54, 55 not used */
+       DB5500_DMA_MEMCPY_TX_1 = 56,
+       DB5500_DMA_MEMCPY_TX_2 = 57,
+       DB5500_DMA_MEMCPY_TX_3 = 58,
+       DB5500_DMA_MEMCPY_TX_4 = 59,
+       DB5500_DMA_MEMCPY_TX_5 = 60,
+       DB5500_DMA_DEV61_CRYPTO0_TX = 61,
+       DB5500_DMA_DEV62_CRYPTO0_TX_HASH0_TX = 62,
+       DB5500_DMA_DEV63_HASH0_TX = 63,
+};
+
+#endif
index 9d9d3797b3b05a5cae83affcfe7817912b7bf651..a616419bea76f3f529578e86cd970a1528ee77ab 100644 (file)
 #ifndef STE_DMA40_DB8500_H
 #define STE_DMA40_DB8500_H
 
-#define STEDMA40_NR_DEV 64
+#define DB8500_DMA_NR_DEV 64
 
 enum dma_src_dev_type {
-       STEDMA40_DEV_SPI0_RX = 0,
-       STEDMA40_DEV_SD_MMC0_RX = 1,
-       STEDMA40_DEV_SD_MMC1_RX = 2,
-       STEDMA40_DEV_SD_MMC2_RX = 3,
-       STEDMA40_DEV_I2C1_RX = 4,
-       STEDMA40_DEV_I2C3_RX = 5,
-       STEDMA40_DEV_I2C2_RX = 6,
-       STEDMA40_DEV_I2C4_RX = 7, /* Only on V1 */
-       STEDMA40_DEV_SSP0_RX = 8,
-       STEDMA40_DEV_SSP1_RX = 9,
-       STEDMA40_DEV_MCDE_RX = 10,
-       STEDMA40_DEV_UART2_RX = 11,
-       STEDMA40_DEV_UART1_RX = 12,
-       STEDMA40_DEV_UART0_RX = 13,
-       STEDMA40_DEV_MSP2_RX = 14,
-       STEDMA40_DEV_I2C0_RX = 15,
-       STEDMA40_DEV_USB_OTG_IEP_8 = 16,
-       STEDMA40_DEV_USB_OTG_IEP_1_9 = 17,
-       STEDMA40_DEV_USB_OTG_IEP_2_10 = 18,
-       STEDMA40_DEV_USB_OTG_IEP_3_11 = 19,
-       STEDMA40_DEV_SLIM0_CH0_RX_HSI_RX_CH0 = 20,
-       STEDMA40_DEV_SLIM0_CH1_RX_HSI_RX_CH1 = 21,
-       STEDMA40_DEV_SLIM0_CH2_RX_HSI_RX_CH2 = 22,
-       STEDMA40_DEV_SLIM0_CH3_RX_HSI_RX_CH3 = 23,
-       STEDMA40_DEV_SRC_SXA0_RX_TX = 24,
-       STEDMA40_DEV_SRC_SXA1_RX_TX = 25,
-       STEDMA40_DEV_SRC_SXA2_RX_TX = 26,
-       STEDMA40_DEV_SRC_SXA3_RX_TX = 27,
-       STEDMA40_DEV_SD_MM2_RX = 28,
-       STEDMA40_DEV_SD_MM0_RX = 29,
-       STEDMA40_DEV_MSP1_RX = 30,
-       /*
-        * This channel is either SlimBus or MSP,
-        * never both at the same time.
-        */
-       STEDMA40_SLIM0_CH0_RX = 31,
-       STEDMA40_DEV_MSP0_RX = 31,
-       STEDMA40_DEV_SD_MM1_RX = 32,
-       STEDMA40_DEV_SPI2_RX = 33,
-       STEDMA40_DEV_I2C3_RX2 = 34,
-       STEDMA40_DEV_SPI1_RX = 35,
-       STEDMA40_DEV_USB_OTG_IEP_4_12 = 36,
-       STEDMA40_DEV_USB_OTG_IEP_5_13 = 37,
-       STEDMA40_DEV_USB_OTG_IEP_6_14 = 38,
-       STEDMA40_DEV_USB_OTG_IEP_7_15 = 39,
-       STEDMA40_DEV_SPI3_RX = 40,
-       STEDMA40_DEV_SD_MM3_RX = 41,
-       STEDMA40_DEV_SD_MM4_RX = 42,
-       STEDMA40_DEV_SD_MM5_RX = 43,
-       STEDMA40_DEV_SRC_SXA4_RX_TX = 44,
-       STEDMA40_DEV_SRC_SXA5_RX_TX = 45,
-       STEDMA40_DEV_SRC_SXA6_RX_TX = 46,
-       STEDMA40_DEV_SRC_SXA7_RX_TX = 47,
-       STEDMA40_DEV_CAC1_RX = 48,
-       /* RX channels 49 and 50 are unused */
-       STEDMA40_DEV_MSHC_RX = 51,
-       STEDMA40_DEV_SLIM1_CH0_RX_HSI_RX_CH4 = 52,
-       STEDMA40_DEV_SLIM1_CH1_RX_HSI_RX_CH5 = 53,
-       STEDMA40_DEV_SLIM1_CH2_RX_HSI_RX_CH6 = 54,
-       STEDMA40_DEV_SLIM1_CH3_RX_HSI_RX_CH7 = 55,
-       /* RX channels 56 thru 60 are unused */
-       STEDMA40_DEV_CAC0_RX = 61,
-       /* RX channels 62 and 63 are unused */
+       DB8500_DMA_DEV0_SPI0_RX = 0,
+       DB8500_DMA_DEV1_SD_MMC0_RX = 1,
+       DB8500_DMA_DEV2_SD_MMC1_RX = 2,
+       DB8500_DMA_DEV3_SD_MMC2_RX = 3,
+       DB8500_DMA_DEV4_I2C1_RX = 4,
+       DB8500_DMA_DEV5_I2C3_RX = 5,
+       DB8500_DMA_DEV6_I2C2_RX = 6,
+       DB8500_DMA_DEV7_I2C4_RX = 7, /* Only on V1 and later */
+       DB8500_DMA_DEV8_SSP0_RX = 8,
+       DB8500_DMA_DEV9_SSP1_RX = 9,
+       DB8500_DMA_DEV10_MCDE_RX = 10,
+       DB8500_DMA_DEV11_UART2_RX = 11,
+       DB8500_DMA_DEV12_UART1_RX = 12,
+       DB8500_DMA_DEV13_UART0_RX = 13,
+       DB8500_DMA_DEV14_MSP2_RX = 14,
+       DB8500_DMA_DEV15_I2C0_RX = 15,
+       DB8500_DMA_DEV16_USB_OTG_IEP_7_15 = 16,
+       DB8500_DMA_DEV17_USB_OTG_IEP_6_14 = 17,
+       DB8500_DMA_DEV18_USB_OTG_IEP_5_13 = 18,
+       DB8500_DMA_DEV19_USB_OTG_IEP_4_12 = 19,
+       DB8500_DMA_DEV20_SLIM0_CH0_RX_HSI_RX_CH0 = 20,
+       DB8500_DMA_DEV21_SLIM0_CH1_RX_HSI_RX_CH1 = 21,
+       DB8500_DMA_DEV22_SLIM0_CH2_RX_HSI_RX_CH2 = 22,
+       DB8500_DMA_DEV23_SLIM0_CH3_RX_HSI_RX_CH3 = 23,
+       DB8500_DMA_DEV24_SRC_SXA0_RX_TX = 24,
+       DB8500_DMA_DEV25_SRC_SXA1_RX_TX = 25,
+       DB8500_DMA_DEV26_SRC_SXA2_RX_TX = 26,
+       DB8500_DMA_DEV27_SRC_SXA3_RX_TX = 27,
+       DB8500_DMA_DEV28_SD_MM2_RX = 28,
+       DB8500_DMA_DEV29_SD_MM0_RX = 29,
+       DB8500_DMA_DEV30_MSP1_RX = 30,
+       /* On DB8500v2, MSP3 RX replaces MSP1 RX */
+       DB8500_DMA_DEV30_MSP3_RX = 30,
+       DB8500_DMA_DEV31_MSP0_RX_SLIM0_CH0_RX = 31,
+       DB8500_DMA_DEV32_SD_MM1_RX = 32,
+       DB8500_DMA_DEV33_SPI2_RX = 33,
+       DB8500_DMA_DEV34_I2C3_RX2 = 34,
+       DB8500_DMA_DEV35_SPI1_RX = 35,
+       DB8500_DMA_DEV36_USB_OTG_IEP_3_11 = 36,
+       DB8500_DMA_DEV37_USB_OTG_IEP_2_10 = 37,
+       DB8500_DMA_DEV38_USB_OTG_IEP_1_9 = 38,
+       DB8500_DMA_DEV39_USB_OTG_IEP_8 = 39,
+       DB8500_DMA_DEV40_SPI3_RX = 40,
+       DB8500_DMA_DEV41_SD_MM3_RX = 41,
+       DB8500_DMA_DEV42_SD_MM4_RX = 42,
+       DB8500_DMA_DEV43_SD_MM5_RX = 43,
+       DB8500_DMA_DEV44_SRC_SXA4_RX_TX = 44,
+       DB8500_DMA_DEV45_SRC_SXA5_RX_TX = 45,
+       DB8500_DMA_DEV46_SLIM0_CH8_RX_SRC_SXA6_RX_TX = 46,
+       DB8500_DMA_DEV47_SLIM0_CH9_RX_SRC_SXA7_RX_TX = 47,
+       DB8500_DMA_DEV48_CAC1_RX = 48,
+       /* 49, 50 and 51 are not used */
+       DB8500_DMA_DEV52_SLIM0_CH4_RX_HSI_RX_CH4 = 52,
+       DB8500_DMA_DEV53_SLIM0_CH5_RX_HSI_RX_CH5 = 53,
+       DB8500_DMA_DEV54_SLIM0_CH6_RX_HSI_RX_CH6 = 54,
+       DB8500_DMA_DEV55_SLIM0_CH7_RX_HSI_RX_CH7 = 55,
+       /* 56, 57, 58, 59 and 60 are not used */
+       DB8500_DMA_DEV61_CAC0_RX = 61,
+       /* 62 and 63 are not used */
 };
 
 enum dma_dest_dev_type {
-       STEDMA40_DEV_SPI0_TX = 0,
-       STEDMA40_DEV_SD_MMC0_TX = 1,
-       STEDMA40_DEV_SD_MMC1_TX = 2,
-       STEDMA40_DEV_SD_MMC2_TX = 3,
-       STEDMA40_DEV_I2C1_TX = 4,
-       STEDMA40_DEV_I2C3_TX = 5,
-       STEDMA40_DEV_I2C2_TX = 6,
-       STEDMA50_DEV_I2C4_TX = 7, /* Only on V1 */
-       STEDMA40_DEV_SSP0_TX = 8,
-       STEDMA40_DEV_SSP1_TX = 9,
-       /* TX channel 10 is unused */
-       STEDMA40_DEV_UART2_TX = 11,
-       STEDMA40_DEV_UART1_TX = 12,
-       STEDMA40_DEV_UART0_TX= 13,
-       STEDMA40_DEV_MSP2_TX = 14,
-       STEDMA40_DEV_I2C0_TX = 15,
-       STEDMA40_DEV_USB_OTG_OEP_8 = 16,
-       STEDMA40_DEV_USB_OTG_OEP_1_9 = 17,
-       STEDMA40_DEV_USB_OTG_OEP_2_10= 18,
-       STEDMA40_DEV_USB_OTG_OEP_3_11 = 19,
-       STEDMA40_DEV_SLIM0_CH0_TX_HSI_TX_CH0 = 20,
-       STEDMA40_DEV_SLIM0_CH1_TX_HSI_TX_CH1 = 21,
-       STEDMA40_DEV_SLIM0_CH2_TX_HSI_TX_CH2 = 22,
-       STEDMA40_DEV_SLIM0_CH3_TX_HSI_TX_CH3 = 23,
-       STEDMA40_DEV_DST_SXA0_RX_TX = 24,
-       STEDMA40_DEV_DST_SXA1_RX_TX = 25,
-       STEDMA40_DEV_DST_SXA2_RX_TX = 26,
-       STEDMA40_DEV_DST_SXA3_RX_TX = 27,
-       STEDMA40_DEV_SD_MM2_TX = 28,
-       STEDMA40_DEV_SD_MM0_TX = 29,
-       STEDMA40_DEV_MSP1_TX = 30,
-       /*
-        * This channel is either SlimBus or MSP,
-        * never both at the same time.
-        */
-       STEDMA40_SLIM0_CH0_TX = 31,
-       STEDMA40_DEV_MSP0_TX = 31,
-       STEDMA40_DEV_SD_MM1_TX = 32,
-       STEDMA40_DEV_SPI2_TX = 33,
-       /* Secondary I2C3 channel */
-       STEDMA40_DEV_I2C3_TX2 = 34,
-       STEDMA40_DEV_SPI1_TX = 35,
-       STEDMA40_DEV_USB_OTG_OEP_4_12 = 36,
-       STEDMA40_DEV_USB_OTG_OEP_5_13 = 37,
-       STEDMA40_DEV_USB_OTG_OEP_6_14 = 38,
-       STEDMA40_DEV_USB_OTG_OEP_7_15 = 39,
-       STEDMA40_DEV_SPI3_TX = 40,
-       STEDMA40_DEV_SD_MM3_TX = 41,
-       STEDMA40_DEV_SD_MM4_TX = 42,
-       STEDMA40_DEV_SD_MM5_TX = 43,
-       STEDMA40_DEV_DST_SXA4_RX_TX = 44,
-       STEDMA40_DEV_DST_SXA5_RX_TX = 45,
-       STEDMA40_DEV_DST_SXA6_RX_TX = 46,
-       STEDMA40_DEV_DST_SXA7_RX_TX = 47,
-       STEDMA40_DEV_CAC1_TX = 48,
-       STEDMA40_DEV_CAC1_TX_HAC1_TX = 49,
-       STEDMA40_DEV_HAC1_TX = 50,
-       STEDMA40_MEMCPY_TX_0 = 51,
-       STEDMA40_DEV_SLIM1_CH0_TX_HSI_TX_CH4 = 52,
-       STEDMA40_DEV_SLIM1_CH1_TX_HSI_TX_CH5 = 53,
-       STEDMA40_DEV_SLIM1_CH2_TX_HSI_TX_CH6 = 54,
-       STEDMA40_DEV_SLIM1_CH3_TX_HSI_TX_CH7 = 55,
-       STEDMA40_MEMCPY_TX_1 = 56,
-       STEDMA40_MEMCPY_TX_2 = 57,
-       STEDMA40_MEMCPY_TX_3 = 58,
-       STEDMA40_MEMCPY_TX_4 = 59,
-       STEDMA40_MEMCPY_TX_5 = 60,
-       STEDMA40_DEV_CAC0_TX = 61,
-       STEDMA40_DEV_CAC0_TX_HAC0_TX = 62,
-       STEDMA40_DEV_HAC0_TX = 63,
+       DB8500_DMA_DEV0_SPI0_TX = 0,
+       DB8500_DMA_DEV1_SD_MMC0_TX = 1,
+       DB8500_DMA_DEV2_SD_MMC1_TX = 2,
+       DB8500_DMA_DEV3_SD_MMC2_TX = 3,
+       DB8500_DMA_DEV4_I2C1_TX = 4,
+       DB8500_DMA_DEV5_I2C3_TX = 5,
+       DB8500_DMA_DEV6_I2C2_TX = 6,
+       DB8500_DMA_DEV7_I2C4_TX = 7, /* Only on V1 and later */
+       DB8500_DMA_DEV8_SSP0_TX = 8,
+       DB8500_DMA_DEV9_SSP1_TX = 9,
+       /* 10 is not used*/
+       DB8500_DMA_DEV11_UART2_TX = 11,
+       DB8500_DMA_DEV12_UART1_TX = 12,
+       DB8500_DMA_DEV13_UART0_TX = 13,
+       DB8500_DMA_DEV14_MSP2_TX = 14,
+       DB8500_DMA_DEV15_I2C0_TX = 15,
+       DB8500_DMA_DEV16_USB_OTG_OEP_7_15 = 16,
+       DB8500_DMA_DEV17_USB_OTG_OEP_6_14 = 17,
+       DB8500_DMA_DEV18_USB_OTG_OEP_5_13 = 18,
+       DB8500_DMA_DEV19_USB_OTG_OEP_4_12 = 19,
+       DB8500_DMA_DEV20_SLIM0_CH0_TX_HSI_TX_CH0 = 20,
+       DB8500_DMA_DEV21_SLIM0_CH1_TX_HSI_TX_CH1 = 21,
+       DB8500_DMA_DEV22_SLIM0_CH2_TX_HSI_TX_CH2 = 22,
+       DB8500_DMA_DEV23_SLIM0_CH3_TX_HSI_TX_CH3 = 23,
+       DB8500_DMA_DEV24_DST_SXA0_RX_TX = 24,
+       DB8500_DMA_DEV25_DST_SXA1_RX_TX = 25,
+       DB8500_DMA_DEV26_DST_SXA2_RX_TX = 26,
+       DB8500_DMA_DEV27_DST_SXA3_RX_TX = 27,
+       DB8500_DMA_DEV28_SD_MM2_TX = 28,
+       DB8500_DMA_DEV29_SD_MM0_TX = 29,
+       DB8500_DMA_DEV30_MSP1_TX = 30,
+       DB8500_DMA_DEV31_MSP0_TX_SLIM0_CH0_TX = 31,
+       DB8500_DMA_DEV32_SD_MM1_TX = 32,
+       DB8500_DMA_DEV33_SPI2_TX = 33,
+       DB8500_DMA_DEV34_I2C3_TX2 = 34,
+       DB8500_DMA_DEV35_SPI1_TX = 35,
+       DB8500_DMA_DEV36_USB_OTG_OEP_3_11 = 36,
+       DB8500_DMA_DEV37_USB_OTG_OEP_2_10 = 37,
+       DB8500_DMA_DEV38_USB_OTG_OEP_1_9 = 38,
+       DB8500_DMA_DEV39_USB_OTG_OEP_8 = 39,
+       DB8500_DMA_DEV40_SPI3_TX = 40,
+       DB8500_DMA_DEV41_SD_MM3_TX = 41,
+       DB8500_DMA_DEV42_SD_MM4_TX = 42,
+       DB8500_DMA_DEV43_SD_MM5_TX = 43,
+       DB8500_DMA_DEV44_DST_SXA4_RX_TX = 44,
+       DB8500_DMA_DEV45_DST_SXA5_RX_TX = 45,
+       DB8500_DMA_DEV46_SLIM0_CH8_TX_DST_SXA6_RX_TX = 46,
+       DB8500_DMA_DEV47_SLIM0_CH9_TX_DST_SXA7_RX_TX = 47,
+       DB8500_DMA_DEV48_CAC1_TX  = 48,
+       DB8500_DMA_DEV49_CAC1_TX_HAC1_TX = 49,
+       DB8500_DMA_DEV50_HAC1_TX = 50,
+       DB8500_DMA_MEMCPY_TX_0 = 51,
+       DB8500_DMA_DEV52_SLIM1_CH4_TX_HSI_TX_CH4 = 52,
+       DB8500_DMA_DEV53_SLIM1_CH5_TX_HSI_TX_CH5 = 53,
+       DB8500_DMA_DEV54_SLIM1_CH6_TX_HSI_TX_CH6 = 54,
+       DB8500_DMA_DEV55_SLIM1_CH7_TX_HSI_TX_CH7 = 55,
+       DB8500_DMA_MEMCPY_TX_1 = 56,
+       DB8500_DMA_MEMCPY_TX_2 = 57,
+       DB8500_DMA_MEMCPY_TX_3 = 58,
+       DB8500_DMA_MEMCPY_TX_4 = 59,
+       DB8500_DMA_MEMCPY_TX_5 = 60,
+       DB8500_DMA_DEV61_CAC0_TX = 61,
+       DB8500_DMA_DEV62_CAC0_TX_HAC0_TX = 62,
+       DB8500_DMA_DEV63_HAC0_TX = 63,
 };
 
 #endif
index 6fea7199c626742d4e39afcaadecd5e32ad39e99..eb2cf7dc5c4410e2b92f13a9e508a2b7bdd2bff5 100644 (file)
  *
 */
 
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx,      #0x10000000
-               movne   \rx,      #0xf1000000   @ virtual base
-               orr     \rx, \rx, #0x001F0000
-               orr     \rx, \rx, #0x00001000
+               .macro  addruart, rp, rv
+               mov     \rp,      #0x001F0000
+               orr     \rp, \rp, #0x00001000
+               orr     \rv, \rp, #0xf1000000   @ virtual base
+               orr     \rp, \rp,  #0x10000000  @ physical base
                .endm
 
 #include <asm/hardware/debug-pl01x.S>
index 427e3612db5d1f48202cae06b310c1b9f5f03477..ebd8a2543d3b811f5be94118e1c9c9798f134275 100644 (file)
@@ -18,4 +18,4 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#define VMALLOC_END            (PAGE_OFFSET + 0x18000000)
+#define VMALLOC_END            0xd8000000
index bb8ec7724f79b3cc27a3dc40bf2b6efb5d11736c..aa9730fb13bfa287efcf8c53161da1bd97e6cf20 100644 (file)
@@ -35,8 +35,6 @@
 
 MACHINE_START(VERSATILE_AB, "ARM-Versatile AB")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_io        = 0x101f1000,
-       .io_pg_offst    = ((0xf11f1000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = versatile_map_io,
        .init_irq       = versatile_init_irq,
index 239cd30fc4f5abea904735789b41de7a02d34167..bf469642a3f811c9032dc34358d8f9ef556ffa10 100644 (file)
@@ -108,8 +108,6 @@ static void __init versatile_pb_init(void)
 
 MACHINE_START(VERSATILE_PB, "ARM-Versatile PB")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
-       .phys_io        = 0x101f1000,
-       .io_pg_offst    = ((0xf11f1000) >> 18) & 0xfffc,
        .boot_params    = 0x00000100,
        .map_io         = versatile_map_io,
        .init_irq       = versatile_init_irq,
index 71fb173495209572817a0e15f8794ab8c756b70f..c2e405a9e0256141d62dfad2f359bfa7bac87555 100644 (file)
@@ -245,8 +245,6 @@ static void __init ct_ca9x4_init(void)
 }
 
 MACHINE_START(VEXPRESS, "ARM-Versatile Express CA9x4")
-       .phys_io        = V2M_UART0 & SECTION_MASK,
-       .io_pg_offst    = (__MMIO_P2V(V2M_UART0) >> 18) & 0xfffc,
        .boot_params    = PHYS_OFFSET + 0x00000100,
        .map_io         = ct_ca9x4_map_io,
        .init_irq       = ct_ca9x4_init_irq,
index 5167e2aceeba9f8a070db5c8b91b3c0936f4f59f..050d65e02a42a9dc4e6923bde6eb474a9a7da41a 100644 (file)
 
 #define DEBUG_LL_UART_OFFSET   0x00009000
 
-               .macro  addruart,rx,tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               moveq   \rx,      #0x10000000
-               movne   \rx,      #0xf8000000   @ virtual base
-               orr     \rx, \rx, #DEBUG_LL_UART_OFFSET
+               .macro  addruart,rp,rv
+               mov     \rp, #DEBUG_LL_UART_OFFSET
+               orr     \rv, \rp, #0xf8000000   @ virtual base
+               orr     \rp, \rp, #0x10000000   @ physical base
                .endm
 
 #include <asm/hardware/debug-pl01x.S>
index 72a9621ed087369eb265de17535e3d34d3693326..5a6da4fd247e86268c660d82ff8c4a4325021ffa 100644 (file)
@@ -2,14 +2,7 @@
 #define __MACH_SMP_H
 
 #include <asm/hardware/gic.h>
-
-#define hard_smp_processor_id()                                \
-       ({                                              \
-               unsigned int cpunum;                    \
-               __asm__("mrc p15, 0, %0, c0, c0, 5"     \
-                       : "=r" (cpunum));               \
-               cpunum &= 0x0F;                         \
-       })
+#include <asm/smp_mpidr.h>
 
 /*
  * We use IRQ1 as the IPI
index ec05bda946f315d4bf5ebb5ae8d6d616f4a4d60d..30fccde94fb89f8e29939b67261695db3bc9da3b 100644 (file)
@@ -34,8 +34,6 @@ static void __init nuc910evb_init(void)
 
 MACHINE_START(W90P910EVB, "W90P910EVB")
        /* Maintainer: Wan ZongShun */
-       .phys_io        = W90X900_PA_UART,
-       .io_pg_offst    = (((u32)W90X900_VA_UART) >> 18) & 0xfffc,
        .boot_params    = 0,
        .map_io         = nuc910evb_map_io,
        .init_irq       = nuc900_init_irq,
index 04d295f89eb049f86ed0b8c6ba8386c5d0c0c09e..590c99b96dc18170a3df165c45e66b60338e5626 100644 (file)
@@ -37,8 +37,6 @@ static void __init nuc950evb_init(void)
 
 MACHINE_START(W90P950EVB, "W90P950EVB")
        /* Maintainer: Wan ZongShun */
-       .phys_io        = W90X900_PA_UART,
-       .io_pg_offst    = (((u32)W90X900_VA_UART) >> 18) & 0xfffc,
        .boot_params    = 0,
        .map_io         = nuc950evb_map_io,
        .init_irq       = nuc900_init_irq,
index e3a46f19f2bc593e90af6f443033dab59612f1de..e09c645d61b6a1ea06db9d79f25e1d654aee91db 100644 (file)
@@ -34,8 +34,6 @@ static void __init nuc960evb_init(void)
 
 MACHINE_START(W90N960EVB, "W90N960EVB")
        /* Maintainer: Wan ZongShun */
-       .phys_io        = W90X900_PA_UART,
-       .io_pg_offst    = (((u32)W90X900_VA_UART) >> 18) & 0xfffc,
        .boot_params    = 0,
        .map_io         = nuc960evb_map_io,
        .init_irq       = nuc900_init_irq,
index 86aa689ef1aa2f6b53cf84a717427df11a25ce1e..99fa688dfadd305113670aa48ea185a9899f8e5b 100644 (file)
 #define D_CACHE_LINE_SIZE      32
 #define BTB_FLUSH_SIZE         8
 
-#ifdef CONFIG_ARM_ERRATA_411920
 /*
- * Invalidate the entire I cache (this code is a workaround for the ARM1136
- * erratum 411920 - Invalidate Instruction Cache operation can fail. This
- * erratum is present in 1136, 1156 and 1176. It does not affect the MPCore.
+ *     v6_flush_icache_all()
+ *
+ *     Flush the whole I-cache.
  *
- * Registers:
- *   r0 - set to 0
- *   r1 - corrupted
+ *     ARM1136 erratum 411920 - Invalidate Instruction Cache operation can fail.
+ *     This erratum is present in 1136, 1156 and 1176. It does not affect the
+ *     MPCore.
+ *
+ *     Registers:
+ *     r0 - set to 0
+ *     r1 - corrupted
  */
-ENTRY(v6_icache_inval_all)
+ENTRY(v6_flush_icache_all)
        mov     r0, #0
+#ifdef CONFIG_ARM_ERRATA_411920
        mrs     r1, cpsr
        cpsid   ifa                             @ disable interrupts
        mcr     p15, 0, r0, c7, c5, 0           @ invalidate entire I-cache
@@ -43,8 +47,11 @@ ENTRY(v6_icache_inval_all)
        .rept   11                              @ ARM Ltd recommends at least
        nop                                     @ 11 NOPs
        .endr
-       mov     pc, lr
+#else
+       mcr     p15, 0, r0, c7, c5, 0           @ invalidate I-cache
 #endif
+       mov     pc, lr
+ENDPROC(v6_flush_icache_all)
 
 /*
  *     v6_flush_cache_all()
@@ -60,7 +67,7 @@ ENTRY(v6_flush_kern_cache_all)
 #ifndef CONFIG_ARM_ERRATA_411920
        mcr     p15, 0, r0, c7, c5, 0           @ I+BTB cache invalidate
 #else
-       b       v6_icache_inval_all
+       b       v6_flush_icache_all
 #endif
 #else
        mcr     p15, 0, r0, c7, c15, 0          @ Cache clean+invalidate
@@ -138,7 +145,7 @@ ENTRY(v6_coherent_user_range)
 #ifndef CONFIG_ARM_ERRATA_411920
        mcr     p15, 0, r0, c7, c5, 0           @ I+BTB cache invalidate
 #else
-       b       v6_icache_inval_all
+       b       v6_flush_icache_all
 #endif
 #else
        mcr     p15, 0, r0, c7, c5, 6           @ invalidate BTB
@@ -312,6 +319,7 @@ ENDPROC(v6_dma_unmap_area)
 
        .type   v6_cache_fns, #object
 ENTRY(v6_cache_fns)
+       .long   v6_flush_icache_all
        .long   v6_flush_kern_cache_all
        .long   v6_flush_user_cache_all
        .long   v6_flush_user_cache_range
index 37c8157e116e8aa54dc8cdf4ffddf1e4f8bda0f3..a3ebf7a4f49b2b404da115a58e7fdf6923792625 100644 (file)
 
 #include "proc-macros.S"
 
+/*
+ *     v7_flush_icache_all()
+ *
+ *     Flush the whole I-cache.
+ *
+ *     Registers:
+ *     r0 - set to 0
+ */
+ENTRY(v7_flush_icache_all)
+       mov     r0, #0
+       ALT_SMP(mcr     p15, 0, r0, c7, c1, 0)          @ invalidate I-cache inner shareable
+       ALT_UP(mcr      p15, 0, r0, c7, c5, 0)          @ I+BTB cache invalidate
+       mov     pc, lr
+ENDPROC(v7_flush_icache_all)
+
 /*
  *     v7_flush_dcache_all()
  *
@@ -91,11 +106,8 @@ ENTRY(v7_flush_kern_cache_all)
  THUMB(        stmfd   sp!, {r4-r7, r9-r11, lr}        )
        bl      v7_flush_dcache_all
        mov     r0, #0
-#ifdef CONFIG_SMP
-       mcr     p15, 0, r0, c7, c1, 0           @ invalidate I-cache inner shareable
-#else
-       mcr     p15, 0, r0, c7, c5, 0           @ I+BTB cache invalidate
-#endif
+       ALT_SMP(mcr     p15, 0, r0, c7, c1, 0)  @ invalidate I-cache inner shareable
+       ALT_UP(mcr      p15, 0, r0, c7, c5, 0)  @ I+BTB cache invalidate
  ARM(  ldmfd   sp!, {r4-r5, r7, r9-r11, lr}    )
  THUMB(        ldmfd   sp!, {r4-r7, r9-r11, lr}        )
        mov     pc, lr
@@ -171,11 +183,8 @@ ENTRY(v7_coherent_user_range)
        cmp     r0, r1
        blo     1b
        mov     r0, #0
-#ifdef CONFIG_SMP
-       mcr     p15, 0, r0, c7, c1, 6           @ invalidate BTB Inner Shareable
-#else
-       mcr     p15, 0, r0, c7, c5, 6           @ invalidate BTB
-#endif
+       ALT_SMP(mcr     p15, 0, r0, c7, c1, 6)  @ invalidate BTB Inner Shareable
+       ALT_UP(mcr      p15, 0, r0, c7, c5, 6)  @ invalidate BTB
        dsb
        isb
        mov     pc, lr
@@ -309,6 +318,7 @@ ENDPROC(v7_dma_unmap_area)
 
        .type   v7_cache_fns, #object
 ENTRY(v7_cache_fns)
+       .long   v7_flush_icache_all
        .long   v7_flush_kern_cache_all
        .long   v7_flush_user_cache_all
        .long   v7_flush_user_cache_range
index 598c51ad50717f28d00202a9f8fd185b6a58b6a8..b8061519ce776b7dbc049815c4fbff21daa073ef 100644 (file)
@@ -73,7 +73,7 @@ void v4_mc_copy_user_highpage(struct page *to, struct page *from,
 {
        void *kto = kmap_atomic(to, KM_USER1);
 
-       if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+       if (!test_and_set_bit(PG_dcache_clean, &from->flags))
                __flush_dcache_page(page_mapping(from), from);
 
        spin_lock(&minicache_lock);
index f55fa1044f72b829d0c307683f9ab12d768a4893..bdba6c65c901a1c682f1aaf0fce3875ad8fa448b 100644 (file)
@@ -79,7 +79,7 @@ static void v6_copy_user_highpage_aliasing(struct page *to,
        unsigned int offset = CACHE_COLOUR(vaddr);
        unsigned long kfrom, kto;
 
-       if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+       if (!test_and_set_bit(PG_dcache_clean, &from->flags))
                __flush_dcache_page(page_mapping(from), from);
 
        /* FIXME: not highmem safe */
index 9920c0ae2096cc2c6b8c9e535dc63ab5d400afb0..649bbcd325bffb27b263d0e43a484cc279c12a05 100644 (file)
@@ -95,7 +95,7 @@ void xscale_mc_copy_user_highpage(struct page *to, struct page *from,
 {
        void *kto = kmap_atomic(to, KM_USER1);
 
-       if (test_and_clear_bit(PG_dcache_dirty, &from->flags))
+       if (!test_and_set_bit(PG_dcache_clean, &from->flags))
                __flush_dcache_page(page_mapping(from), from);
 
        spin_lock(&minicache_lock);
index 4bc43e535d3baadc657df9af504078ff1ae00570..e4dd0646e85978b89a164c40100d0561bd1005f7 100644 (file)
@@ -523,6 +523,12 @@ void ___dma_page_dev_to_cpu(struct page *page, unsigned long off,
                outer_inv_range(paddr, paddr + size);
 
        dma_cache_maint_page(page, off, size, dir, dmac_unmap_area);
+
+       /*
+        * Mark the D-cache clean for this page to avoid extra flushing.
+        */
+       if (dir != DMA_TO_DEVICE && off == 0 && size >= PAGE_SIZE)
+               set_bit(PG_dcache_clean, &page->flags);
 }
 EXPORT_SYMBOL(___dma_page_dev_to_cpu);
 
index 9b906dec1ca1abc0ec308472dc39a7684c6c3b01..8440d952ba6dd1266628678f016bdf5f41a3002a 100644 (file)
@@ -28,6 +28,7 @@
 
 static unsigned long shared_pte_mask = L_PTE_MT_BUFFERABLE;
 
+#if __LINUX_ARM_ARCH__ < 6
 /*
  * We take the easy way out of this problem - we make the
  * PTE uncacheable.  However, we leave the write buffer on.
@@ -141,7 +142,7 @@ make_coherent(struct address_space *mapping, struct vm_area_struct *vma,
  * a page table, or changing an existing PTE.  Basically, there are two
  * things that we need to take care of:
  *
- *  1. If PG_dcache_dirty is set for the page, we need to ensure
+ *  1. If PG_dcache_clean is not set for the page, we need to ensure
  *     that any cache entries for the kernels virtual memory
  *     range are written back to the page.
  *  2. If we have multiple shared mappings of the same space in
@@ -168,10 +169,8 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
                return;
 
        mapping = page_mapping(page);
-#ifndef CONFIG_SMP
-       if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
+       if (!test_and_set_bit(PG_dcache_clean, &page->flags))
                __flush_dcache_page(mapping, page);
-#endif
        if (mapping) {
                if (cache_is_vivt())
                        make_coherent(mapping, vma, addr, ptep, pfn);
@@ -179,6 +178,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr,
                        __flush_icache_all();
        }
 }
+#endif /* __LINUX_ARM_ARCH__ < 6 */
 
 /*
  * Check whether the write buffer has physical address aliasing
index 23b0b03af5ea84b8a01e10c59a97091d92f4618b..1e21e125fe3a833fadcc932c8fcf01177d7ba8f2 100644 (file)
@@ -581,6 +581,19 @@ static struct fsr_info ifsr_info[] = {
        { do_bad,               SIGBUS,  0,             "unknown 31"                       },
 };
 
+void __init
+hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
+                int sig, int code, const char *name)
+{
+       if (nr < 0 || nr >= ARRAY_SIZE(ifsr_info))
+               BUG();
+
+       ifsr_info[nr].fn   = fn;
+       ifsr_info[nr].sig  = sig;
+       ifsr_info[nr].code = code;
+       ifsr_info[nr].name = name;
+}
+
 asmlinkage void __exception
 do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
 {
index c6844cb9b508dde69c49af40bb0d2956b126b8d3..391ffae750986404df8658d53e93fdc69b970ba4 100644 (file)
@@ -17,6 +17,7 @@
 #include <asm/smp_plat.h>
 #include <asm/system.h>
 #include <asm/tlbflush.h>
+#include <asm/smp_plat.h>
 
 #include "mm.h"
 
@@ -39,6 +40,18 @@ static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
            : "cc");
 }
 
+static void flush_icache_alias(unsigned long pfn, unsigned long vaddr, unsigned long len)
+{
+       unsigned long colour = CACHE_COLOUR(vaddr);
+       unsigned long offset = vaddr & (PAGE_SIZE - 1);
+       unsigned long to;
+
+       set_pte_ext(TOP_PTE(ALIAS_FLUSH_START) + colour, pfn_pte(pfn, PAGE_KERNEL), 0);
+       to = ALIAS_FLUSH_START + (colour << PAGE_SHIFT) + offset;
+       flush_tlb_kernel_page(to);
+       flush_icache_range(to, to + len);
+}
+
 void flush_cache_mm(struct mm_struct *mm)
 {
        if (cache_is_vivt()) {
@@ -89,16 +102,16 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long user_addr, unsig
        if (vma->vm_flags & VM_EXEC && icache_is_vivt_asid_tagged())
                __flush_icache_all();
 }
+
 #else
-#define flush_pfn_alias(pfn,vaddr)     do { } while (0)
+#define flush_pfn_alias(pfn,vaddr)             do { } while (0)
+#define flush_icache_alias(pfn,vaddr,len)      do { } while (0)
 #endif
 
-#ifdef CONFIG_SMP
 static void flush_ptrace_access_other(void *args)
 {
        __flush_icache_all();
 }
-#endif
 
 static
 void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
@@ -118,15 +131,16 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
                return;
        }
 
-       /* VIPT non-aliasing cache */
+       /* VIPT non-aliasing D-cache */
        if (vma->vm_flags & VM_EXEC) {
                unsigned long addr = (unsigned long)kaddr;
-               __cpuc_coherent_kern_range(addr, addr + len);
-#ifdef CONFIG_SMP
+               if (icache_is_vipt_aliasing())
+                       flush_icache_alias(page_to_pfn(page), uaddr, len);
+               else
+                       __cpuc_coherent_kern_range(addr, addr + len);
                if (cache_ops_need_broadcast())
                        smp_call_function(flush_ptrace_access_other,
                                          NULL, 1);
-#endif
        }
 }
 
@@ -215,6 +229,36 @@ static void __flush_dcache_aliases(struct address_space *mapping, struct page *p
        flush_dcache_mmap_unlock(mapping);
 }
 
+#if __LINUX_ARM_ARCH__ >= 6
+void __sync_icache_dcache(pte_t pteval)
+{
+       unsigned long pfn;
+       struct page *page;
+       struct address_space *mapping;
+
+       if (!pte_present_user(pteval))
+               return;
+       if (cache_is_vipt_nonaliasing() && !pte_exec(pteval))
+               /* only flush non-aliasing VIPT caches for exec mappings */
+               return;
+       pfn = pte_pfn(pteval);
+       if (!pfn_valid(pfn))
+               return;
+
+       page = pfn_to_page(pfn);
+       if (cache_is_vipt_aliasing())
+               mapping = page_mapping(page);
+       else
+               mapping = NULL;
+
+       if (!test_and_set_bit(PG_dcache_clean, &page->flags))
+               __flush_dcache_page(mapping, page);
+       /* pte_exec() already checked above for non-aliasing VIPT cache */
+       if (cache_is_vipt_nonaliasing() || pte_exec(pteval))
+               __flush_icache_all();
+}
+#endif
+
 /*
  * Ensure cache coherency between kernel mapping and userspace mapping
  * of this page.
@@ -246,17 +290,16 @@ void flush_dcache_page(struct page *page)
 
        mapping = page_mapping(page);
 
-#ifndef CONFIG_SMP
-       if (!PageHighMem(page) && mapping && !mapping_mapped(mapping))
-               set_bit(PG_dcache_dirty, &page->flags);
-       else
-#endif
-       {
+       if (!cache_ops_need_broadcast() &&
+           mapping && !mapping_mapped(mapping))
+               clear_bit(PG_dcache_clean, &page->flags);
+       else {
                __flush_dcache_page(mapping, page);
                if (mapping && cache_is_vivt())
                        __flush_dcache_aliases(mapping, page);
                else if (mapping)
                        __flush_icache_all();
+               set_bit(PG_dcache_clean, &page->flags);
        }
 }
 EXPORT_SYMBOL(flush_dcache_page);
index 7185b00650fe419d0fa0f43b3e79e2e0d90cf6e6..7fd9b5eb177fa02c56acd3444da0e3752e702913 100644 (file)
@@ -150,6 +150,7 @@ static void __init find_limits(struct meminfo *mi,
 static void __init arm_bootmem_init(struct meminfo *mi,
        unsigned long start_pfn, unsigned long end_pfn)
 {
+       struct memblock_region *reg;
        unsigned int boot_pages;
        phys_addr_t bitmap;
        pg_data_t *pgdat;
@@ -180,13 +181,13 @@ static void __init arm_bootmem_init(struct meminfo *mi,
        /*
         * Reserve the memblock reserved regions in bootmem.
         */
-       for (i = 0; i < memblock.reserved.cnt; i++) {
-               phys_addr_t start = memblock_start_pfn(&memblock.reserved, i);
-               if (start >= start_pfn &&
-                   memblock_end_pfn(&memblock.reserved, i) <= end_pfn)
+       for_each_memblock(reserved, reg) {
+               phys_addr_t start = memblock_region_reserved_base_pfn(reg);
+               phys_addr_t end = memblock_region_reserved_end_pfn(reg);
+               if (start >= start_pfn && end <= end_pfn)
                        reserve_bootmem_node(pgdat, __pfn_to_phys(start),
-                               memblock_size_bytes(&memblock.reserved, i),
-                               BOOTMEM_DEFAULT);
+                                            (end - start) << PAGE_SHIFT,
+                                            BOOTMEM_DEFAULT);
        }
 }
 
@@ -237,20 +238,7 @@ static void __init arm_bootmem_free(struct meminfo *mi, unsigned long min,
 #ifndef CONFIG_SPARSEMEM
 int pfn_valid(unsigned long pfn)
 {
-       struct memblock_region *mem = &memblock.memory;
-       unsigned int left = 0, right = mem->cnt;
-
-       do {
-               unsigned int mid = (right + left) / 2;
-
-               if (pfn < memblock_start_pfn(mem, mid))
-                       right = mid;
-               else if (pfn >= memblock_end_pfn(mem, mid))
-                       left = mid + 1;
-               else
-                       return 1;
-       } while (left < right);
-       return 0;
+       return memblock_is_memory(pfn << PAGE_SHIFT);
 }
 EXPORT_SYMBOL(pfn_valid);
 
@@ -260,10 +248,11 @@ static void arm_memory_present(void)
 #else
 static void arm_memory_present(void)
 {
-       int i;
-       for (i = 0; i < memblock.memory.cnt; i++)
-               memory_present(0, memblock_start_pfn(&memblock.memory, i),
-                                 memblock_end_pfn(&memblock.memory, i));
+       struct memblock_region *reg;
+
+       for_each_memblock(memory, reg)
+               memory_present(0, memblock_region_memory_base_pfn(reg),
+                              memblock_region_memory_end_pfn(reg));
 }
 #endif
 
@@ -277,7 +266,7 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
 
        /* Register the kernel text, kernel data and initrd with memblock. */
 #ifdef CONFIG_XIP_KERNEL
-       memblock_reserve(__pa(_data), _end - _data);
+       memblock_reserve(__pa(_sdata), _end - _sdata);
 #else
        memblock_reserve(__pa(_stext), _end - _stext);
 #endif
@@ -545,7 +534,7 @@ void __init mem_init(void)
 
                        MLK_ROUNDUP(__init_begin, __init_end),
                        MLK_ROUNDUP(_text, _etext),
-                       MLK_ROUNDUP(_data, _edata));
+                       MLK_ROUNDUP(_sdata, _edata));
 
 #undef MLK
 #undef MLM
index 4f5b39687df541a417d4c3a9ac888fc53a31b999..b0a98305055c53e54cc9be3edda6c82afb6275b8 100644 (file)
@@ -144,3 +144,25 @@ int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
 {
        return !(pfn + (size >> PAGE_SHIFT) > 0x00100000);
 }
+
+#ifdef CONFIG_STRICT_DEVMEM
+
+#include <linux/ioport.h>
+
+/*
+ * devmem_is_allowed() checks to see if /dev/mem access to a certain
+ * address is valid. The argument is a physical page number.
+ * We mimic x86 here by disallowing access to system RAM as well as
+ * device-exclusive MMIO regions. This effectively disable read()/write()
+ * on /dev/mem.
+ */
+int devmem_is_allowed(unsigned long pfn)
+{
+       if (iomem_is_exclusive(pfn << PAGE_SHIFT))
+               return 0;
+       if (!page_is_ram(pfn))
+               return 1;
+       return 0;
+}
+
+#endif
index e8ed9dc461fe39631efeeb4746b80854e13415c6..c32f731d56d3db4ad51453718c5d1c43f6053f2e 100644 (file)
@@ -310,9 +310,8 @@ static void __init build_mem_type_table(void)
                        cachepolicy = CPOLICY_WRITEBACK;
                ecc_mask = 0;
        }
-#ifdef CONFIG_SMP
-       cachepolicy = CPOLICY_WRITEALLOC;
-#endif
+       if (is_smp())
+               cachepolicy = CPOLICY_WRITEALLOC;
 
        /*
         * Strip out features not present on earlier architectures.
@@ -406,13 +405,11 @@ static void __init build_mem_type_table(void)
        cp = &cache_policies[cachepolicy];
        vecs_pgprot = kern_pgprot = user_pgprot = cp->pte;
 
-#ifndef CONFIG_SMP
        /*
         * Only use write-through for non-SMP systems
         */
-       if (cpu_arch >= CPU_ARCH_ARMv5 && cachepolicy > CPOLICY_WRITETHROUGH)
+       if (!is_smp() && cpu_arch >= CPU_ARCH_ARMv5 && cachepolicy > CPOLICY_WRITETHROUGH)
                vecs_pgprot = cache_policies[CPOLICY_WRITETHROUGH].pte;
-#endif
 
        /*
         * Enable CPU-specific coherency if supported.
@@ -436,22 +433,23 @@ static void __init build_mem_type_table(void)
                mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 
-#ifdef CONFIG_SMP
-               /*
-                * Mark memory with the "shared" attribute for SMP systems
-                */
-               user_pgprot |= L_PTE_SHARED;
-               kern_pgprot |= L_PTE_SHARED;
-               vecs_pgprot |= L_PTE_SHARED;
-               mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_S;
-               mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_SHARED;
-               mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_S;
-               mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED;
-               mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
-               mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED;
-               mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S;
-               mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED;
-#endif
+               if (is_smp()) {
+                       /*
+                        * Mark memory with the "shared" attribute
+                        * for SMP systems
+                        */
+                       user_pgprot |= L_PTE_SHARED;
+                       kern_pgprot |= L_PTE_SHARED;
+                       vecs_pgprot |= L_PTE_SHARED;
+                       mem_types[MT_DEVICE_WC].prot_sect |= PMD_SECT_S;
+                       mem_types[MT_DEVICE_WC].prot_pte |= L_PTE_SHARED;
+                       mem_types[MT_DEVICE_CACHED].prot_sect |= PMD_SECT_S;
+                       mem_types[MT_DEVICE_CACHED].prot_pte |= L_PTE_SHARED;
+                       mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
+                       mem_types[MT_MEMORY].prot_pte |= L_PTE_SHARED;
+                       mem_types[MT_MEMORY_NONCACHED].prot_sect |= PMD_SECT_S;
+                       mem_types[MT_MEMORY_NONCACHED].prot_pte |= L_PTE_SHARED;
+               }
        }
 
        /*
@@ -829,8 +827,7 @@ static void __init sanity_check_meminfo(void)
                         * rather difficult.
                         */
                        reason = "with VIPT aliasing cache";
-#ifdef CONFIG_SMP
-               } else if (tlb_ops_need_broadcast()) {
+               } else if (is_smp() && tlb_ops_need_broadcast()) {
                        /*
                         * kmap_high needs to occasionally flush TLB entries,
                         * however, if the TLB entries need to be broadcast
@@ -840,7 +837,6 @@ static void __init sanity_check_meminfo(void)
                         *   (must not be called with irqs off)
                         */
                        reason = "without hardware TLB ops broadcasting";
-#endif
                }
                if (reason) {
                        printk(KERN_CRIT "HIGHMEM is not supported %s, ignoring high memory\n",
index 203a4e944d9e43c53051725c084f542cceb8b7a3..a6f5f8475b96c6400a3aa26e03875a329ff771b1 100644 (file)
@@ -430,7 +430,7 @@ ENTRY(cpu_arm1020_set_pte_ext)
 #endif /* CONFIG_MMU */
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __arm1020_setup, #function
 __arm1020_setup:
index 1a511e765909957d81b463c17f0000b8893d3770..afc06b9c31332bf7dc25222855d61dcb391bc42d 100644 (file)
@@ -412,7 +412,7 @@ ENTRY(cpu_arm1020e_set_pte_ext)
 #endif /* CONFIG_MMU */
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __arm1020e_setup, #function
 __arm1020e_setup:
index 1ffa4eb9c34f7d7d2f1b5ad5e3825daf67d14156..8915e0ba3fe53e1225bbb422b19f22c8a0d4c085 100644 (file)
@@ -394,7 +394,7 @@ ENTRY(cpu_arm1022_set_pte_ext)
 #endif /* CONFIG_MMU */
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __arm1022_setup, #function
 __arm1022_setup:
index 5697c34b95b0cdb38c31aad752c172b6990b5567..ff446c5d476f029aefb8a57da2fd4a4987e890e3 100644 (file)
@@ -384,7 +384,7 @@ ENTRY(cpu_arm1026_set_pte_ext)
        mov     pc, lr
 
 
-       __INIT
+       __CPUINIT
 
        .type   __arm1026_setup, #function
 __arm1026_setup:
index 64e0b327c7c5f504ec00757dcfd832d1fe56ac9e..6a7be1863eddaf317640fc41b25ecfdfc1b089f1 100644 (file)
@@ -238,7 +238,7 @@ ENTRY(cpu_arm7_reset)
                mcr     p15, 0, r1, c1, c0, 0           @ turn off MMU etc
                mov     pc, r0
 
-               __INIT
+               __CPUINIT
 
                .type   __arm6_setup, #function
 __arm6_setup:  mov     r0, #0
index 9d96824134fc4db4b0cd24f9df65c405717b4341..c285395f44b24e5f5dfb7bc92be1e7f4bd3935be 100644 (file)
@@ -113,7 +113,7 @@ ENTRY(cpu_arm720_reset)
                mcr     p15, 0, ip, c1, c0, 0           @ ctrl register
                mov     pc, r0
 
-       __INIT
+       __CPUINIT
 
        .type   __arm710_setup, #function
 __arm710_setup:
index 6c1a9ab059aedb2f48e0d2bff8b823b3bb306dab..38b27dcba7275bd1038c62990bd49a9d35908f70 100644 (file)
@@ -55,7 +55,7 @@ ENTRY(cpu_arm740_reset)
        mcr     p15, 0, ip, c1, c0, 0           @ ctrl register
        mov     pc, r0
 
-       __INIT
+       __CPUINIT
 
        .type   __arm740_setup, #function
 __arm740_setup:
index 6a850dbba22e5ff7be9aae70476489feeaaeef18..0c9786de20af3575100f21b3e3de6d1e006e4f71 100644 (file)
@@ -46,7 +46,7 @@ ENTRY(cpu_arm7tdmi_proc_fin)
 ENTRY(cpu_arm7tdmi_reset)
                mov     pc, r0
 
-               __INIT
+               __CPUINIT
 
                .type   __arm7tdmi_setup, #function
 __arm7tdmi_setup:
index 86f80aa56216b8ecf3159c090a83eeb2da372820..fecf570939f39553dcc4959a6a963a06827aadc2 100644 (file)
@@ -375,7 +375,7 @@ ENTRY(cpu_arm920_set_pte_ext)
 #endif
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __arm920_setup, #function
 __arm920_setup:
index f76ce9b62883be61a1abe9baf67ae1a4ca4d8324..e3cbf87c9480c97e8b65086638ef6b6b72e3217c 100644 (file)
@@ -379,7 +379,7 @@ ENTRY(cpu_arm922_set_pte_ext)
 #endif /* CONFIG_MMU */
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __arm922_setup, #function
 __arm922_setup:
index 657bd3f7c153bf033f704636a323339129bb5d11..572424c867b5e8560401e7cf40d895a77f140fbe 100644 (file)
@@ -428,7 +428,7 @@ ENTRY(cpu_arm925_set_pte_ext)
 #endif /* CONFIG_MMU */
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __arm925_setup, #function
 __arm925_setup:
index 73f1f3c689108fcade13d8dbb26e057105247645..63d168b4ebe671316ff3add437c26da418dd596f 100644 (file)
@@ -389,7 +389,7 @@ ENTRY(cpu_arm926_set_pte_ext)
 #endif
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __arm926_setup, #function
 __arm926_setup:
index fffb061a45a558ee8dc5883dcba4a0e64ef53311..f6a62822418e3573d8af5629f7f088f7ce24652d 100644 (file)
@@ -264,7 +264,7 @@ ENTRY(arm940_cache_fns)
        .long   arm940_dma_unmap_area
        .long   arm940_dma_flush_range
 
-       __INIT
+       __CPUINIT
 
        .type   __arm940_setup, #function
 __arm940_setup:
index 249a6053760a357baa0dca13c3d67bf49ebf975e..ea2e7f2eb95b1e6f86f4770c2e1ebca292f11f81 100644 (file)
@@ -317,7 +317,7 @@ ENTRY(cpu_arm946_dcache_clean_area)
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __arm946_setup, #function
 __arm946_setup:
index db475667fac2c95df3ab30fdabda084eab94c3f3..db67e3134d7a50447268e815908e443206d0a7a4 100644 (file)
@@ -46,7 +46,7 @@ ENTRY(cpu_arm9tdmi_proc_fin)
 ENTRY(cpu_arm9tdmi_reset)
                mov     pc, r0
 
-               __INIT
+               __CPUINIT
 
                .type   __arm9tdmi_setup, #function
 __arm9tdmi_setup:
index 7803fdf7002933da8e63a3383f9da818ecea724c..7c9ad621f0e65ab031be819b303528341f7d2356 100644 (file)
@@ -134,7 +134,7 @@ ENTRY(cpu_fa526_set_pte_ext)
 #endif
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __fa526_setup, #function
 __fa526_setup:
index b304d0104a4ef9c240191e42b7e08460706408b8..578da69200cfc2694a2359c18ead388dfd4a7353 100644 (file)
@@ -494,7 +494,7 @@ ENTRY(cpu_feroceon_set_pte_ext)
 #endif
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __feroceon_setup, #function
 __feroceon_setup:
index 5f6892fcc1671f28070f175bc6eeda03bbe614c5..4458ee6aa7133343764792b79c9f87f0f7b67ff2 100644 (file)
@@ -338,7 +338,7 @@ ENTRY(cpu_mohawk_set_pte_ext)
        mcr     p15, 0, r0, c7, c10, 4          @ drain WB
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __mohawk_setup, #function
 __mohawk_setup:
index a201eb04b5e1a6327d1a5375c00b669ee7fc439c..5aa8d59c2e8546675d132fc48306c89b2d9380da 100644 (file)
@@ -156,7 +156,7 @@ ENTRY(cpu_sa110_set_pte_ext)
 #endif
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __sa110_setup, #function
 __sa110_setup:
index 7ddc4805bf97a6fe722f54b3a769974bfaa42a1b..2ac4e6f1071378d3f27482483a0e041d540ec648 100644 (file)
@@ -169,7 +169,7 @@ ENTRY(cpu_sa1100_set_pte_ext)
 #endif
        mov     pc, lr
 
-       __INIT
+       __CPUINIT
 
        .type   __sa1100_setup, #function
 __sa1100_setup:
index 22aac85151966d3058ace5cdb24eb4a608605e16..59a7e1ffe7bc02c3fc180c464506ce273f5e9590 100644 (file)
 #define TTB_RGN_WT     (2 << 3)
 #define TTB_RGN_WB     (3 << 3)
 
-#ifndef CONFIG_SMP
-#define TTB_FLAGS      TTB_RGN_WBWA
-#define PMD_FLAGS      PMD_SECT_WB
-#else
-#define TTB_FLAGS      TTB_RGN_WBWA|TTB_S
-#define PMD_FLAGS      PMD_SECT_WBWA|PMD_SECT_S
-#endif
+#define TTB_FLAGS_UP   TTB_RGN_WBWA
+#define PMD_FLAGS_UP   PMD_SECT_WB
+#define TTB_FLAGS_SMP  TTB_RGN_WBWA|TTB_S
+#define PMD_FLAGS_SMP  PMD_SECT_WBWA|PMD_SECT_S
 
 ENTRY(cpu_v6_proc_init)
        mov     pc, lr
@@ -97,7 +94,8 @@ ENTRY(cpu_v6_switch_mm)
 #ifdef CONFIG_MMU
        mov     r2, #0
        ldr     r1, [r1, #MM_CONTEXT_ID]        @ get mm->context.id
-       orr     r0, r0, #TTB_FLAGS
+       ALT_SMP(orr     r0, r0, #TTB_FLAGS_SMP)
+       ALT_UP(orr      r0, r0, #TTB_FLAGS_UP)
        mcr     p15, 0, r2, c7, c5, 6           @ flush BTAC/BTB
        mcr     p15, 0, r2, c7, c10, 4          @ drain write buffer
        mcr     p15, 0, r0, c2, c0, 0           @ set TTB 0
@@ -137,7 +135,7 @@ cpu_pj4_name:
 
        .align
 
-       __INIT
+       __CPUINIT
 
 /*
  *     __v6_setup
@@ -156,9 +154,11 @@ cpu_pj4_name:
  */
 __v6_setup:
 #ifdef CONFIG_SMP
-       mrc     p15, 0, r0, c1, c0, 1           @ Enable SMP/nAMP mode
+       ALT_SMP(mrc     p15, 0, r0, c1, c0, 1)  @ Enable SMP/nAMP mode
+       ALT_UP(nop)
        orr     r0, r0, #0x20
-       mcr     p15, 0, r0, c1, c0, 1
+       ALT_SMP(mcr     p15, 0, r0, c1, c0, 1)
+       ALT_UP(nop)
 #endif
 
        mov     r0, #0
@@ -169,7 +169,8 @@ __v6_setup:
 #ifdef CONFIG_MMU
        mcr     p15, 0, r0, c8, c7, 0           @ invalidate I + D TLBs
        mcr     p15, 0, r0, c2, c0, 2           @ TTB control register
-       orr     r4, r4, #TTB_FLAGS
+       ALT_SMP(orr     r4, r4, #TTB_FLAGS_SMP)
+       ALT_UP(orr      r4, r4, #TTB_FLAGS_UP)
        mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
 #endif /* CONFIG_MMU */
        adr     r5, v6_crval
@@ -192,6 +193,8 @@ __v6_setup:
 v6_crval:
        crval   clear=0x01e0fb7f, mmuset=0x00c0387d, ucset=0x00c0187c
 
+       __INITDATA
+
        .type   v6_processor_functions, #object
 ENTRY(v6_processor_functions)
        .word   v6_early_abort
@@ -205,6 +208,8 @@ ENTRY(v6_processor_functions)
        .word   cpu_v6_set_pte_ext
        .size   v6_processor_functions, . - v6_processor_functions
 
+       .section ".rodata"
+
        .type   cpu_arch_name, #object
 cpu_arch_name:
        .asciz  "armv6"
@@ -225,10 +230,16 @@ cpu_elf_name:
 __v6_proc_info:
        .long   0x0007b000
        .long   0x0007f000
-       .long   PMD_TYPE_SECT | \
+       ALT_SMP(.long \
+               PMD_TYPE_SECT | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ | \
-               PMD_FLAGS
+               PMD_FLAGS_SMP)
+       ALT_UP(.long \
+               PMD_TYPE_SECT | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ | \
+               PMD_FLAGS_UP)
        .long   PMD_TYPE_SECT | \
                PMD_SECT_XN | \
                PMD_SECT_AP_WRITE | \
@@ -249,10 +260,16 @@ __v6_proc_info:
 __pj4_v6_proc_info:
        .long   0x560f5810
        .long   0xff0ffff0
-       .long   PMD_TYPE_SECT | \
+       ALT_SMP(.long \
+               PMD_TYPE_SECT | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ | \
+               PMD_FLAGS_SMP)
+       ALT_UP(.long \
+               PMD_TYPE_SECT | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ | \
-               PMD_FLAGS
+               PMD_FLAGS_UP)
        .long   PMD_TYPE_SECT | \
                PMD_SECT_XN | \
                PMD_SECT_AP_WRITE | \
index 197f21bed5e919f3a13f3cbc9404d428ad80fb97..53cbe2225153de55cf6848394d63d1fb1ea00a18 100644 (file)
 #define TTB_IRGN_WT    ((1 << 0) | (0 << 6))
 #define TTB_IRGN_WB    ((1 << 0) | (1 << 6))
 
-#ifndef CONFIG_SMP
 /* PTWs cacheable, inner WB not shareable, outer WB not shareable */
-#define TTB_FLAGS      TTB_IRGN_WB|TTB_RGN_OC_WB
-#define PMD_FLAGS      PMD_SECT_WB
-#else
+#define TTB_FLAGS_UP   TTB_IRGN_WB|TTB_RGN_OC_WB
+#define PMD_FLAGS_UP   PMD_SECT_WB
+
 /* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */
-#define TTB_FLAGS      TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA
-#define PMD_FLAGS      PMD_SECT_WBWA|PMD_SECT_S
-#endif
+#define TTB_FLAGS_SMP  TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA
+#define PMD_FLAGS_SMP  PMD_SECT_WBWA|PMD_SECT_S
 
 ENTRY(cpu_v7_proc_init)
        mov     pc, lr
@@ -105,7 +103,8 @@ ENTRY(cpu_v7_switch_mm)
 #ifdef CONFIG_MMU
        mov     r2, #0
        ldr     r1, [r1, #MM_CONTEXT_ID]        @ get mm->context.id
-       orr     r0, r0, #TTB_FLAGS
+       ALT_SMP(orr     r0, r0, #TTB_FLAGS_SMP)
+       ALT_UP(orr      r0, r0, #TTB_FLAGS_UP)
 #ifdef CONFIG_ARM_ERRATA_430973
        mcr     p15, 0, r2, c7, c5, 6           @ flush BTAC/BTB
 #endif
@@ -169,7 +168,7 @@ cpu_v7_name:
        .ascii  "ARMv7 Processor"
        .align
 
-       __INIT
+       __CPUINIT
 
 /*
  *     __v7_setup
@@ -188,7 +187,8 @@ cpu_v7_name:
  */
 __v7_ca9mp_setup:
 #ifdef CONFIG_SMP
-       mrc     p15, 0, r0, c1, c0, 1
+       ALT_SMP(mrc     p15, 0, r0, c1, c0, 1)
+       ALT_UP(mov      r0, #(1 << 6))          @ fake it for UP
        tst     r0, #(1 << 6)                   @ SMP/nAMP mode enabled?
        orreq   r0, r0, #(1 << 6) | (1 << 0)    @ Enable SMP/nAMP mode and
        mcreq   p15, 0, r0, c1, c0, 1           @ TLB ops broadcasting
@@ -270,7 +270,8 @@ __v7_setup:
 #ifdef CONFIG_MMU
        mcr     p15, 0, r10, c8, c7, 0          @ invalidate I + D TLBs
        mcr     p15, 0, r10, c2, c0, 2          @ TTB control register
-       orr     r4, r4, #TTB_FLAGS
+       ALT_SMP(orr     r4, r4, #TTB_FLAGS_SMP)
+       ALT_UP(orr      r4, r4, #TTB_FLAGS_UP)
        mcr     p15, 0, r4, c2, c0, 1           @ load TTB1
        mov     r10, #0x1f                      @ domains 0, 1 = manager
        mcr     p15, 0, r10, c3, c0, 0          @ load domain access register
@@ -332,6 +333,8 @@ v7_crval:
 __v7_setup_stack:
        .space  4 * 11                          @ 11 registers
 
+       __INITDATA
+
        .type   v7_processor_functions, #object
 ENTRY(v7_processor_functions)
        .word   v7_early_abort
@@ -345,6 +348,8 @@ ENTRY(v7_processor_functions)
        .word   cpu_v7_set_pte_ext
        .size   v7_processor_functions, . - v7_processor_functions
 
+       .section ".rodata"
+
        .type   cpu_arch_name, #object
 cpu_arch_name:
        .asciz  "armv7"
@@ -362,10 +367,16 @@ cpu_elf_name:
 __v7_ca9mp_proc_info:
        .long   0x410fc090              @ Required ID value
        .long   0xff0ffff0              @ Mask for ID
-       .long   PMD_TYPE_SECT | \
+       ALT_SMP(.long \
+               PMD_TYPE_SECT | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ | \
-               PMD_FLAGS
+               PMD_FLAGS_SMP)
+       ALT_UP(.long \
+               PMD_TYPE_SECT | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ | \
+               PMD_FLAGS_UP)
        .long   PMD_TYPE_SECT | \
                PMD_SECT_XN | \
                PMD_SECT_AP_WRITE | \
@@ -388,10 +399,16 @@ __v7_ca9mp_proc_info:
 __v7_proc_info:
        .long   0x000f0000              @ Required ID value
        .long   0x000f0000              @ Mask for ID
-       .long   PMD_TYPE_SECT | \
+       ALT_SMP(.long \
+               PMD_TYPE_SECT | \
+               PMD_SECT_AP_WRITE | \
+               PMD_SECT_AP_READ | \
+               PMD_FLAGS_SMP)
+       ALT_UP(.long \
+               PMD_TYPE_SECT | \
                PMD_SECT_AP_WRITE | \
                PMD_SECT_AP_READ | \
-               PMD_FLAGS
+               PMD_FLAGS_UP)
        .long   PMD_TYPE_SECT | \
                PMD_SECT_XN | \
                PMD_SECT_AP_WRITE | \
index 361a51e4903063ffc82f6831f3bee47e3a957860..cad07e403044f3a2ba3b62b0812d4b37c6b4ff9f 100644 (file)
@@ -404,7 +404,7 @@ ENTRY(cpu_xsc3_set_pte_ext)
 
        .align
 
-       __INIT
+       __CPUINIT
 
        .type   __xsc3_setup, #function
 __xsc3_setup:
index 14075979bcbac1a4bfe7ae346e97058de819d448..cb245edb2c2bc2e25aa355473f8ceab9dc35d493 100644 (file)
@@ -506,7 +506,7 @@ ENTRY(cpu_xscale_set_pte_ext)
 
        .align
 
-       __INIT
+       __CPUINIT
 
        .type   __xscale_setup, #function
 __xscale_setup:
index f3f288a9546d2a89f4f6d940c6387062ef8ff143..53cd5b45467318e7fae97127bcdead01e3f4e8eb 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <linux/init.h>
 #include <linux/linkage.h>
+#include <asm/assembler.h>
 #include <asm/asm-offsets.h>
 #include <asm/page.h>
 #include <asm/tlbflush.h>
@@ -41,20 +42,15 @@ ENTRY(v7wbi_flush_user_tlb_range)
        orr     r0, r3, r0, lsl #PAGE_SHIFT     @ Create initial MVA
        mov     r1, r1, lsl #PAGE_SHIFT
 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
+       ALT_SMP(mcr     p15, 0, r0, c8, c3, 1)  @ TLB invalidate U MVA (shareable)
+       ALT_UP(mcr      p15, 0, r0, c8, c7, 1)  @ TLB invalidate U MVA
+
        add     r0, r0, #PAGE_SZ
        cmp     r0, r1
        blo     1b
        mov     ip, #0
-#ifdef CONFIG_SMP
-       mcr     p15, 0, ip, c7, c1, 6           @ flush BTAC/BTB Inner Shareable
-#else
-       mcr     p15, 0, ip, c7, c5, 6           @ flush BTAC/BTB
-#endif
+       ALT_SMP(mcr     p15, 0, ip, c7, c1, 6)  @ flush BTAC/BTB Inner Shareable
+       ALT_UP(mcr      p15, 0, ip, c7, c5, 6)  @ flush BTAC/BTB
        dsb
        mov     pc, lr
 ENDPROC(v7wbi_flush_user_tlb_range)
@@ -74,20 +70,14 @@ ENTRY(v7wbi_flush_kern_tlb_range)
        mov     r0, r0, lsl #PAGE_SHIFT
        mov     r1, r1, lsl #PAGE_SHIFT
 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
+       ALT_SMP(mcr     p15, 0, r0, c8, c3, 1)  @ TLB invalidate U MVA (shareable)
+       ALT_UP(mcr      p15, 0, r0, c8, c7, 1)  @ TLB invalidate U MVA
        add     r0, r0, #PAGE_SZ
        cmp     r0, r1
        blo     1b
        mov     r2, #0
-#ifdef CONFIG_SMP
-       mcr     p15, 0, r2, c7, c1, 6           @ flush BTAC/BTB Inner Shareable
-#else
-       mcr     p15, 0, r2, c7, c5, 6           @ flush BTAC/BTB
-#endif
+       ALT_SMP(mcr     p15, 0, r2, c7, c1, 6)  @ flush BTAC/BTB Inner Shareable
+       ALT_UP(mcr      p15, 0, r2, c7, c5, 6)  @ flush BTAC/BTB
        dsb
        isb
        mov     pc, lr
@@ -99,5 +89,6 @@ ENDPROC(v7wbi_flush_kern_tlb_range)
 ENTRY(v7wbi_tlb_fns)
        .long   v7wbi_flush_user_tlb_range
        .long   v7wbi_flush_kern_tlb_range
-       .long   v7wbi_tlb_flags
+       ALT_SMP(.long   v7wbi_tlb_flags_smp)
+       ALT_UP(.long    v7wbi_tlb_flags_up)
        .size   v7wbi_tlb_fns, . - v7wbi_tlb_fns
index e666eafed15295aa5feeedf60d374a704b2caa15..b2215c61cdf02a18df71849611007d97cfea4470 100644 (file)
@@ -6,4 +6,8 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
                oprofilefs.o oprofile_stats.o \
                timer_int.o )
 
+ifeq ($(CONFIG_HW_PERF_EVENTS),y)
+DRIVER_OBJS += $(addprefix ../../../drivers/oprofile/, oprofile_perf.o)
+endif
+
 oprofile-y                             := $(DRIVER_OBJS) common.o
index 72e09eb642dd7c7a00d47fce210bb1290e926fd9..8aa974491dfcd555a6962461c0d2aa5f3287b653 100644 (file)
 #include <asm/ptrace.h>
 
 #ifdef CONFIG_HW_PERF_EVENTS
-/*
- * Per performance monitor configuration as set via oprofilefs.
- */
-struct op_counter_config {
-       unsigned long count;
-       unsigned long enabled;
-       unsigned long event;
-       unsigned long unit_mask;
-       unsigned long kernel;
-       unsigned long user;
-       struct perf_event_attr attr;
-};
-
-static int op_arm_enabled;
-static DEFINE_MUTEX(op_arm_mutex);
-
-static struct op_counter_config *counter_config;
-static struct perf_event **perf_events[nr_cpumask_bits];
-static int perf_num_counters;
-
-/*
- * Overflow callback for oprofile.
- */
-static void op_overflow_handler(struct perf_event *event, int unused,
-                       struct perf_sample_data *data, struct pt_regs *regs)
+char *op_name_from_perf_id(void)
 {
-       int id;
-       u32 cpu = smp_processor_id();
-
-       for (id = 0; id < perf_num_counters; ++id)
-               if (perf_events[cpu][id] == event)
-                       break;
-
-       if (id != perf_num_counters)
-               oprofile_add_sample(regs, id);
-       else
-               pr_warning("oprofile: ignoring spurious overflow "
-                               "on cpu %u\n", cpu);
-}
-
-/*
- * Called by op_arm_setup to create perf attributes to mirror the oprofile
- * settings in counter_config. Attributes are created as `pinned' events and
- * so are permanently scheduled on the PMU.
- */
-static void op_perf_setup(void)
-{
-       int i;
-       u32 size = sizeof(struct perf_event_attr);
-       struct perf_event_attr *attr;
-
-       for (i = 0; i < perf_num_counters; ++i) {
-               attr = &counter_config[i].attr;
-               memset(attr, 0, size);
-               attr->type              = PERF_TYPE_RAW;
-               attr->size              = size;
-               attr->config            = counter_config[i].event;
-               attr->sample_period     = counter_config[i].count;
-               attr->pinned            = 1;
-       }
-}
-
-static int op_create_counter(int cpu, int event)
-{
-       int ret = 0;
-       struct perf_event *pevent;
-
-       if (!counter_config[event].enabled || (perf_events[cpu][event] != NULL))
-               return ret;
-
-       pevent = perf_event_create_kernel_counter(&counter_config[event].attr,
-                                                 cpu, -1,
-                                                 op_overflow_handler);
-
-       if (IS_ERR(pevent)) {
-               ret = PTR_ERR(pevent);
-       } else if (pevent->state != PERF_EVENT_STATE_ACTIVE) {
-               perf_event_release_kernel(pevent);
-               pr_warning("oprofile: failed to enable event %d "
-                               "on CPU %d\n", event, cpu);
-               ret = -EBUSY;
-       } else {
-               perf_events[cpu][event] = pevent;
-       }
-
-       return ret;
-}
+       enum arm_perf_pmu_ids id = armpmu_get_pmu_id();
 
-static void op_destroy_counter(int cpu, int event)
-{
-       struct perf_event *pevent = perf_events[cpu][event];
-
-       if (pevent) {
-               perf_event_release_kernel(pevent);
-               perf_events[cpu][event] = NULL;
-       }
-}
-
-/*
- * Called by op_arm_start to create active perf events based on the
- * perviously configured attributes.
- */
-static int op_perf_start(void)
-{
-       int cpu, event, ret = 0;
-
-       for_each_online_cpu(cpu) {
-               for (event = 0; event < perf_num_counters; ++event) {
-                       ret = op_create_counter(cpu, event);
-                       if (ret)
-                               goto out;
-               }
-       }
-
-out:
-       return ret;
-}
-
-/*
- * Called by op_arm_stop at the end of a profiling run.
- */
-static void op_perf_stop(void)
-{
-       int cpu, event;
-
-       for_each_online_cpu(cpu)
-               for (event = 0; event < perf_num_counters; ++event)
-                       op_destroy_counter(cpu, event);
-}
-
-
-static char *op_name_from_perf_id(enum arm_perf_pmu_ids id)
-{
        switch (id) {
        case ARM_PERF_PMU_ID_XSCALE1:
                return "arm/xscale1";
@@ -176,116 +47,6 @@ static char *op_name_from_perf_id(enum arm_perf_pmu_ids id)
        }
 }
 
-static int op_arm_create_files(struct super_block *sb, struct dentry *root)
-{
-       unsigned int i;
-
-       for (i = 0; i < perf_num_counters; i++) {
-               struct dentry *dir;
-               char buf[4];
-
-               snprintf(buf, sizeof buf, "%d", i);
-               dir = oprofilefs_mkdir(sb, root, buf);
-               oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
-               oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
-               oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
-               oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
-               oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
-               oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
-       }
-
-       return 0;
-}
-
-static int op_arm_setup(void)
-{
-       spin_lock(&oprofilefs_lock);
-       op_perf_setup();
-       spin_unlock(&oprofilefs_lock);
-       return 0;
-}
-
-static int op_arm_start(void)
-{
-       int ret = -EBUSY;
-
-       mutex_lock(&op_arm_mutex);
-       if (!op_arm_enabled) {
-               ret = 0;
-               op_perf_start();
-               op_arm_enabled = 1;
-       }
-       mutex_unlock(&op_arm_mutex);
-       return ret;
-}
-
-static void op_arm_stop(void)
-{
-       mutex_lock(&op_arm_mutex);
-       if (op_arm_enabled)
-               op_perf_stop();
-       op_arm_enabled = 0;
-       mutex_unlock(&op_arm_mutex);
-}
-
-#ifdef CONFIG_PM
-static int op_arm_suspend(struct platform_device *dev, pm_message_t state)
-{
-       mutex_lock(&op_arm_mutex);
-       if (op_arm_enabled)
-               op_perf_stop();
-       mutex_unlock(&op_arm_mutex);
-       return 0;
-}
-
-static int op_arm_resume(struct platform_device *dev)
-{
-       mutex_lock(&op_arm_mutex);
-       if (op_arm_enabled && op_perf_start())
-               op_arm_enabled = 0;
-       mutex_unlock(&op_arm_mutex);
-       return 0;
-}
-
-static struct platform_driver oprofile_driver = {
-       .driver         = {
-               .name           = "arm-oprofile",
-       },
-       .resume         = op_arm_resume,
-       .suspend        = op_arm_suspend,
-};
-
-static struct platform_device *oprofile_pdev;
-
-static int __init init_driverfs(void)
-{
-       int ret;
-
-       ret = platform_driver_register(&oprofile_driver);
-       if (ret)
-               goto out;
-
-       oprofile_pdev = platform_device_register_simple(
-                               oprofile_driver.driver.name, 0, NULL, 0);
-       if (IS_ERR(oprofile_pdev)) {
-               ret = PTR_ERR(oprofile_pdev);
-               platform_driver_unregister(&oprofile_driver);
-       }
-
-out:
-       return ret;
-}
-
-static void  exit_driverfs(void)
-{
-       platform_device_unregister(oprofile_pdev);
-       platform_driver_unregister(&oprofile_driver);
-}
-#else
-static int __init init_driverfs(void) { return 0; }
-#define exit_driverfs() do { } while (0)
-#endif /* CONFIG_PM */
-
 static int report_trace(struct stackframe *frame, void *d)
 {
        unsigned int *depth = d;
@@ -350,74 +111,14 @@ static void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-       int cpu, ret = 0;
-
-       perf_num_counters = armpmu_get_max_events();
-
-       counter_config = kcalloc(perf_num_counters,
-                       sizeof(struct op_counter_config), GFP_KERNEL);
-
-       if (!counter_config) {
-               pr_info("oprofile: failed to allocate %d "
-                               "counters\n", perf_num_counters);
-               return -ENOMEM;
-       }
-
-       ret = init_driverfs();
-       if (ret) {
-               kfree(counter_config);
-               counter_config = NULL;
-               return ret;
-       }
-
-       for_each_possible_cpu(cpu) {
-               perf_events[cpu] = kcalloc(perf_num_counters,
-                               sizeof(struct perf_event *), GFP_KERNEL);
-               if (!perf_events[cpu]) {
-                       pr_info("oprofile: failed to allocate %d perf events "
-                                       "for cpu %d\n", perf_num_counters, cpu);
-                       while (--cpu >= 0)
-                               kfree(perf_events[cpu]);
-                       return -ENOMEM;
-               }
-       }
-
        ops->backtrace          = arm_backtrace;
-       ops->create_files       = op_arm_create_files;
-       ops->setup              = op_arm_setup;
-       ops->start              = op_arm_start;
-       ops->stop               = op_arm_stop;
-       ops->shutdown           = op_arm_stop;
-       ops->cpu_type           = op_name_from_perf_id(armpmu_get_pmu_id());
-
-       if (!ops->cpu_type)
-               ret = -ENODEV;
-       else
-               pr_info("oprofile: using %s\n", ops->cpu_type);
 
-       return ret;
+       return oprofile_perf_init(ops);
 }
 
-void oprofile_arch_exit(void)
+void __exit oprofile_arch_exit(void)
 {
-       int cpu, id;
-       struct perf_event *event;
-
-       if (*perf_events) {
-               for_each_possible_cpu(cpu) {
-                       for (id = 0; id < perf_num_counters; ++id) {
-                               event = perf_events[cpu][id];
-                               if (event != NULL)
-                                       perf_event_release_kernel(event);
-                       }
-                       kfree(perf_events[cpu]);
-               }
-       }
-
-       if (counter_config) {
-               kfree(counter_config);
-               exit_driverfs();
-       }
+       oprofile_perf_exit();
 }
 #else
 int __init oprofile_arch_init(struct oprofile_operations *ops)
@@ -425,5 +126,5 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        pr_info("oprofile: hardware counters not available\n");
        return -ENODEV;
 }
-void oprofile_arch_exit(void) {}
+void __exit oprofile_arch_exit(void) {}
 #endif /* CONFIG_HW_PERF_EVENTS */
index 6785db4179b84ccd925f9112cd48e9be71668e7c..64e3a64520e086cf24e57b10f2716b8bd852b0fd 100644 (file)
@@ -92,6 +92,18 @@ config MXC_DEBUG_BOARD
          data/address de-multiplexing and decode, signal level shift,
          interrupt control and various board functions.
 
+config HAVE_EPIT
+       bool
+
+config MXC_USE_EPIT
+       bool "Use EPIT instead of GPT"
+       depends on HAVE_EPIT
+       help
+         Use EPIT as the system timer on systems that have it. Normally you
+         don't have a reason to do so as the EPIT has the same features and
+         uses the same clocks as the GPT. Anyway, on some systems the GPT
+         may be in use for other purposes.
+
 config MXC_ULPI
        bool
 
@@ -110,4 +122,8 @@ config ARCH_MXC_AUDMUX_V1
 config ARCH_MXC_AUDMUX_V2
        bool
 
+config IRAM_ALLOC
+       bool
+       select GENERIC_ALLOCATOR
+
 endif
index 78d405ed861656ef83182a7242c385dcab805ce0..06875b4dd70fb2999da998299238aaf1e460d07b 100644 (file)
@@ -10,9 +10,11 @@ obj-$(CONFIG_MXC_TZIC) += tzic.o
 
 obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
 obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
+obj-$(CONFIG_IRAM_ALLOC) += iram_alloc.o
 obj-$(CONFIG_MXC_PWM)  += pwm.o
 obj-$(CONFIG_USB_EHCI_MXC) += ehci.o
 obj-$(CONFIG_MXC_ULPI) += ulpi.o
+obj-$(CONFIG_MXC_USE_EPIT) += epit.o
 obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
 obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o
 obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o
index f9e7cdbd000568a562ac4bd062a550df73f3a853..62920490c0d6be3900b7475548a1ffbbc3d44b8a 100644 (file)
@@ -186,7 +186,13 @@ EXPORT_SYMBOL_GPL(mxc_audmux_v2_configure_port);
 static int mxc_audmux_v2_init(void)
 {
        int ret;
-
+#if defined(CONFIG_ARCH_MX5)
+       if (cpu_is_mx51()) {
+               audmux_base = MX51_IO_ADDRESS(MX51_AUDMUX_BASE_ADDR);
+               ret = 0;
+               return ret;
+       }
+#endif
 #if defined(CONFIG_ARCH_MX3)
        if (cpu_is_mx31())
                audmux_base = MX31_IO_ADDRESS(MX31_AUDMUX_BASE_ADDR);
index 9ab784b776f9192a33feaff37ff21be99b0a3691..404799487f1760b5eb9cec4e0636753830b54566 100644 (file)
@@ -1,3 +1,10 @@
+config IMX_HAVE_PLATFORM_ESDHC
+       bool
+
+config IMX_HAVE_PLATFORM_FEC
+       bool
+       default y if ARCH_MX25 || SOC_IMX27 || ARCH_MX35 || ARCH_MX51
+
 config IMX_HAVE_PLATFORM_FLEXCAN
        select HAVE_CAN_FLEXCAN
        bool
@@ -5,6 +12,9 @@ config IMX_HAVE_PLATFORM_FLEXCAN
 config IMX_HAVE_PLATFORM_IMX_I2C
        bool
 
+config IMX_HAVE_PLATFORM_IMX_SSI
+       bool
+
 config IMX_HAVE_PLATFORM_IMX_UART
        bool
 
index 347da5161f7e82521c0b6f4d930742267068fcdc..0a3c1f089413e2e2a896326612e3dd080e02818f 100644 (file)
@@ -1,8 +1,9 @@
-ifdef CONFIG_CAN_FLEXCAN
-# the ifdef can be removed once the flexcan driver has been merged
-obj-$(CONFIG_IMX_HAVE_PLATFORM_FLEXCAN) +=  platform-flexcan.o
-endif
+obj-$(CONFIG_IMX_HAVE_PLATFORM_ESDHC) += platform-esdhc.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_FEC) += platform-fec.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o
+obj-y += platform-imx-dma.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_I2C) += platform-imx-i2c.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_SSI) += platform-imx-ssi.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_UART) += platform-imx-uart.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) +=  platform-spi_imx.o
diff --git a/arch/arm/plat-mxc/devices/platform-esdhc.c b/arch/arm/plat-mxc/devices/platform-esdhc.c
new file mode 100644 (file)
index 0000000..2605bfa
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Pengutronix, Wolfram Sang <w.sang@pengutronix.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 <mach/hardware.h>
+#include <mach/devices-common.h>
+#include <mach/esdhc.h>
+
+#define imx_esdhc_imx_data_entry_single(soc, _id, hwid) \
+       {                                                               \
+               .id = _id,                                              \
+               .iobase = soc ## _ESDHC ## hwid ## _BASE_ADDR,  \
+               .irq = soc ## _INT_ESDHC ## hwid,                       \
+       }
+
+#define imx_esdhc_imx_data_entry(soc, id, hwid)        \
+       [id] = imx_esdhc_imx_data_entry_single(soc, id, hwid)
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_esdhc_imx_data imx25_esdhc_data[] __initconst = {
+#define imx25_esdhc_data_entry(_id, _hwid)                             \
+       imx_esdhc_imx_data_entry(MX25, _id, _hwid)
+       imx25_esdhc_data_entry(0, 1),
+       imx25_esdhc_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_esdhc_imx_data imx35_esdhc_data[] __initconst = {
+#define imx35_esdhc_data_entry(_id, _hwid)                           \
+       imx_esdhc_imx_data_entry(MX35, _id, _hwid)
+       imx35_esdhc_data_entry(0, 1),
+       imx35_esdhc_data_entry(1, 2),
+       imx35_esdhc_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_esdhc_imx_data imx51_esdhc_data[] __initconst = {
+#define imx51_esdhc_data_entry(_id, _hwid)                             \
+       imx_esdhc_imx_data_entry(MX51, _id, _hwid)
+       imx51_esdhc_data_entry(0, 1),
+       imx51_esdhc_data_entry(1, 2),
+       imx51_esdhc_data_entry(2, 3),
+       imx51_esdhc_data_entry(3, 4),
+};
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+struct platform_device *__init imx_add_esdhc(
+               const struct imx_esdhc_imx_data *data,
+               const struct esdhc_platform_data *pdata)
+{
+       struct resource res[] = {
+               {
+                       .start = data->iobase,
+                       .end = data->iobase + SZ_16K - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = data->irq,
+                       .end = data->irq,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+
+       return imx_add_platform_device("sdhci-esdhc-imx", data->id, res,
+                       ARRAY_SIZE(res), pdata, sizeof(*pdata));
+}
diff --git a/arch/arm/plat-mxc/devices/platform-fec.c b/arch/arm/plat-mxc/devices/platform-fec.c
new file mode 100644 (file)
index 0000000..11d087f
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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 <asm/sizes.h>
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#define imx_fec_data_entry_single(soc)                                 \
+       {                                                               \
+               .iobase = soc ## _FEC_BASE_ADDR,                        \
+               .irq = soc ## _INT_FEC,                                 \
+       }
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_fec_data imx25_fec_data __initconst =
+       imx_fec_data_entry_single(MX25);
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_fec_data imx27_fec_data __initconst =
+       imx_fec_data_entry_single(MX27);
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_fec_data imx35_fec_data __initconst =
+       imx_fec_data_entry_single(MX35);
+#endif
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_fec_data imx51_fec_data __initconst =
+       imx_fec_data_entry_single(MX51);
+#endif
+
+struct platform_device *__init imx_add_fec(
+               const struct imx_fec_data *data,
+               const struct fec_platform_data *pdata)
+{
+       struct resource res[] = {
+               {
+                       .start = data->iobase,
+                       .end = data->iobase + SZ_4K,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = data->irq,
+                       .end = data->irq,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+
+       return imx_add_platform_device("fec", 0 /* -1? */,
+                       res, ARRAY_SIZE(res),
+                       pdata, sizeof(*pdata));
+}
diff --git a/arch/arm/plat-mxc/devices/platform-imx-dma.c b/arch/arm/plat-mxc/devices/platform-imx-dma.c
new file mode 100644 (file)
index 0000000..02d9890
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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/compiler.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+#ifdef SDMA_IS_MERGED
+#include <mach/sdma.h>
+#else
+struct sdma_platform_data {
+       int sdma_version;
+       char *cpu_name;
+       int to_version;
+};
+#endif
+
+struct imx_imx_sdma_data {
+       resource_size_t iobase;
+       resource_size_t irq;
+       struct sdma_platform_data pdata;
+};
+
+#define imx_imx_sdma_data_entry_single(soc, _sdma_version, _cpu_name, _to_version)\
+       {                                                               \
+               .iobase = soc ## _SDMA ## _BASE_ADDR,                   \
+               .irq = soc ## _INT_SDMA,                                \
+               .pdata = {                                              \
+                       .sdma_version = _sdma_version,                  \
+                       .cpu_name = _cpu_name,                          \
+                       .to_version = _to_version,                      \
+               },                                                      \
+       }
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_imx_sdma_data imx25_imx_sdma_data __initconst =
+       imx_imx_sdma_data_entry_single(MX25, 1, "imx25", 0);
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_ARCH_MX31
+struct imx_imx_sdma_data imx31_imx_sdma_data __initdata =
+       imx_imx_sdma_data_entry_single(MX31, 1, "imx31", 0);
+#endif /* ifdef CONFIG_ARCH_MX31 */
+
+#ifdef CONFIG_ARCH_MX35
+struct imx_imx_sdma_data imx35_imx_sdma_data __initdata =
+       imx_imx_sdma_data_entry_single(MX35, 2, "imx35", 0);
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_imx_sdma_data imx51_imx_sdma_data __initconst =
+       imx_imx_sdma_data_entry_single(MX51, 2, "imx51", 0);
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+static struct platform_device __init __maybe_unused *imx_add_imx_sdma(
+               const struct imx_imx_sdma_data *data)
+{
+       struct resource res[] = {
+               {
+                       .start = data->iobase,
+                       .end = data->iobase + SZ_4K - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = data->irq,
+                       .end = data->irq,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+
+       return imx_add_platform_device("imx-sdma", -1,
+                       res, ARRAY_SIZE(res),
+                       &data->pdata, sizeof(data->pdata));
+}
+
+static struct platform_device __init __maybe_unused *imx_add_imx_dma(void)
+{
+       return imx_add_platform_device("imx-dma", -1, NULL, 0, NULL, 0);
+}
+
+static int __init imxXX_add_imx_dma(void)
+{
+       struct platform_device *ret;
+
+#if defined(CONFIG_SOC_IMX21) || defined(CONFIG_SOC_IMX27)
+       if (cpu_is_mx21() || cpu_is_mx27())
+               ret = imx_add_imx_dma();
+       else
+#endif
+
+#if defined(CONFIG_ARCH_MX25)
+       if (cpu_is_mx25())
+               ret = imx_add_imx_sdma(&imx25_imx_sdma_data);
+       else
+#endif
+
+#if defined(CONFIG_ARCH_MX31)
+       if (cpu_is_mx31()) {
+               imx31_imx_sdma_data.pdata.to_version = mx31_revision() >> 4;
+               ret = imx_add_imx_sdma(&imx31_imx_sdma_data);
+       } else
+#endif
+
+#if defined(CONFIG_ARCH_MX35)
+       if (cpu_is_mx35()) {
+               imx35_imx_sdma_data.pdata.to_version = mx35_revision() >> 4;
+               ret = imx_add_imx_sdma(&imx35_imx_sdma_data);
+       } else
+#endif
+
+#if defined(CONFIG_ARCH_MX51)
+       if (cpu_is_mx51())
+               ret = imx_add_imx_sdma(&imx51_imx_sdma_data);
+       else
+#endif
+               ret = ERR_PTR(-ENODEV);
+
+       if (IS_ERR(ret))
+               return PTR_ERR(ret);
+
+       return 0;
+}
+arch_initcall(imxXX_add_imx_dma);
index d0af9f7d8aed06439f3e2978b9969595b0d3eaa6..679588453aad330004bd7c1fc13d2a371c281922 100644 (file)
@@ -6,24 +6,95 @@
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
  */
+#include <mach/hardware.h>
 #include <mach/devices-common.h>
 
-struct platform_device *__init imx_add_imx_i2c(int id,
-               resource_size_t iobase, resource_size_t iosize, int irq,
+#define imx_imx_i2c_data_entry_single(soc, _id, _hwid, _size)          \
+       {                                                               \
+               .id = _id,                                              \
+               .iobase = soc ## _I2C ## _hwid ## _BASE_ADDR,           \
+               .iosize = _size,                                        \
+               .irq = soc ## _INT_I2C ## _hwid,                        \
+       }
+
+#define imx_imx_i2c_data_entry(soc, _id, _hwid, _size)                 \
+       [_id] = imx_imx_i2c_data_entry_single(soc, _id, _hwid, _size)
+
+#ifdef CONFIG_SOC_IMX1
+const struct imx_imx_i2c_data imx1_imx_i2c_data __initconst =
+       imx_imx_i2c_data_entry_single(MX1, 0, , SZ_4K);
+#endif /* ifdef CONFIG_SOC_IMX1 */
+
+#ifdef CONFIG_SOC_IMX21
+const struct imx_imx_i2c_data imx21_imx_i2c_data __initconst =
+       imx_imx_i2c_data_entry_single(MX21, 0, , SZ_4K);
+#endif /* ifdef CONFIG_SOC_IMX21 */
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_imx_i2c_data imx25_imx_i2c_data[] __initconst = {
+#define imx25_imx_i2c_data_entry(_id, _hwid)                           \
+       imx_imx_i2c_data_entry(MX25, _id, _hwid, SZ_16K)
+       imx25_imx_i2c_data_entry(0, 1),
+       imx25_imx_i2c_data_entry(1, 2),
+       imx25_imx_i2c_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_imx_i2c_data imx27_imx_i2c_data[] __initconst = {
+#define imx27_imx_i2c_data_entry(_id, _hwid)                           \
+       imx_imx_i2c_data_entry(MX27, _id, _hwid, SZ_4K)
+       imx27_imx_i2c_data_entry(0, 1),
+       imx27_imx_i2c_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX31
+const struct imx_imx_i2c_data imx31_imx_i2c_data[] __initconst = {
+#define imx31_imx_i2c_data_entry(_id, _hwid)                           \
+       imx_imx_i2c_data_entry(MX31, _id, _hwid, SZ_4K)
+       imx31_imx_i2c_data_entry(0, 1),
+       imx31_imx_i2c_data_entry(1, 2),
+       imx31_imx_i2c_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX31 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_imx_i2c_data imx35_imx_i2c_data[] __initconst = {
+#define imx35_imx_i2c_data_entry(_id, _hwid)                           \
+       imx_imx_i2c_data_entry(MX35, _id, _hwid, SZ_4K)
+       imx35_imx_i2c_data_entry(0, 1),
+       imx35_imx_i2c_data_entry(1, 2),
+       imx35_imx_i2c_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst = {
+#define imx51_imx_i2c_data_entry(_id, _hwid)                           \
+       imx_imx_i2c_data_entry(MX51, _id, _hwid, SZ_4K)
+       imx51_imx_i2c_data_entry(0, 1),
+       imx51_imx_i2c_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+struct platform_device *__init imx_add_imx_i2c(
+               const struct imx_imx_i2c_data *data,
                const struct imxi2c_platform_data *pdata)
 {
        struct resource res[] = {
                {
-                       .start = iobase,
-                       .end = iobase + iosize - 1,
+                       .start = data->iobase,
+                       .end = data->iobase + data->iosize - 1,
                        .flags = IORESOURCE_MEM,
                }, {
-                       .start = irq,
-                       .end = irq,
+                       .start = data->irq,
+                       .end = data->irq,
                        .flags = IORESOURCE_IRQ,
                },
        };
 
-       return imx_add_platform_device("imx-i2c", id, res, ARRAY_SIZE(res),
+       return imx_add_platform_device("imx-i2c", data->id,
+                       res, ARRAY_SIZE(res),
                        pdata, sizeof(*pdata));
 }
diff --git a/arch/arm/plat-mxc/devices/platform-imx-ssi.c b/arch/arm/plat-mxc/devices/platform-imx-ssi.c
new file mode 100644 (file)
index 0000000..38a7a0b
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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 <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#define imx_imx_ssi_data_entry(soc, _id, _hwid, _size)                 \
+       [_id] = {                                                       \
+               .id = _id,                                              \
+               .iobase = soc ## _SSI ## _hwid ## _BASE_ADDR,           \
+               .iosize = _size,                                        \
+               .irq = soc ## _INT_SSI ## _hwid,                        \
+               .dmatx0 = soc ## _DMA_REQ_SSI ## _hwid ## _TX0,         \
+               .dmarx0 = soc ## _DMA_REQ_SSI ## _hwid ## _RX0,         \
+               .dmatx1 = soc ## _DMA_REQ_SSI ## _hwid ## _TX1,         \
+               .dmarx1 = soc ## _DMA_REQ_SSI ## _hwid ## _RX1,         \
+       }
+
+#ifdef CONFIG_SOC_IMX21
+const struct imx_imx_ssi_data imx21_imx_ssi_data[] __initconst = {
+#define imx21_imx_ssi_data_entry(_id, _hwid)                           \
+       imx_imx_ssi_data_entry(MX21, _id, _hwid, SZ_4K)
+       imx21_imx_ssi_data_entry(0, 1),
+       imx21_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX21 */
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_imx_ssi_data imx25_imx_ssi_data[] __initconst = {
+#define imx25_imx_ssi_data_entry(_id, _hwid)                           \
+       imx_imx_ssi_data_entry(MX25, _id, _hwid, SZ_4K)
+       imx25_imx_ssi_data_entry(0, 1),
+       imx25_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_imx_ssi_data imx27_imx_ssi_data[] __initconst = {
+#define imx27_imx_ssi_data_entry(_id, _hwid)                           \
+       imx_imx_ssi_data_entry(MX27, _id, _hwid, SZ_4K)
+       imx27_imx_ssi_data_entry(0, 1),
+       imx27_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX31
+const struct imx_imx_ssi_data imx31_imx_ssi_data[] __initconst = {
+#define imx31_imx_ssi_data_entry(_id, _hwid)                           \
+       imx_imx_ssi_data_entry(MX31, _id, _hwid, SZ_4K)
+       imx31_imx_ssi_data_entry(0, 1),
+       imx31_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX31 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_imx_ssi_data imx35_imx_ssi_data[] __initconst = {
+#define imx35_imx_ssi_data_entry(_id, _hwid)                           \
+       imx_imx_ssi_data_entry(MX35, _id, _hwid, SZ_4K)
+       imx35_imx_ssi_data_entry(0, 1),
+       imx35_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_imx_ssi_data imx51_imx_ssi_data[] __initconst = {
+#define imx51_imx_ssi_data_entry(_id, _hwid)                           \
+       imx_imx_ssi_data_entry(MX51, _id, _hwid, SZ_4K)
+       imx51_imx_ssi_data_entry(0, 1),
+       imx51_imx_ssi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+struct platform_device *__init imx_add_imx_ssi(
+               const struct imx_imx_ssi_data *data,
+               const struct imx_ssi_platform_data *pdata)
+{
+       struct resource res[] = {
+               {
+                       .start = data->iobase,
+                       .end = data->iobase + data->iosize - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = data->irq,
+                       .end = data->irq,
+                       .flags = IORESOURCE_IRQ,
+               },
+#define DMARES(_name) {                                                        \
+       .name = #_name,                                                 \
+       .start = data->dma ## _name,                                    \
+       .end = data->dma ## _name,                                      \
+       .flags = IORESOURCE_DMA,                                        \
+}
+               DMARES(tx0),
+               DMARES(rx0),
+               DMARES(tx1),
+               DMARES(rx1),
+       };
+
+       return imx_add_platform_device("imx-ssi", data->id,
+                       res, ARRAY_SIZE(res),
+                       pdata, sizeof(*pdata));
+}
index fa3dff1433e8e86afe8570f96cd6a780310604e8..2039640adf27ffa8b126788754570ccf81355c24 100644 (file)
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
  */
+#include <mach/hardware.h>
 #include <mach/devices-common.h>
 
-struct platform_device *__init imx_add_imx_uart_3irq(int id,
-               resource_size_t iobase, resource_size_t iosize,
-               resource_size_t irqrx, resource_size_t irqtx,
-               resource_size_t irqrts,
+#define imx_imx_uart_3irq_data_entry(soc, _id, _hwid, _size)           \
+       [_id] = {                                                       \
+               .id = _id,                                              \
+               .iobase = soc ## _UART ## _hwid ## _BASE_ADDR,          \
+               .iosize = _size,                                        \
+               .irqrx = soc ## _INT_UART ## _hwid ## RX,               \
+               .irqtx = soc ## _INT_UART ## _hwid ## TX,               \
+               .irqrts = soc ## _INT_UART ## _hwid ## RTS,             \
+       }
+
+#define imx_imx_uart_1irq_data_entry(soc, _id, _hwid, _size)           \
+       [_id] = {                                                       \
+               .id = _id,                                              \
+               .iobase = soc ## _UART ## _hwid ## _BASE_ADDR,          \
+               .iosize = _size,                                        \
+               .irq = soc ## _INT_UART ## _hwid,                       \
+       }
+
+#ifdef CONFIG_SOC_IMX1
+const struct imx_imx_uart_3irq_data imx1_imx_uart_data[] __initconst = {
+#define imx1_imx_uart_data_entry(_id, _hwid)                           \
+       imx_imx_uart_3irq_data_entry(MX1, _id, _hwid, 0xd0)
+       imx1_imx_uart_data_entry(0, 1),
+       imx1_imx_uart_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_SOC_IMX1 */
+
+#ifdef CONFIG_SOC_IMX21
+const struct imx_imx_uart_1irq_data imx21_imx_uart_data[] __initconst = {
+#define imx21_imx_uart_data_entry(_id, _hwid)                          \
+       imx_imx_uart_1irq_data_entry(MX21, _id, _hwid, SZ_4K)
+       imx21_imx_uart_data_entry(0, 1),
+       imx21_imx_uart_data_entry(1, 2),
+       imx21_imx_uart_data_entry(2, 3),
+       imx21_imx_uart_data_entry(3, 4),
+};
+#endif
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_imx_uart_1irq_data imx25_imx_uart_data[] __initconst = {
+#define imx25_imx_uart_data_entry(_id, _hwid)                          \
+       imx_imx_uart_1irq_data_entry(MX25, _id, _hwid, SZ_16K)
+       imx25_imx_uart_data_entry(0, 1),
+       imx25_imx_uart_data_entry(1, 2),
+       imx25_imx_uart_data_entry(2, 3),
+       imx25_imx_uart_data_entry(3, 4),
+       imx25_imx_uart_data_entry(4, 5),
+};
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_imx_uart_1irq_data imx27_imx_uart_data[] __initconst = {
+#define imx27_imx_uart_data_entry(_id, _hwid)                          \
+       imx_imx_uart_1irq_data_entry(MX27, _id, _hwid, SZ_4K)
+       imx27_imx_uart_data_entry(0, 1),
+       imx27_imx_uart_data_entry(1, 2),
+       imx27_imx_uart_data_entry(2, 3),
+       imx27_imx_uart_data_entry(3, 4),
+       imx27_imx_uart_data_entry(4, 5),
+       imx27_imx_uart_data_entry(5, 6),
+};
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX31
+const struct imx_imx_uart_1irq_data imx31_imx_uart_data[] __initconst = {
+#define imx31_imx_uart_data_entry(_id, _hwid)                          \
+       imx_imx_uart_1irq_data_entry(MX31, _id, _hwid, SZ_4K)
+       imx31_imx_uart_data_entry(0, 1),
+       imx31_imx_uart_data_entry(1, 2),
+       imx31_imx_uart_data_entry(2, 3),
+       imx31_imx_uart_data_entry(3, 4),
+       imx31_imx_uart_data_entry(4, 5),
+};
+#endif /* ifdef CONFIG_ARCH_MX31 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_imx_uart_1irq_data imx35_imx_uart_data[] __initconst = {
+#define imx35_imx_uart_data_entry(_id, _hwid)                          \
+       imx_imx_uart_1irq_data_entry(MX31, _id, _hwid, SZ_16K)
+       imx35_imx_uart_data_entry(0, 1),
+       imx35_imx_uart_data_entry(1, 2),
+       imx35_imx_uart_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_imx_uart_1irq_data imx51_imx_uart_data[] __initconst = {
+#define imx51_imx_uart_data_entry(_id, _hwid)                          \
+       imx_imx_uart_1irq_data_entry(MX51, _id, _hwid, SZ_4K)
+       imx51_imx_uart_data_entry(0, 1),
+       imx51_imx_uart_data_entry(1, 2),
+       imx51_imx_uart_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+struct platform_device *__init imx_add_imx_uart_3irq(
+               const struct imx_imx_uart_3irq_data *data,
                const struct imxuart_platform_data *pdata)
 {
        struct resource res[] = {
                {
-                       .start = iobase,
-                       .end = iobase + iosize - 1,
+                       .start = data->iobase,
+                       .end = data->iobase + data->iosize - 1,
                        .flags = IORESOURCE_MEM,
                }, {
-                       .start = irqrx,
-                       .end = irqrx,
+                       .start = data->irqrx,
+                       .end = data->irqrx,
                        .flags = IORESOURCE_IRQ,
                }, {
-                       .start = irqtx,
-                       .end = irqtx,
+                       .start = data->irqtx,
+                       .end = data->irqtx,
                        .flags = IORESOURCE_IRQ,
                }, {
-                       .start = irqrts,
-                       .end = irqrx,
+                       .start = data->irqrts,
+                       .end = data->irqrx,
                        .flags = IORESOURCE_IRQ,
                },
        };
 
-       return imx_add_platform_device("imx-uart", id, res, ARRAY_SIZE(res),
-                       pdata, sizeof(*pdata));
+       return imx_add_platform_device("imx-uart", data->id, res,
+                       ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
 
-struct platform_device *__init imx_add_imx_uart_1irq(int id,
-               resource_size_t iobase, resource_size_t iosize,
-               resource_size_t irq,
+struct platform_device *__init imx_add_imx_uart_1irq(
+               const struct imx_imx_uart_1irq_data *data,
                const struct imxuart_platform_data *pdata)
 {
        struct resource res[] = {
                {
-                       .start = iobase,
-                       .end = iobase + iosize - 1,
+                       .start = data->iobase,
+                       .end = data->iobase + data->iosize - 1,
                        .flags = IORESOURCE_MEM,
                }, {
-                       .start = irq,
-                       .end = irq,
+                       .start = data->irq,
+                       .end = data->irq,
                        .flags = IORESOURCE_IRQ,
                },
        };
 
-       return imx_add_platform_device("imx-uart", id, res, ARRAY_SIZE(res),
+       return imx_add_platform_device("imx-uart", data->id, res, ARRAY_SIZE(res),
                        pdata, sizeof(*pdata));
 }
index 1c286418d12335140a2d466ca5532e388f42022c..3fdcc32e3d679b5170da47681935c470a8462abb 100644 (file)
@@ -7,38 +7,77 @@
  * Free Software Foundation.
  */
 #include <asm/sizes.h>
+#include <mach/hardware.h>
 #include <mach/devices-common.h>
 
-static struct platform_device *__init imx_add_mxc_nand(resource_size_t iobase,
-               int irq, const struct mxc_nand_platform_data *pdata,
-               resource_size_t iosize)
+#define imx_mxc_nand_data_entry_single(soc, _size)                     \
+       {                                                               \
+               .iobase = soc ## _NFC_BASE_ADDR,                        \
+               .iosize = _size,                                        \
+               .irq = soc ## _INT_NFC                                  \
+       }
+
+#define imx_mxc_nandv3_data_entry_single(soc, _size)                   \
+       {                                                               \
+               .id = -1,                                               \
+               .iobase = soc ## _NFC_BASE_ADDR,                        \
+               .iosize = _size,                                        \
+               .axibase = soc ## _NFC_AXI_BASE_ADDR,                   \
+               .irq = soc ## _INT_NFC                                  \
+       }
+
+#ifdef CONFIG_SOC_IMX21
+const struct imx_mxc_nand_data imx21_mxc_nand_data __initconst =
+       imx_mxc_nand_data_entry_single(MX21, SZ_4K);
+#endif /* ifdef CONFIG_SOC_IMX21 */
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_mxc_nand_data imx25_mxc_nand_data __initconst =
+       imx_mxc_nand_data_entry_single(MX25, SZ_8K);
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_mxc_nand_data imx27_mxc_nand_data __initconst =
+       imx_mxc_nand_data_entry_single(MX27, SZ_4K);
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX31
+const struct imx_mxc_nand_data imx31_mxc_nand_data __initconst =
+       imx_mxc_nand_data_entry_single(MX31, SZ_4K);
+#endif
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_mxc_nand_data imx35_mxc_nand_data __initconst =
+       imx_mxc_nand_data_entry_single(MX35, SZ_8K);
+#endif
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_mxc_nand_data imx51_mxc_nand_data __initconst =
+       imx_mxc_nandv3_data_entry_single(MX51, SZ_16K);
+#endif
+
+struct platform_device *__init imx_add_mxc_nand(
+               const struct imx_mxc_nand_data *data,
+               const struct mxc_nand_platform_data *pdata)
 {
-       static int id = 0;
-       
+       /* AXI has to come first, that's how the mxc_nand driver expect it */
        struct resource res[] = {
                {
-                       .start = iobase,
-                       .end = iobase + iosize - 1,
+                       .start = data->axibase,
+                       .end = data->axibase + SZ_16K - 1,
                        .flags = IORESOURCE_MEM,
                }, {
-                       .start = irq,
-                       .end = irq,
+                       .start = data->iobase,
+                       .end = data->iobase + data->iosize - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = data->irq,
+                       .end = data->irq,
                        .flags = IORESOURCE_IRQ,
                },
        };
-
-       return imx_add_platform_device("mxc_nand", id++, res, ARRAY_SIZE(res),
+       return imx_add_platform_device("mxc_nand", data->id,
+                       res + !data->axibase,
+                       ARRAY_SIZE(res) - !data->axibase,
                        pdata, sizeof(*pdata));
 }
-
-struct platform_device *__init imx_add_mxc_nand_v1(resource_size_t iobase,
-               int irq, const struct mxc_nand_platform_data *pdata)
-{
-       return imx_add_mxc_nand(iobase, irq, pdata, SZ_4K);
-}
-
-struct platform_device *__init imx_add_mxc_nand_v21(resource_size_t iobase,
-               int irq, const struct mxc_nand_platform_data *pdata)
-{
-       return imx_add_mxc_nand(iobase, irq, pdata, SZ_8K);
-}
index 2831a6d3eb4bf726f78a956960fc75d0fc436774..e48340ec331e4a8ca376b96c25b36faa0a7eafe0 100644 (file)
@@ -6,25 +6,96 @@
  * the terms of the GNU General Public License version 2 as published by the
  * Free Software Foundation.
  */
-#include <asm/sizes.h>
+#include <mach/hardware.h>
 #include <mach/devices-common.h>
 
-struct platform_device *__init imx_add_spi_imx(int id,
-               resource_size_t iobase, resource_size_t iosize, int irq,
+#define imx_spi_imx_data_entry_single(soc, type, _devid, _id, hwid, _size) \
+       {                                                               \
+               .devid = _devid,                                        \
+               .id = _id,                                              \
+               .iobase = soc ## _ ## type ## hwid ## _BASE_ADDR,       \
+               .iosize = _size,                                        \
+               .irq = soc ## _INT_ ## type ## hwid,                    \
+       }
+
+#define imx_spi_imx_data_entry(soc, type, devid, id, hwid, size)       \
+       [id] = imx_spi_imx_data_entry_single(soc, type, devid, id, hwid, size)
+
+#ifdef CONFIG_SOC_IMX21
+const struct imx_spi_imx_data imx21_cspi_data[] __initconst = {
+#define imx21_cspi_data_entry(_id, _hwid)                            \
+       imx_spi_imx_data_entry(MX21, CSPI, "imx21-cspi", _id, _hwid, SZ_4K)
+       imx21_cspi_data_entry(0, 1),
+       imx21_cspi_data_entry(1, 2),
+#endif
+
+#ifdef CONFIG_ARCH_MX25
+const struct imx_spi_imx_data imx25_cspi_data[] __initconst = {
+#define imx25_cspi_data_entry(_id, _hwid)                              \
+       imx_spi_imx_data_entry(MX25, CSPI, "imx25-cspi", _id, _hwid, SZ_16K)
+       imx25_cspi_data_entry(0, 1),
+       imx25_cspi_data_entry(1, 2),
+       imx25_cspi_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX25 */
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_spi_imx_data imx27_cspi_data[] __initconst = {
+#define imx27_cspi_data_entry(_id, _hwid)                              \
+       imx_spi_imx_data_entry(MX27, CSPI, "imx27-cspi", _id, _hwid, SZ_4K)
+       imx27_cspi_data_entry(0, 1),
+       imx27_cspi_data_entry(1, 2),
+       imx27_cspi_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_SOC_IMX27 */
+
+#ifdef CONFIG_ARCH_MX31
+const struct imx_spi_imx_data imx31_cspi_data[] __initconst = {
+#define imx31_cspi_data_entry(_id, _hwid)                              \
+       imx_spi_imx_data_entry(MX31, CSPI, "imx31-cspi", _id, _hwid, SZ_4K)
+       imx31_cspi_data_entry(0, 1),
+       imx31_cspi_data_entry(1, 2),
+       imx31_cspi_data_entry(2, 3),
+};
+#endif /* ifdef CONFIG_ARCH_MX31 */
+
+#ifdef CONFIG_ARCH_MX35
+const struct imx_spi_imx_data imx35_cspi_data[] __initconst = {
+#define imx35_cspi_data_entry(_id, _hwid)                           \
+       imx_spi_imx_data_entry(MX35, CSPI, "imx35-cspi", _id, _hwid, SZ_4K)
+       imx35_cspi_data_entry(0, 1),
+       imx35_cspi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX35 */
+
+#ifdef CONFIG_ARCH_MX51
+const struct imx_spi_imx_data imx51_cspi_data __initconst =
+       imx_spi_imx_data_entry_single(MX51, CSPI, "imx51-cspi", 0, , SZ_4K);
+
+const struct imx_spi_imx_data imx51_ecspi_data[] __initconst = {
+#define imx51_ecspi_data_entry(_id, _hwid)                             \
+       imx_spi_imx_data_entry(MX51, ECSPI, "imx51-ecspi", _id, _hwid, SZ_4K)
+       imx51_ecspi_data_entry(0, 1),
+       imx51_ecspi_data_entry(1, 2),
+};
+#endif /* ifdef CONFIG_ARCH_MX51 */
+
+struct platform_device *__init imx_add_spi_imx(
+               const struct imx_spi_imx_data *data,
                const struct spi_imx_master *pdata)
 {
        struct resource res[] = {
                {
-                       .start = iobase,
-                       .end = iobase + iosize - 1,
+                       .start = data->iobase,
+                       .end = data->iobase + data->iosize - 1,
                        .flags = IORESOURCE_MEM,
                }, {
-                       .start = irq,
-                       .end = irq,
+                       .start = data->irq,
+                       .end = data->irq,
                        .flags = IORESOURCE_IRQ,
                },
        };
 
-       return imx_add_platform_device("spi_imx", id, res, ARRAY_SIZE(res),
-                       pdata, sizeof(*pdata));
+       return imx_add_platform_device(data->devid, data->id,
+                       res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
 }
index 35a064ff02ba61a66b4f0425728baa4b7f74cda6..9915607683de39e08d1145b115bd289fec360da2 100644 (file)
@@ -249,8 +249,8 @@ int mxc_initialize_usb_hw(int port, unsigned int flags)
 #ifdef CONFIG_ARCH_MX51
        if (cpu_is_mx51()) {
                void __iomem *usb_base;
-               u32 usbotg_base;
-               u32 usbother_base;
+               void __iomem *usbotg_base;
+               void __iomem *usbother_base;
                int ret = 0;
 
                usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K);
diff --git a/arch/arm/plat-mxc/epit.c b/arch/arm/plat-mxc/epit.c
new file mode 100644 (file)
index 0000000..ee9582f
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ *  linux/arch/arm/plat-mxc/epit.c
+ *
+ *  Copyright (C) 2010 Sascha Hauer <s.hauer@pengutronix.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.
+ */
+
+#define EPITCR         0x00
+#define EPITSR         0x04
+#define EPITLR         0x08
+#define EPITCMPR       0x0c
+#define EPITCNR                0x10
+
+#define EPITCR_EN                      (1 << 0)
+#define EPITCR_ENMOD                   (1 << 1)
+#define EPITCR_OCIEN                   (1 << 2)
+#define EPITCR_RLD                     (1 << 3)
+#define EPITCR_PRESC(x)                        (((x) & 0xfff) << 4)
+#define EPITCR_SWR                     (1 << 16)
+#define EPITCR_IOVW                    (1 << 17)
+#define EPITCR_DBGEN                   (1 << 18)
+#define EPITCR_WAITEN                  (1 << 19)
+#define EPITCR_RES                     (1 << 20)
+#define EPITCR_STOPEN                  (1 << 21)
+#define EPITCR_OM_DISCON               (0 << 22)
+#define EPITCR_OM_TOGGLE               (1 << 22)
+#define EPITCR_OM_CLEAR                        (2 << 22)
+#define EPITCR_OM_SET                  (3 << 22)
+#define EPITCR_CLKSRC_OFF              (0 << 24)
+#define EPITCR_CLKSRC_PERIPHERAL       (1 << 24)
+#define EPITCR_CLKSRC_REF_HIGH         (1 << 24)
+#define EPITCR_CLKSRC_REF_LOW          (3 << 24)
+
+#define EPITSR_OCIF                    (1 << 0)
+
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+
+#include <mach/hardware.h>
+#include <asm/mach/time.h>
+#include <mach/common.h>
+
+static struct clock_event_device clockevent_epit;
+static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
+
+static void __iomem *timer_base;
+
+static inline void epit_irq_disable(void)
+{
+       u32 val;
+
+       val = __raw_readl(timer_base + EPITCR);
+       val &= ~EPITCR_OCIEN;
+       __raw_writel(val, timer_base + EPITCR);
+}
+
+static inline void epit_irq_enable(void)
+{
+       u32 val;
+
+       val = __raw_readl(timer_base + EPITCR);
+       val |= EPITCR_OCIEN;
+       __raw_writel(val, timer_base + EPITCR);
+}
+
+static void epit_irq_acknowledge(void)
+{
+       __raw_writel(EPITSR_OCIF, timer_base + EPITSR);
+}
+
+static cycle_t epit_read(struct clocksource *cs)
+{
+       return 0 - __raw_readl(timer_base + EPITCNR);
+}
+
+static struct clocksource clocksource_epit = {
+       .name           = "epit",
+       .rating         = 200,
+       .read           = epit_read,
+       .mask           = CLOCKSOURCE_MASK(32),
+       .shift          = 20,
+       .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init epit_clocksource_init(struct clk *timer_clk)
+{
+       unsigned int c = clk_get_rate(timer_clk);
+
+       clocksource_epit.mult = clocksource_hz2mult(c,
+                                       clocksource_epit.shift);
+       clocksource_register(&clocksource_epit);
+
+       return 0;
+}
+
+/* clock event */
+
+static int epit_set_next_event(unsigned long evt,
+                             struct clock_event_device *unused)
+{
+       unsigned long tcmp;
+
+       tcmp = __raw_readl(timer_base + EPITCNR);
+
+       __raw_writel(tcmp - evt, timer_base + EPITCMPR);
+
+       return 0;
+}
+
+static void epit_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 epit_set_next_event()
+        */
+       local_irq_save(flags);
+
+       /* Disable interrupt in GPT module */
+       epit_irq_disable();
+
+       if (mode != clockevent_mode) {
+               /* Set event time into far-far future */
+
+               /* Clear pending interrupt */
+               epit_irq_acknowledge();
+       }
+
+       /* Remember timer mode */
+       clockevent_mode = mode;
+       local_irq_restore(flags);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_PERIODIC:
+               printk(KERN_ERR "epit_set_mode: Periodic mode is not "
+                               "supported for i.MX EPIT\n");
+               break;
+       case CLOCK_EVT_MODE_ONESHOT:
+       /*
+        * Do not put overhead of interrupt enable/disable into
+        * epit_set_next_event(), the core has about 4 minutes
+        * to call epit_set_next_event() or shutdown clock after
+        * mode switching
+        */
+               local_irq_save(flags);
+               epit_irq_enable();
+               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 appear */
+               break;
+       }
+}
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t epit_timer_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *evt = &clockevent_epit;
+
+       epit_irq_acknowledge();
+
+       evt->event_handler(evt);
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction epit_timer_irq = {
+       .name           = "i.MX EPIT Timer Tick",
+       .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+       .handler        = epit_timer_interrupt,
+};
+
+static struct clock_event_device clockevent_epit = {
+       .name           = "epit",
+       .features       = CLOCK_EVT_FEAT_ONESHOT,
+       .shift          = 32,
+       .set_mode       = epit_set_mode,
+       .set_next_event = epit_set_next_event,
+       .rating         = 200,
+};
+
+static int __init epit_clockevent_init(struct clk *timer_clk)
+{
+       unsigned int c = clk_get_rate(timer_clk);
+
+       clockevent_epit.mult = div_sc(c, NSEC_PER_SEC,
+                                       clockevent_epit.shift);
+       clockevent_epit.max_delta_ns =
+                       clockevent_delta2ns(0xfffffffe, &clockevent_epit);
+       clockevent_epit.min_delta_ns =
+                       clockevent_delta2ns(0x800, &clockevent_epit);
+
+       clockevent_epit.cpumask = cpumask_of(0);
+
+       clockevents_register_device(&clockevent_epit);
+
+       return 0;
+}
+
+void __init epit_timer_init(struct clk *timer_clk, void __iomem *base, int irq)
+{
+       clk_enable(timer_clk);
+
+       timer_base = base;
+
+       /*
+        * Initialise to a known state (all timers off, and timing reset)
+        */
+       __raw_writel(0x0, timer_base + EPITCR);
+
+       __raw_writel(0xffffffff, timer_base + EPITLR);
+       __raw_writel(EPITCR_EN | EPITCR_CLKSRC_REF_HIGH | EPITCR_WAITEN,
+                       timer_base + EPITCR);
+
+       /* init and register the timer to the framework */
+       epit_clocksource_init(timer_clk);
+       epit_clockevent_init(timer_clk);
+
+       /* Make irqs happen */
+       setup_irq(irq, &epit_timer_irq);
+}
index 57ec4a896a5d983556ebae058dbf52293ebe669e..9d38da077edb121cfbcb065322be5e7251975463 100644 (file)
@@ -235,7 +235,7 @@ static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        unsigned long flags;
 
        spin_lock_irqsave(&port->lock, flags);
-       l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset);
+       l = (__raw_readl(reg) & (~(1 << offset))) | (!!value << offset);
        __raw_writel(l, reg);
        spin_unlock_irqrestore(&port->lock, flags);
 }
diff --git a/arch/arm/plat-mxc/include/mach/board-mx31ads.h b/arch/arm/plat-mxc/include/mach/board-mx31ads.h
new file mode 100644 (file)
index 0000000..94b60dd
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARCH_MXC_BOARD_MX31ADS_H__
+#define __ASM_ARCH_MXC_BOARD_MX31ADS_H__
+
+#include <mach/hardware.h>
+
+/*
+ * These symbols are used by drivers/net/cs89x0.c.
+ * This is ugly as hell, but we have to provide them until
+ * someone fixed the driver.
+ */
+
+/* Base address of PBC controller */
+#define PBC_BASE_ADDRESS        MX31_CS4_BASE_ADDR_VIRT
+/* Offsets for the PBC Controller register */
+
+/* Ethernet Controller IO base address */
+#define PBC_CS8900A_IOBASE      0x020000
+
+#define MXC_EXP_IO_BASE                (MXC_BOARD_IRQ_START)
+
+#define EXPIO_INT_ENET_INT     (MXC_EXP_IO_BASE + 8)
+
+#endif /* __ASM_ARCH_MXC_BOARD_MX31ADS_H__ */
index 2941472582d2a2e63e08627bdd0abd97792c698c..7a1e1f89ff0934f36eeebd0dae3b5e0c356a8ea5 100644 (file)
@@ -32,6 +32,7 @@ extern void mx31_init_irq(void);
 extern void mx35_init_irq(void);
 extern void mx51_init_irq(void);
 extern void mxc91231_init_irq(void);
+extern void epit_timer_init(struct clk *timer_clk, void __iomem *base, int irq);
 extern void mxc_timer_init(struct clk *timer_clk, void __iomem *, int);
 extern int mx1_clocks_init(unsigned long fref);
 extern int mx21_clocks_init(unsigned long lref, unsigned long fref);
index 25606409aabcfb7de02a3dbce55e7221b68d2ece..d56213fb901ba14e54be3a1dba0963b42ffc1183 100644 (file)
 #define UART_PADDR     MXC91231_UART2_BASE_ADDR
 #define UART_VADDR     MXC91231_IO_ADDRESS(MXC91231_UART2_BASE_ADDR)
 #endif
-               .macro  addruart, rx, tmp
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                 @ MMU enabled?
-               ldreq   \rx, =UART_PADDR        @ physical
-               ldrne   \rx, =UART_VADDR        @ virtual
+               .macro  addruart, rp, rv
+               ldr     \rp, =UART_PADDR        @ physical
+               ldr     \rv, =UART_VADDR        @ virtual
                .endm
 
                .macro  senduart,rd,rx
index c5f68c587309e2f37949f61c540fcf7826587f70..86d7575a564dba0c550e93d668fe35e0b44b1dff 100644 (file)
@@ -14,47 +14,105 @@ struct platform_device *imx_add_platform_device(const char *name, int id,
                const struct resource *res, unsigned int num_resources,
                const void *data, size_t size_data);
 
-#if defined (CONFIG_CAN_FLEXCAN) || defined (CONFIG_CAN_FLEXCAN_MODULE)
+#include <linux/fec.h>
+struct imx_fec_data {
+       resource_size_t iobase;
+       resource_size_t irq;
+};
+struct platform_device *__init imx_add_fec(
+               const struct imx_fec_data *data,
+               const struct fec_platform_data *pdata);
+
 #include <linux/can/platform/flexcan.h>
 struct platform_device *__init imx_add_flexcan(int id,
                resource_size_t iobase, resource_size_t iosize,
                resource_size_t irq,
                const struct flexcan_platform_data *pdata);
-#else
-/* the ifdef can be removed once the flexcan driver has been merged */
-struct flexcan_platform_data;
-static inline struct platform_device *__init imx_add_flexcan(int id,
-               resource_size_t iobase, resource_size_t iosize,
-               resource_size_t irq,
-               const struct flexcan_platform_data *pdata)
-{
-       return NULL;
-}
-#endif
 
 #include <mach/i2c.h>
-struct platform_device *__init imx_add_imx_i2c(int id,
-               resource_size_t iobase, resource_size_t iosize, int irq,
+struct imx_imx_i2c_data {
+       int id;
+       resource_size_t iobase;
+       resource_size_t iosize;
+       resource_size_t irq;
+};
+struct platform_device *__init imx_add_imx_i2c(
+               const struct imx_imx_i2c_data *data,
                const struct imxi2c_platform_data *pdata);
 
+#include <mach/ssi.h>
+struct imx_imx_ssi_data {
+       int id;
+       resource_size_t iobase;
+       resource_size_t iosize;
+       resource_size_t irq;
+       resource_size_t dmatx0;
+       resource_size_t dmarx0;
+       resource_size_t dmatx1;
+       resource_size_t dmarx1;
+};
+struct platform_device *__init imx_add_imx_ssi(
+               const struct imx_imx_ssi_data *data,
+               const struct imx_ssi_platform_data *pdata);
+
 #include <mach/imx-uart.h>
-struct platform_device *__init imx_add_imx_uart_3irq(int id,
-               resource_size_t iobase, resource_size_t iosize,
-               resource_size_t irqrx, resource_size_t irqtx,
-               resource_size_t irqrts,
+struct imx_imx_uart_3irq_data {
+       int id;
+       resource_size_t iobase;
+       resource_size_t iosize;
+       resource_size_t irqrx;
+       resource_size_t irqtx;
+       resource_size_t irqrts;
+};
+struct platform_device *__init imx_add_imx_uart_3irq(
+               const struct imx_imx_uart_3irq_data *data,
                const struct imxuart_platform_data *pdata);
-struct platform_device *__init imx_add_imx_uart_1irq(int id,
-               resource_size_t iobase, resource_size_t iosize,
-               resource_size_t irq,
+
+struct imx_imx_uart_1irq_data {
+       int id;
+       resource_size_t iobase;
+       resource_size_t iosize;
+       resource_size_t irq;
+};
+struct platform_device *__init imx_add_imx_uart_1irq(
+               const struct imx_imx_uart_1irq_data *data,
                const struct imxuart_platform_data *pdata);
 
 #include <mach/mxc_nand.h>
-struct platform_device *__init imx_add_mxc_nand_v1(resource_size_t iobase,
-               int irq, const struct mxc_nand_platform_data *pdata);
-struct platform_device *__init imx_add_mxc_nand_v21(resource_size_t iobase,
-               int irq, const struct mxc_nand_platform_data *pdata);
+struct imx_mxc_nand_data {
+       /*
+        * id is traditionally 0, but -1 is more appropriate.  We use -1 for new
+        * machines but don't change existing devices as the nand device usually
+        * appears in the kernel command line to pass its partitioning.
+        */
+       int id;
+       resource_size_t iobase;
+       resource_size_t iosize;
+       resource_size_t axibase;
+       resource_size_t irq;
+};
+struct platform_device *__init imx_add_mxc_nand(
+               const struct imx_mxc_nand_data *data,
+               const struct mxc_nand_platform_data *pdata);
 
 #include <mach/spi.h>
-struct platform_device *__init imx_add_spi_imx(int id,
-               resource_size_t iobase, resource_size_t iosize, int irq,
+struct imx_spi_imx_data {
+       const char *devid;
+       int id;
+       resource_size_t iobase;
+       resource_size_t iosize;
+       int irq;
+};
+struct platform_device *__init imx_add_spi_imx(
+               const struct imx_spi_imx_data *data,
                const struct spi_imx_master *pdata);
+
+#include <mach/esdhc.h>
+struct imx_esdhc_imx_data {
+       int id;
+       resource_size_t iobase;
+       resource_size_t irq;
+};
+struct platform_device *__init imx_add_esdhc(
+               const struct imx_esdhc_imx_data *data,
+               const struct esdhc_platform_data *pdata);
diff --git a/arch/arm/plat-mxc/include/mach/esdhc.h b/arch/arm/plat-mxc/include/mach/esdhc.h
new file mode 100644 (file)
index 0000000..a48a9aa
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2010 Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#ifndef __ASM_ARCH_IMX_ESDHC_H
+#define __ASM_ARCH_IMX_ESDHC_H
+
+struct esdhc_platform_data {
+       unsigned int wp_gpio;   /* write protect pin */
+};
+#endif /* __ASM_ARCH_IMX_ESDHC_H */
index 656acb45d434b7333e0864798fb6b69538387701..a21d3313f9942eeb5233e74490d2f68c78ae1b4b 100644 (file)
  * its own devices, it calls baseboard's init function.
  * TODO: Add your own baseboard init function and call it from
  * inside eukrea_cpuimx25_init() eukrea_cpuimx27_init()
- * eukrea_cpuimx35_init() or eukrea_cpuimx51_init().
+ * eukrea_cpuimx35_init() eukrea_cpuimx51_init()
+ * or eukrea_cpuimx51sd_init().
  *
  * This example here is for the development board. Refer
  * mach-mx25/eukrea_mbimxsd-baseboard.c for cpuimx25
  * mach-imx/eukrea_mbimx27-baseboard.c for cpuimx27
  * mach-mx3/eukrea_mbimxsd-baseboard.c for cpuimx35
  * mach-mx5/eukrea_mbimx51-baseboard.c for cpuimx51
+ * mach-mx5/eukrea_mbimxsd-baseboard.c for cpuimx51sd
  */
 
 extern void eukrea_mbimxsd25_baseboard_init(void);
 extern void eukrea_mbimx27_baseboard_init(void);
 extern void eukrea_mbimxsd35_baseboard_init(void);
 extern void eukrea_mbimx51_baseboard_init(void);
+extern void eukrea_mbimxsd51_baseboard_init(void);
 
 #endif
 
index 21bfa46785bb5254e16ed1cfd8f36d7e384dbfcc..e46b1c2836d4c6d42a095eeae4a06ccc15f8d896 100644 (file)
@@ -45,6 +45,18 @@ typedef enum iomux_config {
                                PAD_CTL_PKE | PAD_CTL_HYS)
 #define MX51_GPIO_PAD_CTRL             (PAD_CTL_DSE_HIGH | PAD_CTL_PKE | \
                                PAD_CTL_SRE_FAST)
+#define MX51_ECSPI_PAD_CTRL    (PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_DSE_HIGH | \
+                               PAD_CTL_SRE_FAST)
+#define MX51_SDHCI_PAD_CTRL    (PAD_CTL_DSE_HIGH | PAD_CTL_PUS_47K_UP | \
+                               PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_SRE_FAST | \
+                               PAD_CTL_DVS)
+
+#define MX51_PAD_CTRL_1        (PAD_CTL_SRE_FAST | PAD_CTL_DSE_HIGH | \
+                                       PAD_CTL_PUE | PAD_CTL_PKE | PAD_CTL_HYS)
+#define MX51_PAD_CTRL_2        (PAD_CTL_HYS | PAD_CTL_PKE)
+#define MX51_PAD_CTRL_3        (PAD_CTL_PKE | PAD_CTL_PUS_100K_UP)
+#define MX51_PAD_CTRL_4        (PAD_CTL_DVS | PAD_CTL_HYS | PAD_CTL_PKE)
+#define MX51_PAD_CTRL_5        (PAD_CTL_DVS | PAD_CTL_DSE_HIGH)
 
 /*
  * The naming convention for the pad modes is MX51_PAD_<padname>__<padmode>
@@ -106,14 +118,20 @@ typedef enum iomux_config {
 #define MX51_PAD_EIM_EB0__EIM_EB0               IOMUX_PAD(0x460, 0x0cc, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_EB1__EIM_EB1               IOMUX_PAD(0x464, 0x0d0, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_EB2__GPIO_2_22             IOMUX_PAD(0x468, 0x0d4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_EB2__FEC_MDIO             IOMUX_PAD(0x468, 0x0d4, 3, 0x0,   0, MX51_PAD_CTRL_1 | PAD_CTL_PUS_22K_UP)
 #define MX51_PAD_EIM_EB3__GPIO_2_23             IOMUX_PAD(0x46c, 0x0d8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_EB3__FEC_RDAT1            IOMUX_PAD(0x46c, 0x0d8, 3, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_EIM_OE__GPIO_2_24              IOMUX_PAD(0x470, 0x0dc, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_CS0__GPIO_2_25             IOMUX_PAD(0x474, 0x0e0, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_CS1__GPIO_2_26             IOMUX_PAD(0x478, 0x0e4, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_CS2__GPIO_2_27             IOMUX_PAD(0x47c, 0x0e8, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS2__FEC_RDAT2            IOMUX_PAD(0x47c, 0x0e8, 3, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_EIM_CS3__GPIO_2_28             IOMUX_PAD(0x480, 0x0ec, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS3__FEC_RDAT3            IOMUX_PAD(0x480, 0x0ec, 3, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_EIM_CS4__GPIO_2_29             IOMUX_PAD(0x484, 0x0f0, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS4__FEC_RX_ER            IOMUX_PAD(0x484, 0x0f0, 3, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_EIM_CS5__GPIO_2_30             IOMUX_PAD(0x488, 0x0f4, 1, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_CS5__FEC_CRS              IOMUX_PAD(0x488, 0x0f4, 3, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_EIM_DTACK__GPIO_2_31           IOMUX_PAD(0x48c, 0x0f8, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_LBA__GPIO_3_1              IOMUX_PAD(0x494, 0x0FC, 1, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_EIM_CRE__GPIO_3_2              IOMUX_PAD(0x4A0, 0x100, 1, 0x0,   0, NO_PAD_CTRL)
@@ -126,18 +144,32 @@ typedef enum iomux_config {
 #define MX51_PAD_NANDF_RB0__GPIO_3_8            IOMUX_PAD(0x4F8, 0x11C, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB1__GPIO_3_9            IOMUX_PAD(0x4FC, 0x120, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_RB2__GPIO_3_10           IOMUX_PAD(0x500, 0x124, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB2__ECSPI2_SCLK         IOMUX_PAD(0x500, 0x124, 2, 0x0,   0, MX51_ECSPI_PAD_CTRL)
+#define MX51_PAD_NANDF_RB2__FEC_COL            IOMUX_PAD(0x500, 0x124, 1, 0x0,   0, MX51_PAD_CTRL_2)
 #define MX51_PAD_NANDF_RB3__GPIO_3_11           IOMUX_PAD(0x504, 0x128, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RB3__ECSPI2_MISO         IOMUX_PAD(0x504, 0x128, 2, 0x0,   0, MX51_ECSPI_PAD_CTRL)
+#define MX51_PAD_NANDF_RB3__FEC_RXCLK          IOMUX_PAD(0x504, 0x128, 1, 0x0,   0, MX51_PAD_CTRL_2)
+#define MX51_PAD_NANDF_RB6__FEC_RDAT0          IOMUX_PAD(0x5DC, 0x134, 1, 0x0,   0, MX51_PAD_CTRL_4)
+#define MX51_PAD_NANDF_RB7__FEC_TDAT0          IOMUX_PAD(0x5E0, 0x138, 1, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_GPIO_NAND__GPIO_3_12           IOMUX_PAD(0x514, 0x12C, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS0__GPIO_3_16           IOMUX_PAD(0x518, 0x130, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS1__GPIO_3_17           IOMUX_PAD(0x51C, 0x134, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_CS2__GPIO_3_18           IOMUX_PAD(0x520, 0x138, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS2__FEC_TX_ER          IOMUX_PAD(0x520, 0x138, 2, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS3__GPIO_3_19           IOMUX_PAD(0x524, 0x13C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS3__FEC_MDC            IOMUX_PAD(0x524, 0x13C, 2, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS4__GPIO_3_20           IOMUX_PAD(0x528, 0x140, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS4__FEC_TDAT1          IOMUX_PAD(0x528, 0x140, 2, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS5__GPIO_3_21           IOMUX_PAD(0x52C, 0x144, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS5__FEC_TDAT2          IOMUX_PAD(0x52C, 0x144, 2, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS6__GPIO_3_22           IOMUX_PAD(0x530, 0x148, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS6__FEC_TDAT3          IOMUX_PAD(0x530, 0x148, 2, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_CS7__GPIO_3_23           IOMUX_PAD(0x534, 0x14C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_CS7__FEC_TX_EN          IOMUX_PAD(0x534, 0x14C, 1, 0x0,   0, MX51_PAD_CTRL_5)
 #define MX51_PAD_NANDF_RDY_INT__GPIO_3_24       IOMUX_PAD(0x538, 0x150, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK     IOMUX_PAD(0x538, 0x150, 1, 0x0,   0, MX51_PAD_CTRL_4)
 #define MX51_PAD_NANDF_D15__GPIO_3_25           IOMUX_PAD(0x53C, 0x154, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_NANDF_D15__ECSPI2_MOSI         IOMUX_PAD(0x53C, 0x154, 2, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_NANDF_D14__GPIO_3_26           IOMUX_PAD(0x540, 0x158, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_D13__GPIO_3_27           IOMUX_PAD(0x544, 0x15C, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_NANDF_D12__GPIO_3_28           IOMUX_PAD(0x548, 0x160, 3, 0x0,   0, NO_PAD_CTRL)
@@ -185,15 +217,25 @@ typedef enum iomux_config {
 #define MX51_PAD_I2C1_CLK__HSI2C_CLK           IOMUX_PAD(0x5E8, 0x1F8, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_I2C1_DAT__GPIO_4_17            IOMUX_PAD(0x5EC, 0x1FC, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_I2C1_DAT__HSI2C_DAT           IOMUX_PAD(0x5EC, 0x1FC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_TXD__AUD3_BB_TXD       IOMUX_PAD(0x5F0, 0x200, IOMUX_CONFIG_SION, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_AUD3_BB_TXD__GPIO_4_18         IOMUX_PAD(0x5F0, 0x200, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_RXD__AUD3_BB_RXD       IOMUX_PAD(0x5F4, 0x204, IOMUX_CONFIG_SION, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_AUD3_BB_RXD__GPIO_4_19         IOMUX_PAD(0x5F4, 0x204, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_CK__AUD3_BB_CK         IOMUX_PAD(0x5F8, 0x208, IOMUX_CONFIG_SION, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_AUD3_BB_CK__GPIO_4_20          IOMUX_PAD(0x5F8, 0x208, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_AUD3_BB_FS__AUD3_BB_FS         IOMUX_PAD(0x5FC, 0x20C, IOMUX_CONFIG_SION, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_AUD3_BB_FS__GPIO_4_21          IOMUX_PAD(0x5FC, 0x20C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI        IOMUX_PAD(0x600, 0x210, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_MOSI__GPIO_4_22          IOMUX_PAD(0x600, 0x210, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_MISO__ECSPI1_MISO        IOMUX_PAD(0x604, 0x214, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_MISO__GPIO_4_23          IOMUX_PAD(0x604, 0x214, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_SS0__ECSPI1_SS0          IOMUX_PAD(0x608, 0x218, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_SS0__GPIO_4_24           IOMUX_PAD(0x608, 0x218, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_SS1__ECSPI1_SS1          IOMUX_PAD(0x60C, 0x21C, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_SS1__GPIO_4_25           IOMUX_PAD(0x60C, 0x21C, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_RDY__ECSPI1_RDY          IOMUX_PAD(0x610, 0x220, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_RDY__GPIO_4_26           IOMUX_PAD(0x610, 0x220, 3, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK        IOMUX_PAD(0x614, 0x224, 0, 0x0,   0, MX51_ECSPI_PAD_CTRL)
 #define MX51_PAD_CSPI1_SCLK__GPIO_4_27          IOMUX_PAD(0x614, 0x224, 3, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_UART1_RXD__UART1_RXD           IOMUX_PAD(0x618, 0x228, 0, 0x9e4, 0, MX51_UART1_PAD_CTRL | PAD_CTL_SRE_FAST)
 #define MX51_PAD_UART1_TXD__UART1_TXD           IOMUX_PAD(0x61C, 0x22C, 0, 0x0,   0, MX51_UART1_PAD_CTRL | PAD_CTL_SRE_FAST)
@@ -236,14 +278,14 @@ typedef enum iomux_config {
 #define MX51_PAD_USBH1_DATA6__USBH1_DATA6       IOMUX_PAD(0x6A0, 0x2A0, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
 #define MX51_PAD_USBH1_DATA7__USBH1_DATA7       IOMUX_PAD(0x6A4, 0x2A4, 0, 0x0,   0, MX51_USBH1_PAD_CTRL)
 #define MX51_PAD_DI1_PIN11__GPIO_3_0            IOMUX_PAD(0x6A8, 0x2A8, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DI1_PIN12__GPIO_3_1            IOMUX_PAD(0x6AC, 0x2AC, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DI1_PIN13__GPIO_3_2            IOMUX_PAD(0x6B0, 0x2B0, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DI1_D0_CS__GPIO_3_3            IOMUX_PAD(0x6B4, 0x2B4, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DI1_D1_CS__GPIO_3_4            IOMUX_PAD(0x6B8, 0x2B8, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DISPB2_SER_DIN__GPIO_3_5       IOMUX_PAD(0x6BC, 0x2BC, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DISPB2_SER_DIO__GPIO_3_6       IOMUX_PAD(0x6C0, 0x2C0, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DISPB2_SER_CLK__GPIO_3_7       IOMUX_PAD(0x6C4, 0x2C4, 4, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_DISPB2_SER_RS__GPIO_3_8        IOMUX_PAD(0x6C8, 0x2C8, 4, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_DI1_PIN12__GPIO_3_1            IOMUX_PAD(0x6AC, 0x2AC, 4, 0x978, 1, NO_PAD_CTRL)
+#define MX51_PAD_DI1_PIN13__GPIO_3_2            IOMUX_PAD(0x6B0, 0x2B0, 4, 0x97c, 1, NO_PAD_CTRL)
+#define MX51_PAD_DI1_D0_CS__GPIO_3_3            IOMUX_PAD(0x6B4, 0x2B4, 4, 0x980, 1, NO_PAD_CTRL)
+#define MX51_PAD_DI1_D1_CS__GPIO_3_4            IOMUX_PAD(0x6B8, 0x2B8, 4, 0x984, 1, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_DIN__GPIO_3_5       IOMUX_PAD(0x6BC, 0x2BC, 4, 0x988, 1, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_DIO__GPIO_3_6       IOMUX_PAD(0x6C0, 0x2C0, 4, 0x98c, 1, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_CLK__GPIO_3_7       IOMUX_PAD(0x6C4, 0x2C4, 4, 0x990, 1, NO_PAD_CTRL)
+#define MX51_PAD_DISPB2_SER_RS__GPIO_3_8        IOMUX_PAD(0x6C8, 0x2C8, 4, 0x994, 1, NO_PAD_CTRL)
 #define MX51_PAD_DISP1_DAT0__DISP1_DAT0         IOMUX_PAD(0x6CC, 0x2CC, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_DISP1_DAT1__DISP1_DAT1         IOMUX_PAD(0x6D0, 0x2D0, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_DISP1_DAT2__DISP1_DAT2         IOMUX_PAD(0x6D4, 0x2D4, 0, 0x0,   0, NO_PAD_CTRL)
@@ -294,32 +336,50 @@ typedef enum iomux_config {
 #define MX51_PAD_DISP2_DAT13__DISP2_DAT13       IOMUX_PAD(0x790, 0x388, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT14__DISP2_DAT14       IOMUX_PAD(0x794, 0x38C, 0, 0x0,   0, NO_PAD_CTRL)
 #define MX51_PAD_DISP2_DAT15__DISP2_DAT15       IOMUX_PAD(0x798, 0x390, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_CMD__SD1_CMD               IOMUX_PAD(0x79C, 0x394, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_CLK__SD1_CLK               IOMUX_PAD(0x7A0, 0x398, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA0__SD1_DATA0           IOMUX_PAD(0x7A4, 0x39C, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA1__SD1_DATA1           IOMUX_PAD(0x7A8, 0x3A0, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA2__SD1_DATA2           IOMUX_PAD(0x7AC, 0x3A4, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD1_DATA3__SD1_DATA3           IOMUX_PAD(0x7B0, 0x3A8, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_0__GPIO_1_0            IOMUX_PAD(0x7B4, 0x3AC, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_1__GPIO_1_1            IOMUX_PAD(0x7B8, 0x3B0, 1, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_CMD__SD2_CMD               IOMUX_PAD(0x7BC, 0x3B4, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_CLK__SD2_CLK               IOMUX_PAD(0x7C0, 0x3B8, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA0__SD2_DATA0           IOMUX_PAD(0x7C4, 0x3BC, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA1__SD2_DATA1           IOMUX_PAD(0x7C8, 0x3C0, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA2__SD2_DATA2           IOMUX_PAD(0x7CC, 0x3C4, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_SD2_DATA3__SD2_DATA3           IOMUX_PAD(0x7D0, 0x3C8, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_2__GPIO_1_2            IOMUX_PAD(0x7D4, 0x3CC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_SD1_CMD__SD1_CMD              IOMUX_PAD(0x79C, 0x394, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_CMD__AUD5_RXFS             IOMUX_PAD(0x79C, 0x394, 1, 0x8e0, 1, NO_PAD_CTRL)
+#define MX51_PAD_SD1_CLK__SD1_CLK              IOMUX_PAD(0x7A0, 0x398, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS)
+#define MX51_PAD_SD1_CLK__AUD5_RXC              IOMUX_PAD(0x7A0, 0x398, 1, 0x8dc, 1, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA0__SD1_DATA0          IOMUX_PAD(0x7A4, 0x39C, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA0__AUD5_TXD            IOMUX_PAD(0x7A4, 0x39C, 1, 0x8d8, 2, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA1__SD1_DATA1          IOMUX_PAD(0x7A8, 0x3A0, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA1__AUD5_RXD            IOMUX_PAD(0x7A8, 0x3A0, 1, 0x8d4, 2, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA2__SD1_DATA2          IOMUX_PAD(0x7AC, 0x3A4, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA2__AUD5_TXC            IOMUX_PAD(0x7AC, 0x3A4, 1, 0x8e4, 2, NO_PAD_CTRL)
+#define MX51_PAD_SD1_DATA3__SD1_DATA3          IOMUX_PAD(0x7B0, 0x3A8, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD1_DATA3__AUD5_TXFS           IOMUX_PAD(0x7B0, 0x3A8, 1, 0x8e8, 2, NO_PAD_CTRL)
+#define MX51_PAD_SD2_CMD__SD2_CMD              IOMUX_PAD(0x7BC, 0x3B4, IOMUX_CONFIG_SION, 0x0, 1, \
+                                                       MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_CLK__SD2_CLK              IOMUX_PAD(0x7C0, 0x3B8, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL | PAD_CTL_HYS)
+#define MX51_PAD_SD2_DATA0__SD2_DATA0          IOMUX_PAD(0x7C4, 0x3BC, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_DATA1__SD2_DATA1          IOMUX_PAD(0x7C8, 0x3C0, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_DATA2__SD2_DATA2          IOMUX_PAD(0x7CC, 0x3C4, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_SD2_DATA3__SD2_DATA3          IOMUX_PAD(0x7D0, 0x3C8, IOMUX_CONFIG_SION, 0x0, 0, \
+                                                       MX51_SDHCI_PAD_CTRL)
+#define MX51_PAD_GPIO_1_0__GPIO_1_0            IOMUX_PAD(0x7B4, 0x3AC, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_1__GPIO_1_1            IOMUX_PAD(0x7B8, 0x3B0, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_2__GPIO_1_2            IOMUX_PAD(0x7D4, 0x3CC, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO_1_2__I2C2_SCL            IOMUX_PAD(0x7D4, 0x3CC, (2 | IOMUX_CONFIG_SION), \
                                                        0x9b8,   3, MX51_I2C_PAD_CTRL)
-#define MX51_PAD_GPIO_1_3__GPIO_1_3            IOMUX_PAD(0x7D8, 0x3D0, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_3__GPIO_1_3            IOMUX_PAD(0x7D8, 0x3D0, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
 #define MX51_PAD_GPIO_1_3__I2C2_SDA            IOMUX_PAD(0x7D8, 0x3D0, (2 | IOMUX_CONFIG_SION), \
                                                        0x9bc,   3, MX51_I2C_PAD_CTRL)
 #define MX51_PAD_PMIC_INT_REQ__PMIC_INT_REQ    IOMUX_PAD(0x7FC, 0x3D4, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_4__GPIO_1_4            IOMUX_PAD(0x804, 0x3D8, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_5__GPIO_1_5            IOMUX_PAD(0x808, 0x3DC, 0, 0x0,   0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_6__GPIO_1_6            IOMUX_PAD(0x80C, 0x3E0, 0, 0x0,   0, MX51_GPIO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_7__GPIO_1_7            IOMUX_PAD(0x810, 0x3E4, 0, 0x0,   0, MX51_GPIO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_8__GPIO_1_8            IOMUX_PAD(0x814, 0x3E8, 0, 0x0,   1, MX51_GPIO_PAD_CTRL)
-#define MX51_PAD_GPIO_1_9__GPIO_1_9            IOMUX_PAD(0x818, 0x3EC, 0, 0x0,   0, NO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_4__GPIO_1_4            IOMUX_PAD(0x804, 0x3D8, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_5__GPIO_1_5            IOMUX_PAD(0x808, 0x3DC, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_6__GPIO_1_6            IOMUX_PAD(0x80C, 0x3E0, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_7__GPIO_1_7            IOMUX_PAD(0x810, 0x3E4, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_8__GPIO_1_8            IOMUX_PAD(0x814, 0x3E8, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
+#define MX51_PAD_GPIO_1_9__GPIO_1_9            IOMUX_PAD(0x818, 0x3EC, 1, 0x0,   0, MX51_GPIO_PAD_CTRL)
 
 #endif /* __MACH_IOMUX_MX51_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/iram.h b/arch/arm/plat-mxc/include/mach/iram.h
new file mode 100644 (file)
index 0000000..022690c
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+#include <linux/errno.h>
+
+#ifdef CONFIG_IRAM_ALLOC
+
+int __init iram_init(unsigned long base, unsigned long size);
+void __iomem *iram_alloc(unsigned int size, unsigned long *dma_addr);
+void iram_free(unsigned long dma_addr, unsigned int size);
+
+#else
+
+static inline int __init iram_init(unsigned long base, unsigned long size)
+{
+       return -ENOMEM;
+}
+
+static inline void __iomem *iram_alloc(unsigned int size, unsigned long *dma_addr)
+{
+       return NULL;
+}
+
+static inline void iram_free(unsigned long base, unsigned long size) {}
+
+#endif
index ed98b9c9f389c622db6c3fc9c41c5730852be1f9..8bc59720b6e4be8ed7b52c08bece17cf35c0cfb1 100644 (file)
 #define MX21_INT_GPT1          26
 #define MX21_INT_WDOG          27
 #define MX21_INT_PCMCIA                28
-#define MX21_INT_NANDFC                29
+#define MX21_INT_NFC           29
 #define MX21_INT_BMI           30
 #define MX21_INT_CSI           31
 #define MX21_INT_DMACH0                32
index 4a6f800990f83a826e687ae6a8d8776def7a3689..cf46a45b0d4e54971d3fe829bfc8a7c7942aaebc 100644 (file)
 #define MX25_SSI1_BASE_ADDR            0x50034000
 #define MX25_NFC_BASE_ADDR             0xbb000000
 #define MX25_DRYICE_BASE_ADDR          0x53ffc000
+#define MX25_ESDHC1_BASE_ADDR          0x53fb4000
+#define MX25_ESDHC2_BASE_ADDR          0x53fb8000
 #define MX25_LCDC_BASE_ADDR            0x53fbc000
 #define MX25_KPP_BASE_ADDR             0x43fa8000
+#define MX25_SDMA_BASE_ADDR            0x53fd4000
 #define MX25_OTG_BASE_ADDR             0x53ff4000
 #define MX25_CSI_BASE_ADDR             0x53ff8000
 
@@ -59,6 +62,8 @@
 #define MX25_INT_I2C1          3
 #define MX25_INT_I2C2          4
 #define MX25_INT_UART4         5
+#define MX25_INT_ESDHC2                8
+#define MX25_INT_ESDHC1                9
 #define MX25_INT_I2C3          10
 #define MX25_INT_SSI2          11
 #define MX25_INT_SSI1          12
@@ -69,7 +74,8 @@
 #define MX25_INT_KPP           24
 #define MX25_INT_DRYICE                25
 #define MX25_INT_UART2         32
-#define MX25_INT_NANDFC                33
+#define MX25_INT_NFC           33
+#define MX25_INT_SDMA          34
 #define MX25_INT_LCDC          39
 #define MX25_INT_UART5         40
 #define MX25_INT_CAN1          43
 #define MX25_INT_UART1         45
 #define MX25_INT_FEC           57
 
+#define MX25_DMA_REQ_SSI2_RX1  22
+#define MX25_DMA_REQ_SSI2_TX1  23
+#define MX25_DMA_REQ_SSI2_RX0  24
+#define MX25_DMA_REQ_SSI2_TX0  25
+#define MX25_DMA_REQ_SSI1_RX1  26
+#define MX25_DMA_REQ_SSI1_TX1  27
+#define MX25_DMA_REQ_SSI1_RX0  28
+#define MX25_DMA_REQ_SSI1_TX0  29
+
 #endif /* ifndef __MACH_MX25_H__ */
index a8ab2e02a8caf36460591865237e6d6c34d534de..2237ba2e53519230f2d8986af241558b6822925c 100644 (file)
@@ -167,7 +167,7 @@ static inline void mx27_setup_weimcs(size_t cs,
 #define MX27_INT_GPT1          26
 #define MX27_INT_WDOG          27
 #define MX27_INT_PCMCIA                28
-#define MX27_INT_NANDFC                29
+#define MX27_INT_NFC           29
 #define MX27_INT_ATA           30
 #define MX27_INT_CSI           31
 #define MX27_INT_DMACH0                32
index afee3ab9d62e2aef32a366f21c82350a562dab22..03e2afabc9fc15b662e1bc444c3ff6df4890f519 100644 (file)
@@ -168,7 +168,7 @@ static inline void mx31_setup_weimcs(size_t cs,
 #define MX31_INT_POWER_FAIL    30
 #define MX31_INT_CCM_DVFS      31
 #define MX31_INT_UART2         32
-#define MX31_INT_NANDFC                33
+#define MX31_INT_NFC           33
 #define MX31_INT_SDMA          34
 #define MX31_INT_USB1          35
 #define MX31_INT_USB2          36
@@ -197,6 +197,15 @@ static inline void mx31_setup_weimcs(size_t cs,
 #define MX31_INT_EXT_WDOG      62
 #define MX31_INT_EXT_TV                63
 
+#define MX31_DMA_REQ_SSI2_RX1  22
+#define MX31_DMA_REQ_SSI2_TX1  23
+#define MX31_DMA_REQ_SSI2_RX0  24
+#define MX31_DMA_REQ_SSI2_TX0  25
+#define MX31_DMA_REQ_SSI1_RX1  26
+#define MX31_DMA_REQ_SSI1_TX1  27
+#define MX31_DMA_REQ_SSI1_RX0  28
+#define MX31_DMA_REQ_SSI1_TX0  29
+
 #define MX31_PROD_SIGNATURE            0x1     /* For MX31 */
 
 /* silicon revisions specific to i.MX31 */
index af3038c12e39c03b16d00855e5f5f40b75ba9b97..ff905cb324589f6c163aa9cd2d7996a017afe6bc 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef __MACH_MX35_H__
 #define __MACH_MX35_H__
+
 /*
  * IRAM
  */
@@ -52,6 +53,9 @@
 #define MX35_GPIO3_BASE_ADDR                   (MX35_AIPS2_BASE_ADDR + 0xa4000)
 #define MX35_SCC_BASE_ADDR                     (MX35_AIPS2_BASE_ADDR + 0xac000)
 #define MX35_RNGA_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xb0000)
+#define MX35_ESDHC1_BASE_ADDR                  (MX35_AIPS2_BASE_ADDR + 0xb4000)
+#define MX35_ESDHC2_BASE_ADDR                  (MX35_AIPS2_BASE_ADDR + 0xb8000)
+#define MX35_ESDHC3_BASE_ADDR                  (MX35_AIPS2_BASE_ADDR + 0xbc000)
 #define MX35_IPU_CTRL_BASE_ADDR                        (MX35_AIPS2_BASE_ADDR + 0xc0000)
 #define MX35_AUDMUX_BASE_ADDR                  (MX35_AIPS2_BASE_ADDR + 0xc4000)
 #define MX35_GPIO1_BASE_ADDR                   (MX35_AIPS2_BASE_ADDR + 0xcc000)
@@ -63,6 +67,8 @@
 #define MX35_CAN1_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xe4000)
 #define MX35_CAN2_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xe8000)
 #define MX35_RTIC_BASE_ADDR                    (MX35_AIPS2_BASE_ADDR + 0xec000)
+#define MX35_IIM_BASE_ADDR                     (MX35_AIPS2_BASE_ADDR + 0xf0000)
+
 #define MX35_OTG_BASE_ADDR             0x53ff4000
 
 #define MX35_ROMP_BASE_ADDR            0x60000000
 #define MX35_INT_I2C3          3
 #define MX35_INT_I2C2          4
 #define MX35_INT_RTIC          6
-#define MX35_INT_MMC_SDHC1     7
-#define MX35_INT_MMC_SDHC2     8
-#define MX35_INT_MMC_SDHC3     9
+#define MX35_INT_ESDHC1                7
+#define MX35_INT_ESDHC2                8
+#define MX35_INT_ESDHC3                9
 #define MX35_INT_I2C1          10
 #define MX35_INT_SSI1          11
 #define MX35_INT_SSI2          12
 #define MX35_INT_GPT           29
 #define MX35_INT_POWER_FAIL    30
 #define MX35_INT_UART2         32
-#define MX35_INT_NANDFC                33
+#define MX35_INT_NFC           33
 #define MX35_INT_SDMA          34
 #define MX35_INT_USBHS         35
 #define MX35_INT_USBOTG                37
 #define MX35_INT_EXT_WDOG      62
 #define MX35_INT_EXT_TV                63
 
+#define MX35_DMA_REQ_SSI2_RX1   22
+#define MX35_DMA_REQ_SSI2_TX1   23
+#define MX35_DMA_REQ_SSI2_RX0   24
+#define MX35_DMA_REQ_SSI2_TX0   25
+#define MX35_DMA_REQ_SSI1_RX1   26
+#define MX35_DMA_REQ_SSI1_TX1   27
+#define MX35_DMA_REQ_SSI1_RX0   28
+#define MX35_DMA_REQ_SSI1_TX0   29
+
 #define MX35_PROD_SIGNATURE            0x1     /* For MX31 */
 
-/* silicon revisions specific to i.MX31 */
-#define MX35_CHIP_REV_1_0              0x10
-#define MX35_CHIP_REV_1_1              0x11
-#define MX35_CHIP_REV_1_2              0x12
-#define MX35_CHIP_REV_1_3              0x13
-#define MX35_CHIP_REV_2_0              0x20
-#define MX35_CHIP_REV_2_1              0x21
-#define MX35_CHIP_REV_2_2              0x22
-#define MX35_CHIP_REV_2_3              0x23
-#define MX35_CHIP_REV_3_0              0x30
-#define MX35_CHIP_REV_3_1              0x31
-#define MX35_CHIP_REV_3_2              0x32
-
-#define MX35_SYSTEM_REV_MIN            MX35_CHIP_REV_1_0
+#define MX35_SYSTEM_REV_MIN            MX3x_CHIP_REV_1_0
 #define MX35_SYSTEM_REV_NUM            3
 
 #ifdef IMX_NEEDS_DEPRECATED_SYMBOLS
index 7a356de385f5992166bf49861bad48a92f4c244b..d1bd26d7b8a694cb887ef19823a41f94300c5316 100644 (file)
 
 #define MX3x_PROD_SIGNATURE            0x1     /* For MX31 */
 
-/* silicon revisions specific to i.MX31 */
+/* silicon revisions specific to i.MX31 and i.MX35 */
 #define MX3x_CHIP_REV_1_0              0x10
 #define MX3x_CHIP_REV_1_1              0x11
 #define MX3x_CHIP_REV_1_2              0x12
@@ -267,6 +267,14 @@ static inline int mx31_revision(void)
 {
        return mx31_cpu_rev;
 }
+
+extern unsigned int mx35_cpu_rev;
+extern void mx35_read_cpu_rev(void);
+
+static inline int mx35_revision(void)
+{
+       return mx35_cpu_rev;
+}
 #endif
 
 #ifdef IMX_NEEDS_DEPRECATED_SYMBOLS
@@ -389,19 +397,6 @@ static inline int mx31_revision(void)
 #define MXC_INT_EXT_WDOG MX3x_INT_EXT_WDOG
 #define MXC_INT_EXT_TV MX3x_INT_EXT_TV
 #define PROD_SIGNATURE MX3x_PROD_SIGNATURE
-#define CHIP_REV_1_0 MX3x_CHIP_REV_1_0
-#define CHIP_REV_1_1 MX3x_CHIP_REV_1_1
-#define CHIP_REV_1_2 MX3x_CHIP_REV_1_2
-#define CHIP_REV_1_3 MX3x_CHIP_REV_1_3
-#define CHIP_REV_2_0 MX3x_CHIP_REV_2_0
-#define CHIP_REV_2_1 MX3x_CHIP_REV_2_1
-#define CHIP_REV_2_2 MX3x_CHIP_REV_2_2
-#define CHIP_REV_2_3 MX3x_CHIP_REV_2_3
-#define CHIP_REV_3_0 MX3x_CHIP_REV_3_0
-#define CHIP_REV_3_1 MX3x_CHIP_REV_3_1
-#define CHIP_REV_3_2 MX3x_CHIP_REV_3_2
-#define SYSTEM_REV_MIN MX3x_SYSTEM_REV_MIN
-#define SYSTEM_REV_NUM MX3x_SYSTEM_REV_NUM
 #endif
 
 #endif /* ifndef __MACH_MX3x_H__ */
index 5aad344d56515c82a1ef7eaf0dd5e9248e15ab7c..2af7a1056fc17661d69e0ef900349aa317a98eba 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef __ASM_ARCH_MXC_MX51_H__
-#define __ASM_ARCH_MXC_MX51_H__
+#ifndef __MACH_MX51_H__
+#define __MACH_MX51_H__
 
 /*
  * MX51 memory map:
@@ -7,24 +7,23 @@
  *
  * Virt                Phys            Size    What
  * ---------------------------------------------------------------------------
- * FA3E0000    1FFE0000        128K    IRAM (SCCv2 RAM)
+ * fa3e0000    1ffe0000        128K    IRAM (SCCv2 RAM)
  *             30000000        256M    GPU
  *             40000000        512M    IPU
- * FA200000    60000000        1M      DEBUG
- * FB100000    70000000        1M      SPBA 0
- * FB000000    73F00000        1M      AIPS 1
- * FB200000    83F00000        1M      AIPS 2
- *             8FFFC000        16K     TZIC (interrupt controller)
+ * fa200000    60000000        1M      DEBUG
+ * fb100000    70000000        1M      SPBA 0
+ * fb000000    73f00000        1M      AIPS 1
+ * fb200000    83f00000        1M      AIPS 2
+ *             8fffc000        16K     TZIC (interrupt controller)
  *             90000000        256M    CSD0 SDRAM/DDR
- *             A0000000        256M    CSD1 SDRAM/DDR
- *             B0000000        128M    CS0 Flash
- *             B8000000        128M    CS1 Flash
- *             C0000000        128M    CS2 Flash
- *             C8000000        64M     CS3 Flash
- *             CC000000        32M     CS4 SRAM
- *             CE000000        32M     CS5 SRAM
- *             CFFF0000        64K     NFC (NAND Flash AXI)
- *
+ *             a0000000        256M    CSD1 SDRAM/DDR
+ *             b0000000        128M    CS0 Flash
+ *             b8000000        128M    CS1 Flash
+ *             c0000000        128M    CS2 Flash
+ *             c8000000        64M     CS3 Flash
+ *             cc000000        32M     CS4 SRAM
+ *             ce000000        32M     CS5 SRAM
+ *             cfff0000        64K     NFC (NAND Flash AXI)
  */
 
 /*
 /*
  * IRAM
  */
-#define MX51_IRAM_BASE_ADDR            0x1FFE0000      /* internal ram */
-#define MX51_IRAM_BASE_ADDR_VIRT       0xFA3E0000
+#define MX51_IRAM_BASE_ADDR            0x1ffe0000      /* internal ram */
+#define MX51_IRAM_BASE_ADDR_VIRT       0xfa3e0000
 #define MX51_IRAM_PARTITIONS           16
-#define MX51_IRAM_PARTITIONS_TO1       12
 #define MX51_IRAM_SIZE         (MX51_IRAM_PARTITIONS * SZ_8K)  /* 128KB */
 
+#define MX51_GPU_BASE_ADDR             0x20000000
+#define MX51_GPU_CTRL_BASE_ADDR                0x30000000
+#define MX51_IPU_CTRL_BASE_ADDR                0x40000000
+
+#define MX51_DEBUG_BASE_ADDR           0x60000000
+#define MX51_DEBUG_BASE_ADDR_VIRT      0xfa200000
+#define MX51_DEBUG_SIZE                        SZ_1M
+
+#define MX51_ETB_BASE_ADDR             (MX51_DEBUG_BASE_ADDR + 0x01000)
+#define MX51_ETM_BASE_ADDR             (MX51_DEBUG_BASE_ADDR + 0x02000)
+#define MX51_TPIU_BASE_ADDR            (MX51_DEBUG_BASE_ADDR + 0x03000)
+#define MX51_CTI0_BASE_ADDR            (MX51_DEBUG_BASE_ADDR + 0x04000)
+#define MX51_CTI1_BASE_ADDR            (MX51_DEBUG_BASE_ADDR + 0x05000)
+#define MX51_CTI2_BASE_ADDR            (MX51_DEBUG_BASE_ADDR + 0x06000)
+#define MX51_CTI3_BASE_ADDR            (MX51_DEBUG_BASE_ADDR + 0x07000)
+#define MX51_CORTEX_DBG_BASE_ADDR      (MX51_DEBUG_BASE_ADDR + 0x08000)
+
 /*
- * NFC
+ * SPBA global module enabled #0
  */
-#define MX51_NFC_AXI_BASE_ADDR         0xCFFF0000      /* NAND flash AXI */
-#define MX51_NFC_AXI_SIZE              SZ_64K
+#define MX51_SPBA0_BASE_ADDR           0x70000000
+#define MX51_SPBA0_BASE_ADDR_VIRT      0xfb100000
+#define MX51_SPBA0_SIZE                        SZ_1M
+
+#define MX51_ESDHC1_BASE_ADDR          (MX51_SPBA0_BASE_ADDR + 0x04000)
+#define MX51_ESDHC2_BASE_ADDR          (MX51_SPBA0_BASE_ADDR + 0x08000)
+#define MX51_UART3_BASE_ADDR           (MX51_SPBA0_BASE_ADDR + 0x0c000)
+#define MX51_ECSPI1_BASE_ADDR          (MX51_SPBA0_BASE_ADDR + 0x10000)
+#define MX51_SSI2_BASE_ADDR            (MX51_SPBA0_BASE_ADDR + 0x14000)
+#define MX51_ESDHC3_BASE_ADDR          (MX51_SPBA0_BASE_ADDR + 0x20000)
+#define MX51_ESDHC4_BASE_ADDR          (MX51_SPBA0_BASE_ADDR + 0x24000)
+#define MX51_SPDIF_BASE_ADDR           (MX51_SPBA0_BASE_ADDR + 0x28000)
+#define MX51_ATA_DMA_BASE_ADDR         (MX51_SPBA0_BASE_ADDR + 0x30000)
+#define MX51_SLIM_DMA_BASE_ADDR                (MX51_SPBA0_BASE_ADDR + 0x34000)
+#define MX51_HSI2C_DMA_BASE_ADDR       (MX51_SPBA0_BASE_ADDR + 0x38000)
+#define MX51_SPBA_CTRL_BASE_ADDR       (MX51_SPBA0_BASE_ADDR + 0x3c000)
 
 /*
- * Graphics Memory of GPU
+ * AIPS 1
  */
-#define MX51_GPU_BASE_ADDR             0x20000000
-#define MX51_GPU2D_BASE_ADDR           0xD0000000
+#define MX51_AIPS1_BASE_ADDR           0x73f00000
+#define MX51_AIPS1_BASE_ADDR_VIRT      0xfb000000
+#define MX51_AIPS1_SIZE                        SZ_1M
+
+#define MX51_OTG_BASE_ADDR             (MX51_AIPS1_BASE_ADDR + 0x80000)
+#define MX51_GPIO1_BASE_ADDR           (MX51_AIPS1_BASE_ADDR + 0x84000)
+#define MX51_GPIO2_BASE_ADDR           (MX51_AIPS1_BASE_ADDR + 0x88000)
+#define MX51_GPIO3_BASE_ADDR           (MX51_AIPS1_BASE_ADDR + 0x8c000)
+#define MX51_GPIO4_BASE_ADDR           (MX51_AIPS1_BASE_ADDR + 0x90000)
+#define MX51_KPP_BASE_ADDR             (MX51_AIPS1_BASE_ADDR + 0x94000)
+#define MX51_WDOG_BASE_ADDR            (MX51_AIPS1_BASE_ADDR + 0x98000)
+#define MX51_WDOG2_BASE_ADDR           (MX51_AIPS1_BASE_ADDR + 0x9c000)
+#define MX51_GPT1_BASE_ADDR            (MX51_AIPS1_BASE_ADDR + 0xa0000)
+#define MX51_SRTC_BASE_ADDR            (MX51_AIPS1_BASE_ADDR + 0xa4000)
+#define MX51_IOMUXC_BASE_ADDR          (MX51_AIPS1_BASE_ADDR + 0xa8000)
+#define MX51_EPIT1_BASE_ADDR           (MX51_AIPS1_BASE_ADDR + 0xac000)
+#define MX51_EPIT2_BASE_ADDR           (MX51_AIPS1_BASE_ADDR + 0xb0000)
+#define MX51_PWM1_BASE_ADDR            (MX51_AIPS1_BASE_ADDR + 0xb4000)
+#define MX51_PWM2_BASE_ADDR            (MX51_AIPS1_BASE_ADDR + 0xb8000)
+#define MX51_UART1_BASE_ADDR           (MX51_AIPS1_BASE_ADDR + 0xbc000)
+#define MX51_UART2_BASE_ADDR           (MX51_AIPS1_BASE_ADDR + 0xc0000)
+#define MX51_SRC_BASE_ADDR             (MX51_AIPS1_BASE_ADDR + 0xd0000)
+#define MX51_CCM_BASE_ADDR             (MX51_AIPS1_BASE_ADDR + 0xd4000)
+#define MX51_GPC_BASE_ADDR             (MX51_AIPS1_BASE_ADDR + 0xd8000)
 
-#define MX51_TZIC_BASE_ADDR_TO1                0x8FFFC000
-#define MX51_TZIC_BASE_ADDR            0xE0000000
+/*
+ * AIPS 2
+ */
+#define MX51_AIPS2_BASE_ADDR           0x83f00000
+#define MX51_AIPS2_BASE_ADDR_VIRT      0xfb200000
+#define MX51_AIPS2_SIZE                        SZ_1M
 
-#define MX51_DEBUG_BASE_ADDR           0x60000000
-#define MX51_DEBUG_BASE_ADDR_VIRT      0xFA200000
-#define MX51_DEBUG_SIZE                        SZ_1M
-#define MX51_ETB_BASE_ADDR             (MX51_DEBUG_BASE_ADDR + 0x00001000)
-#define MX51_ETM_BASE_ADDR             (MX51_DEBUG_BASE_ADDR + 0x00002000)
-#define MX51_TPIU_BASE_ADDR            (MX51_DEBUG_BASE_ADDR + 0x00003000)
-#define MX51_CTI0_BASE_ADDR            (MX51_DEBUG_BASE_ADDR + 0x00004000)
-#define MX51_CTI1_BASE_ADDR            (MX51_DEBUG_BASE_ADDR + 0x00005000)
-#define MX51_CTI2_BASE_ADDR            (MX51_DEBUG_BASE_ADDR + 0x00006000)
-#define MX51_CTI3_BASE_ADDR            (MX51_DEBUG_BASE_ADDR + 0x00007000)
-#define MX51_CORTEX_DBG_BASE_ADDR      (MX51_DEBUG_BASE_ADDR + 0x00008000)
+#define MX51_PLL1_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0x80000)
+#define MX51_PLL2_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0x84000)
+#define MX51_PLL3_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0x88000)
+#define MX51_AHBMAX_BASE_ADDR          (MX51_AIPS2_BASE_ADDR + 0x94000)
+#define MX51_IIM_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0x98000)
+#define MX51_CSU_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0x9c000)
+#define MX51_ARM_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0xa0000)
+#define MX51_OWIRE_BASE_ADDR           (MX51_AIPS2_BASE_ADDR + 0xa4000)
+#define MX51_FIRI_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0xa8000)
+#define MX51_ECSPI2_BASE_ADDR          (MX51_AIPS2_BASE_ADDR + 0xac000)
+#define MX51_SDMA_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0xb0000)
+#define MX51_SCC_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0xb4000)
+#define MX51_ROMCP_BASE_ADDR           (MX51_AIPS2_BASE_ADDR + 0xb8000)
+#define MX51_RTIC_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0xbc000)
+#define MX51_CSPI_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0xc0000)
+#define MX51_I2C2_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0xc4000)
+#define MX51_I2C1_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0xc8000)
+#define MX51_SSI1_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0xcc000)
+#define MX51_AUDMUX_BASE_ADDR          (MX51_AIPS2_BASE_ADDR + 0xd0000)
+#define MX51_M4IF_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0xd8000)
+#define MX51_ESDCTL_BASE_ADDR          (MX51_AIPS2_BASE_ADDR + 0xd9000)
+#define MX51_WEIM_BASE_ADDR            (MX51_AIPS2_BASE_ADDR + 0xda000)
+#define MX51_NFC_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0xdb000)
+#define MX51_EMI_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0xdbf00)
+#define MX51_MIPI_HSC_BASE_ADDR                (MX51_AIPS2_BASE_ADDR + 0xdc000)
+#define MX51_ATA_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0xe0000)
+#define MX51_SIM_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0xe4000)
+#define MX51_SSI3BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0xe8000)
+#define MX51_FEC_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0xec000)
+#define MX51_TVE_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0xf0000)
+#define MX51_VPU_BASE_ADDR             (MX51_AIPS2_BASE_ADDR + 0xf4000)
+#define MX51_SAHARA_BASE_ADDR          (MX51_AIPS2_BASE_ADDR + 0xf8000)
+
+#define MX51_CSD0_BASE_ADDR            0x90000000
+#define MX51_CSD1_BASE_ADDR            0xa0000000
+#define MX51_CS0_BASE_ADDR             0xb0000000
+#define MX51_CS1_BASE_ADDR             0xb8000000
+#define MX51_CS2_BASE_ADDR             0xc0000000
+#define MX51_CS3_BASE_ADDR             0xc8000000
+#define MX51_CS4_BASE_ADDR             0xcc000000
+#define MX51_CS5_BASE_ADDR             0xce000000
 
 /*
- * SPBA global module enabled #0
+ * NFC
  */
-#define MX51_SPBA0_BASE_ADDR           0x70000000
-#define MX51_SPBA0_BASE_ADDR_VIRT      0xFB100000
-#define MX51_SPBA0_SIZE                        SZ_1M
+#define MX51_NFC_AXI_BASE_ADDR         0xcfff0000      /* NAND flash AXI */
+#define MX51_NFC_AXI_SIZE              SZ_64K
+
+#define MX51_GPU2D_BASE_ADDR           0xd0000000
+#define MX51_TZIC_BASE_ADDR            0xe0000000
 
-#define MX51_MMC_SDHC1_BASE_ADDR       (MX51_SPBA0_BASE_ADDR + 0x00004000)
-#define MX51_MMC_SDHC2_BASE_ADDR       (MX51_SPBA0_BASE_ADDR + 0x00008000)
-#define MX51_UART3_BASE_ADDR           (MX51_SPBA0_BASE_ADDR + 0x0000C000)
-#define MX51_CSPI1_BASE_ADDR           (MX51_SPBA0_BASE_ADDR + 0x00010000)
-#define MX51_SSI2_BASE_ADDR            (MX51_SPBA0_BASE_ADDR + 0x00014000)
-#define MX51_MMC_SDHC3_BASE_ADDR       (MX51_SPBA0_BASE_ADDR + 0x00020000)
-#define MX51_MMC_SDHC4_BASE_ADDR       (MX51_SPBA0_BASE_ADDR + 0x00024000)
-#define MX51_SPDIF_BASE_ADDR           (MX51_SPBA0_BASE_ADDR + 0x00028000)
-#define MX51_ATA_DMA_BASE_ADDR         (MX51_SPBA0_BASE_ADDR + 0x00030000)
-#define MX51_SLIM_DMA_BASE_ADDR                (MX51_SPBA0_BASE_ADDR + 0x00034000)
-#define MX51_HSI2C_DMA_BASE_ADDR       (MX51_SPBA0_BASE_ADDR + 0x00038000)
-#define MX51_SPBA_CTRL_BASE_ADDR       (MX51_SPBA0_BASE_ADDR + 0x0003C000)
+#define MX51_IO_ADDRESS(x) (                                           \
+       IMX_IO_ADDRESS(x, MX51_IRAM) ?:                                 \
+       IMX_IO_ADDRESS(x, MX51_DEBUG) ?:                                \
+       IMX_IO_ADDRESS(x, MX51_SPBA0) ?:                                \
+       IMX_IO_ADDRESS(x, MX51_AIPS1) ?:                                \
+       IMX_IO_ADDRESS(x, MX51_AIPS2))
+
+/* This is currently used in <mach/debug-macro.S>, but should go away */
+#define MX51_AIPS1_IO_ADDRESS(x)  \
+       (((x) - MX51_AIPS1_BASE_ADDR) + MX51_AIPS1_BASE_ADDR_VIRT)
 
 /*
  * defines for SPBA modules
  */
 #define MX51_SPBA_SDHC1        0x04
 #define MX51_SPBA_SDHC2        0x08
-#define MX51_SPBA_UART3        0x0C
+#define MX51_SPBA_UART3        0x0c
 #define MX51_SPBA_CSPI1        0x10
 #define MX51_SPBA_SSI2 0x14
 #define MX51_SPBA_SDHC3        0x20
 #define MX51_SPBA_ATA  0x30
 #define MX51_SPBA_SLIM 0x34
 #define MX51_SPBA_HSI2C        0x38
-#define MX51_SPBA_CTRL 0x3C
-
-/*
- * AIPS 1
- */
-#define MX51_AIPS1_BASE_ADDR   0x73F00000
-#define MX51_AIPS1_BASE_ADDR_VIRT      0xFB000000
-#define MX51_AIPS1_SIZE                SZ_1M
-
-#define MX51_OTG_BASE_ADDR     (MX51_AIPS1_BASE_ADDR + 0x00080000)
-#define MX51_GPIO1_BASE_ADDR   (MX51_AIPS1_BASE_ADDR + 0x00084000)
-#define MX51_GPIO2_BASE_ADDR   (MX51_AIPS1_BASE_ADDR + 0x00088000)
-#define MX51_GPIO3_BASE_ADDR   (MX51_AIPS1_BASE_ADDR + 0x0008C000)
-#define MX51_GPIO4_BASE_ADDR   (MX51_AIPS1_BASE_ADDR + 0x00090000)
-#define MX51_KPP_BASE_ADDR     (MX51_AIPS1_BASE_ADDR + 0x00094000)
-#define MX51_WDOG_BASE_ADDR    (MX51_AIPS1_BASE_ADDR + 0x00098000)
-#define MX51_WDOG2_BASE_ADDR   (MX51_AIPS1_BASE_ADDR + 0x0009C000)
-#define MX51_GPT1_BASE_ADDR    (MX51_AIPS1_BASE_ADDR + 0x000A0000)
-#define MX51_SRTC_BASE_ADDR    (MX51_AIPS1_BASE_ADDR + 0x000A4000)
-#define MX51_IOMUXC_BASE_ADDR  (MX51_AIPS1_BASE_ADDR + 0x000A8000)
-#define MX51_EPIT1_BASE_ADDR   (MX51_AIPS1_BASE_ADDR + 0x000AC000)
-#define MX51_EPIT2_BASE_ADDR   (MX51_AIPS1_BASE_ADDR + 0x000B0000)
-#define MX51_PWM1_BASE_ADDR    (MX51_AIPS1_BASE_ADDR + 0x000B4000)
-#define MX51_PWM2_BASE_ADDR    (MX51_AIPS1_BASE_ADDR + 0x000B8000)
-#define MX51_UART1_BASE_ADDR   (MX51_AIPS1_BASE_ADDR + 0x000BC000)
-#define MX51_UART2_BASE_ADDR   (MX51_AIPS1_BASE_ADDR + 0x000C0000)
-#define MX51_SRC_BASE_ADDR     (MX51_AIPS1_BASE_ADDR + 0x000D0000)
-#define MX51_CCM_BASE_ADDR     (MX51_AIPS1_BASE_ADDR + 0x000D4000)
-#define MX51_GPC_BASE_ADDR     (MX51_AIPS1_BASE_ADDR + 0x000D8000)
+#define MX51_SPBA_CTRL 0x3c
 
 /*
  * Defines for modules using static and dynamic DMA channels
 #define MX51_MXC_DMA_CHANNEL_ATA_TX    MXC_DMA_DYNAMIC_CHANNEL
 #define MX51_MXC_DMA_CHANNEL_MEMORY    MXC_DMA_DYNAMIC_CHANNEL
 
-/*
- * AIPS 2
- */
-#define MX51_AIPS2_BASE_ADDR           0x83F00000
-#define MX51_AIPS2_BASE_ADDR_VIRT      0xFB200000
-#define MX51_AIPS2_SIZE                        SZ_1M
-
-#define MX51_PLL1_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x00080000)
-#define MX51_PLL2_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x00084000)
-#define MX51_PLL3_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x00088000)
-#define MX51_AHBMAX_BASE_ADDR  (MX51_AIPS2_BASE_ADDR + 0x00094000)
-#define MX51_IIM_BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x00098000)
-#define MX51_CSU_BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x0009C000)
-#define MX51_ARM_BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x000A0000)
-#define MX51_OWIRE_BASE_ADDR   (MX51_AIPS2_BASE_ADDR + 0x000A4000)
-#define MX51_FIRI_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x000A8000)
-#define MX51_CSPI2_BASE_ADDR   (MX51_AIPS2_BASE_ADDR + 0x000AC000)
-#define MX51_SDMA_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x000B0000)
-#define MX51_SCC_BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x000B4000)
-#define MX51_ROMCP_BASE_ADDR   (MX51_AIPS2_BASE_ADDR + 0x000B8000)
-#define MX51_RTIC_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x000BC000)
-#define MX51_CSPI3_BASE_ADDR   (MX51_AIPS2_BASE_ADDR + 0x000C0000)
-#define MX51_I2C2_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x000C4000)
-#define MX51_I2C1_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x000C8000)
-#define MX51_SSI1_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x000CC000)
-#define MX51_AUDMUX_BASE_ADDR  (MX51_AIPS2_BASE_ADDR + 0x000D0000)
-#define MX51_M4IF_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x000D8000)
-#define MX51_ESDCTL_BASE_ADDR  (MX51_AIPS2_BASE_ADDR + 0x000D9000)
-#define MX51_WEIM_BASE_ADDR    (MX51_AIPS2_BASE_ADDR + 0x000DA000)
-#define MX51_NFC_BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x000DB000)
-#define MX51_EMI_BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x000DBF00)
-#define MX51_MIPI_HSC_BASE_ADDR        (MX51_AIPS2_BASE_ADDR + 0x000DC000)
-#define MX51_ATA_BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x000E0000)
-#define MX51_SIM_BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x000E4000)
-#define MX51_SSI3BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x000E8000)
-#define MX51_MXC_FEC_BASE_ADDR (MX51_AIPS2_BASE_ADDR + 0x000EC000)
-#define MX51_TVE_BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x000F0000)
-#define MX51_VPU_BASE_ADDR     (MX51_AIPS2_BASE_ADDR + 0x000F4000)
-#define MX51_SAHARA_BASE_ADDR  (MX51_AIPS2_BASE_ADDR + 0x000F8000)
-
-/*
- * Memory regions and CS
- */
-#define MX51_GPU_CTRL_BASE_ADDR                0x30000000
-#define MX51_IPU_CTRL_BASE_ADDR                0x40000000
-#define MX51_CSD0_BASE_ADDR            0x90000000
-#define MX51_CSD1_BASE_ADDR            0xA0000000
-#define MX51_CS0_BASE_ADDR             0xB0000000
-#define MX51_CS1_BASE_ADDR             0xB8000000
-#define MX51_CS2_BASE_ADDR             0xC0000000
-#define MX51_CS3_BASE_ADDR             0xC8000000
-#define MX51_CS4_BASE_ADDR             0xCC000000
-#define MX51_CS5_BASE_ADDR             0xCE000000
-
-/* Does given address belongs to the specified memory region? */
-#define ADDRESS_IN_REGION(addr, start, size)                   \
-       (((addr) >= (start)) && ((addr) < (start)+(size)))
-
-/* Does given address belongs to the specified named `module'? */
-#define MX51_IS_MODULE(addr, module)                          \
-       ADDRESS_IN_REGION(addr, MX51_ ## module ## _BASE_ADDR, \
-                               MX51_ ## module ## _SIZE)
-/*
- * This macro defines the physical to virtual address mapping for all the
- * peripheral modules. It is used by passing in the physical address as x
- * and returning the virtual address. If the physical address is not mapped,
- * it returns 0xDEADBEEF
- */
-
-#define MX51_IO_ADDRESS(x)                                     \
-       (void __iomem *)                                        \
-       (MX51_IS_MODULE(x, IRAM) ? MX51_IRAM_IO_ADDRESS(x) :    \
-       MX51_IS_MODULE(x, DEBUG) ? MX51_DEBUG_IO_ADDRESS(x) :   \
-       MX51_IS_MODULE(x, SPBA0) ? MX51_SPBA0_IO_ADDRESS(x) :   \
-       MX51_IS_MODULE(x, AIPS1) ? MX51_AIPS1_IO_ADDRESS(x) :   \
-       MX51_IS_MODULE(x, AIPS2) ? MX51_AIPS2_IO_ADDRESS(x) : \
-       0xDEADBEEF)
-
-/*
- * define the address mapping macros: in physical address order
- */
-#define MX51_IRAM_IO_ADDRESS(x)  \
-       (((x) - MX51_IRAM_BASE_ADDR) + MX51_IRAM_BASE_ADDR_VIRT)
-
-#define MX51_DEBUG_IO_ADDRESS(x)  \
-       (((x) - MX51_DEBUG_BASE_ADDR) + MX51_DEBUG_BASE_ADDR_VIRT)
-
-#define MX51_SPBA0_IO_ADDRESS(x)  \
-       (((x) - MX51_SPBA0_BASE_ADDR) + MX51_SPBA0_BASE_ADDR_VIRT)
-
-#define MX51_AIPS1_IO_ADDRESS(x)  \
-       (((x) - MX51_AIPS1_BASE_ADDR) + MX51_AIPS1_BASE_ADDR_VIRT)
-
-#define MX51_AIPS2_IO_ADDRESS(x)  \
-       (((x) - MX51_AIPS2_BASE_ADDR) + MX51_AIPS2_BASE_ADDR_VIRT)
-
 #define MX51_IS_MEM_DEVICE_NONSHARED(x)                0
 
 /*
  * DMA request assignments
  */
-#define MX51_DMA_REQ_SSI3_TX1  47
-#define MX51_DMA_REQ_SSI3_RX1  46
-#define MX51_DMA_REQ_SPDIF     45
-#define MX51_DMA_REQ_UART3_TX  44
-#define MX51_DMA_REQ_UART3_RX  43
-#define MX51_DMA_REQ_SLIM_B_TX 42
-#define MX51_DMA_REQ_SDHC4     41
-#define MX51_DMA_REQ_SDHC3     40
-#define MX51_DMA_REQ_CSPI_TX   39
-#define MX51_DMA_REQ_CSPI_RX   38
-#define MX51_DMA_REQ_SSI3_TX2  37
-#define MX51_DMA_REQ_IPU       36
-#define MX51_DMA_REQ_SSI3_RX2  35
-#define MX51_DMA_REQ_EPIT2     34
-#define MX51_DMA_REQ_CTI2_1    33
-#define MX51_DMA_REQ_EMI_WR    32
-#define MX51_DMA_REQ_CTI2_0    31
-#define MX51_DMA_REQ_EMI_RD    30
-#define MX51_DMA_REQ_SSI1_TX1  29
-#define MX51_DMA_REQ_SSI1_RX1  28
-#define MX51_DMA_REQ_SSI1_TX2  27
-#define MX51_DMA_REQ_SSI1_RX2  26
-#define MX51_DMA_REQ_SSI2_TX1  25
-#define MX51_DMA_REQ_SSI2_RX1  24
-#define MX51_DMA_REQ_SSI2_TX2  23
-#define MX51_DMA_REQ_SSI2_RX2  22
-#define MX51_DMA_REQ_SDHC2     21
-#define MX51_DMA_REQ_SDHC1     20
-#define MX51_DMA_REQ_UART1_TX  19
-#define MX51_DMA_REQ_UART1_RX  18
-#define MX51_DMA_REQ_UART2_TX  17
-#define MX51_DMA_REQ_UART2_RX  16
-#define MX51_DMA_REQ_GPU       15
-#define MX51_DMA_REQ_EXTREQ1   14
-#define MX51_DMA_REQ_FIRI_TX   13
-#define MX51_DMA_REQ_FIRI_RX   12
-#define MX51_DMA_REQ_HS_I2C_RX 11
-#define MX51_DMA_REQ_HS_I2C_TX 10
-#define MX51_DMA_REQ_CSPI2_TX  9
-#define MX51_DMA_REQ_CSPI2_RX  8
-#define MX51_DMA_REQ_CSPI1_TX  7
-#define MX51_DMA_REQ_CSPI1_RX  6
-#define MX51_DMA_REQ_SLIM_B    5
-#define MX51_DMA_REQ_ATA_TX_END        4
-#define MX51_DMA_REQ_ATA_TX    3
-#define MX51_DMA_REQ_ATA_RX    2
-#define MX51_DMA_REQ_GPC       1
-#define MX51_DMA_REQ_VPU       0
+#define MX51_DMA_REQ_VPU               0
+#define MX51_DMA_REQ_GPC               1
+#define MX51_DMA_REQ_ATA_RX            2
+#define MX51_DMA_REQ_ATA_TX            3
+#define MX51_DMA_REQ_ATA_TX_END                4
+#define MX51_DMA_REQ_SLIM_B            5
+#define MX51_DMA_REQ_CSPI1_RX          6
+#define MX51_DMA_REQ_CSPI1_TX          7
+#define MX51_DMA_REQ_CSPI2_RX          8
+#define MX51_DMA_REQ_CSPI2_TX          9
+#define MX51_DMA_REQ_HS_I2C_TX         10
+#define MX51_DMA_REQ_HS_I2C_RX         11
+#define MX51_DMA_REQ_FIRI_RX           12
+#define MX51_DMA_REQ_FIRI_TX           13
+#define MX51_DMA_REQ_EXTREQ1           14
+#define MX51_DMA_REQ_GPU               15
+#define MX51_DMA_REQ_UART2_RX          16
+#define MX51_DMA_REQ_UART2_TX          17
+#define MX51_DMA_REQ_UART1_RX          18
+#define MX51_DMA_REQ_UART1_TX          19
+#define MX51_DMA_REQ_SDHC1             20
+#define MX51_DMA_REQ_SDHC2             21
+#define MX51_DMA_REQ_SSI2_RX1          22
+#define MX51_DMA_REQ_SSI2_TX1          23
+#define MX51_DMA_REQ_SSI2_RX0          24
+#define MX51_DMA_REQ_SSI2_TX0          25
+#define MX51_DMA_REQ_SSI1_RX1          26
+#define MX51_DMA_REQ_SSI1_TX1          27
+#define MX51_DMA_REQ_SSI1_RX0          28
+#define MX51_DMA_REQ_SSI1_TX0          29
+#define MX51_DMA_REQ_EMI_RD            30
+#define MX51_DMA_REQ_CTI2_0            31
+#define MX51_DMA_REQ_EMI_WR            32
+#define MX51_DMA_REQ_CTI2_1            33
+#define MX51_DMA_REQ_EPIT2             34
+#define MX51_DMA_REQ_SSI3_RX2          35
+#define MX51_DMA_REQ_IPU               36
+#define MX51_DMA_REQ_SSI3_TX2          37
+#define MX51_DMA_REQ_CSPI_RX           38
+#define MX51_DMA_REQ_CSPI_TX           39
+#define MX51_DMA_REQ_SDHC3             40
+#define MX51_DMA_REQ_SDHC4             41
+#define MX51_DMA_REQ_SLIM_B_TX         42
+#define MX51_DMA_REQ_UART3_RX          43
+#define MX51_DMA_REQ_UART3_TX          44
+#define MX51_DMA_REQ_SPDIF             45
+#define MX51_DMA_REQ_SSI3_RX1          46
+#define MX51_DMA_REQ_SSI3_TX1          47
 
 /*
  * Interrupt numbers
  */
-#define MX51_MXC_INT_BASE      0
-#define MX51_MXC_INT_RESV0     0
-#define MX51_MXC_INT_MMC_SDHC1 1
-#define MX51_MXC_INT_MMC_SDHC2 2
-#define MX51_MXC_INT_MMC_SDHC3 3
-#define MX51_MXC_INT_MMC_SDHC4 4
-#define MX51_MXC_INT_RESV5     5
-#define MX51_MXC_INT_SDMA      6
-#define MX51_MXC_INT_IOMUX     7
-#define MX51_MXC_INT_NFC       8
-#define MX51_MXC_INT_VPU       9
-#define MX51_MXC_INT_IPU_ERR   10
-#define MX51_MXC_INT_IPU_SYN   11
-#define MX51_MXC_INT_GPU       12
-#define MX51_MXC_INT_RESV13    13
-#define MX51_MXC_INT_USB_H1    14
-#define MX51_MXC_INT_EMI       15
-#define MX51_MXC_INT_USB_H2    16
-#define MX51_MXC_INT_USB_H3    17
-#define MX51_MXC_INT_USB_OTG   18
-#define MX51_MXC_INT_SAHARA_H0 19
-#define MX51_MXC_INT_SAHARA_H1 20
-#define MX51_MXC_INT_SCC_SMN   21
-#define MX51_MXC_INT_SCC_STZ   22
-#define MX51_MXC_INT_SCC_SCM   23
-#define MX51_MXC_INT_SRTC_NTZ  24
-#define MX51_MXC_INT_SRTC_TZ   25
-#define MX51_MXC_INT_RTIC      26
-#define MX51_MXC_INT_CSU       27
-#define MX51_MXC_INT_SLIM_B    28
-#define MX51_MXC_INT_SSI1      29
-#define MX51_MXC_INT_SSI2      30
-#define MX51_MXC_INT_UART1     31
-#define MX51_MXC_INT_UART2     32
-#define MX51_MXC_INT_UART3     33
-#define MX51_MXC_INT_RESV34    34
-#define MX51_MXC_INT_RESV35    35
-#define MX51_MXC_INT_CSPI1     36
-#define MX51_MXC_INT_CSPI2     37
-#define MX51_MXC_INT_CSPI      38
-#define MX51_MXC_INT_GPT       39
-#define MX51_MXC_INT_EPIT1     40
-#define MX51_MXC_INT_EPIT2     41
-#define MX51_MXC_INT_GPIO1_INT7        42
-#define MX51_MXC_INT_GPIO1_INT6        43
-#define MX51_MXC_INT_GPIO1_INT5        44
-#define MX51_MXC_INT_GPIO1_INT4        45
-#define MX51_MXC_INT_GPIO1_INT3        46
-#define MX51_MXC_INT_GPIO1_INT2        47
-#define MX51_MXC_INT_GPIO1_INT1        48
-#define MX51_MXC_INT_GPIO1_INT0        49
-#define MX51_MXC_INT_GPIO1_LOW 50
-#define MX51_MXC_INT_GPIO1_HIGH        51
-#define MX51_MXC_INT_GPIO2_LOW 52
-#define MX51_MXC_INT_GPIO2_HIGH        53
-#define MX51_MXC_INT_GPIO3_LOW 54
-#define MX51_MXC_INT_GPIO3_HIGH        55
-#define MX51_MXC_INT_GPIO4_LOW 56
-#define MX51_MXC_INT_GPIO4_HIGH        57
-#define MX51_MXC_INT_WDOG1     58
-#define MX51_MXC_INT_WDOG2     59
-#define MX51_MXC_INT_KPP       60
-#define MX51_MXC_INT_PWM1      61
-#define MX51_MXC_INT_I2C1      62
-#define MX51_MXC_INT_I2C2      63
-#define MX51_MXC_INT_HS_I2C    64
-#define MX51_MXC_INT_RESV65    65
-#define MX51_MXC_INT_RESV66    66
-#define MX51_MXC_INT_SIM_IPB   67
-#define MX51_MXC_INT_SIM_DAT   68
-#define MX51_MXC_INT_IIM       69
-#define MX51_MXC_INT_ATA       70
-#define MX51_MXC_INT_CCM1      71
-#define MX51_MXC_INT_CCM2      72
-#define MX51_MXC_INT_GPC1      73
-#define MX51_MXC_INT_GPC2      74
-#define MX51_MXC_INT_SRC       75
-#define MX51_MXC_INT_NM                76
-#define MX51_MXC_INT_PMU       77
-#define MX51_MXC_INT_CTI_IRQ   78
-#define MX51_MXC_INT_CTI1_TG0  79
-#define MX51_MXC_INT_CTI1_TG1  80
-#define MX51_MXC_INT_MCG_ERR   81
-#define MX51_MXC_INT_MCG_TMR   82
-#define MX51_MXC_INT_MCG_FUNC  83
-#define MX51_MXC_INT_GPU2_IRQ  84
-#define MX51_MXC_INT_GPU2_BUSY 85
-#define MX51_MXC_INT_RESV86    86
-#define MX51_MXC_INT_FEC       87
-#define MX51_MXC_INT_OWIRE     88
-#define MX51_MXC_INT_CTI1_TG2  89
-#define MX51_MXC_INT_SJC       90
-#define MX51_MXC_INT_SPDIF     91
-#define MX51_MXC_INT_TVE       92
-#define MX51_MXC_INT_FIRI      93
-#define MX51_MXC_INT_PWM2      94
-#define MX51_MXC_INT_SLIM_EXP  95
-#define MX51_MXC_INT_SSI3      96
-#define MX51_MXC_INT_EMI_BOOT  97
-#define MX51_MXC_INT_CTI1_TG3  98
-#define MX51_MXC_INT_SMC_RX    99
-#define MX51_MXC_INT_VPU_IDLE  100
-#define MX51_MXC_INT_EMI_NFC   101
-#define MX51_MXC_INT_GPU_IDLE  102
+#define MX51_MXC_INT_BASE              0
+#define MX51_MXC_INT_RESV0             0
+#define MX51_INT_ESDHC1                        1
+#define MX51_INT_ESDHC2                        2
+#define MX51_INT_ESDHC3                        3
+#define MX51_INT_ESDHC4                        4
+#define MX51_MXC_INT_RESV5             5
+#define MX51_INT_SDMA                  6
+#define MX51_MXC_INT_IOMUX             7
+#define MX51_INT_NFC                   8
+#define MX51_MXC_INT_VPU               9
+#define MX51_MXC_INT_IPU_ERR           10
+#define MX51_MXC_INT_IPU_SYN           11
+#define MX51_MXC_INT_GPU               12
+#define MX51_MXC_INT_RESV13            13
+#define MX51_MXC_INT_USB_H1            14
+#define MX51_MXC_INT_EMI               15
+#define MX51_MXC_INT_USB_H2            16
+#define MX51_MXC_INT_USB_H3            17
+#define MX51_MXC_INT_USB_OTG           18
+#define MX51_MXC_INT_SAHARA_H0         19
+#define MX51_MXC_INT_SAHARA_H1         20
+#define MX51_MXC_INT_SCC_SMN           21
+#define MX51_MXC_INT_SCC_STZ           22
+#define MX51_MXC_INT_SCC_SCM           23
+#define MX51_MXC_INT_SRTC_NTZ          24
+#define MX51_MXC_INT_SRTC_TZ           25
+#define MX51_MXC_INT_RTIC              26
+#define MX51_MXC_INT_CSU               27
+#define MX51_MXC_INT_SLIM_B            28
+#define MX51_INT_SSI1                  29
+#define MX51_INT_SSI2                  30
+#define MX51_INT_UART1                 31
+#define MX51_INT_UART2                 32
+#define MX51_INT_UART3                 33
+#define MX51_MXC_INT_RESV34            34
+#define MX51_MXC_INT_RESV35            35
+#define MX51_INT_ECSPI1                        36
+#define MX51_INT_ECSPI2                        37
+#define MX51_INT_CSPI                  38
+#define MX51_MXC_INT_GPT               39
+#define MX51_MXC_INT_EPIT1             40
+#define MX51_MXC_INT_EPIT2             41
+#define MX51_MXC_INT_GPIO1_INT7                42
+#define MX51_MXC_INT_GPIO1_INT6                43
+#define MX51_MXC_INT_GPIO1_INT5                44
+#define MX51_MXC_INT_GPIO1_INT4                45
+#define MX51_MXC_INT_GPIO1_INT3                46
+#define MX51_MXC_INT_GPIO1_INT2                47
+#define MX51_MXC_INT_GPIO1_INT1                48
+#define MX51_MXC_INT_GPIO1_INT0                49
+#define MX51_MXC_INT_GPIO1_LOW         50
+#define MX51_MXC_INT_GPIO1_HIGH                51
+#define MX51_MXC_INT_GPIO2_LOW         52
+#define MX51_MXC_INT_GPIO2_HIGH                53
+#define MX51_MXC_INT_GPIO3_LOW         54
+#define MX51_MXC_INT_GPIO3_HIGH                55
+#define MX51_MXC_INT_GPIO4_LOW         56
+#define MX51_MXC_INT_GPIO4_HIGH                57
+#define MX51_MXC_INT_WDOG1             58
+#define MX51_MXC_INT_WDOG2             59
+#define MX51_MXC_INT_KPP               60
+#define MX51_MXC_INT_PWM1              61
+#define MX51_INT_I2C1                  62
+#define MX51_INT_I2C2                  63
+#define MX51_MXC_INT_HS_I2C            64
+#define MX51_MXC_INT_RESV65            65
+#define MX51_MXC_INT_RESV66            66
+#define MX51_MXC_INT_SIM_IPB           67
+#define MX51_MXC_INT_SIM_DAT           68
+#define MX51_MXC_INT_IIM               69
+#define MX51_MXC_INT_ATA               70
+#define MX51_MXC_INT_CCM1              71
+#define MX51_MXC_INT_CCM2              72
+#define MX51_MXC_INT_GPC1              73
+#define MX51_MXC_INT_GPC2              74
+#define MX51_MXC_INT_SRC               75
+#define MX51_MXC_INT_NM                        76
+#define MX51_MXC_INT_PMU               77
+#define MX51_MXC_INT_CTI_IRQ           78
+#define MX51_MXC_INT_CTI1_TG0          79
+#define MX51_MXC_INT_CTI1_TG1          80
+#define MX51_MXC_INT_MCG_ERR           81
+#define MX51_MXC_INT_MCG_TMR           82
+#define MX51_MXC_INT_MCG_FUNC          83
+#define MX51_MXC_INT_GPU2_IRQ          84
+#define MX51_MXC_INT_GPU2_BUSY         85
+#define MX51_MXC_INT_RESV86            86
+#define MX51_INT_FEC                   87
+#define MX51_MXC_INT_OWIRE             88
+#define MX51_MXC_INT_CTI1_TG2          89
+#define MX51_MXC_INT_SJC               90
+#define MX51_MXC_INT_SPDIF             91
+#define MX51_MXC_INT_TVE               92
+#define MX51_MXC_INT_FIRI              93
+#define MX51_MXC_INT_PWM2              94
+#define MX51_MXC_INT_SLIM_EXP          95
+#define MX51_MXC_INT_SSI3              96
+#define MX51_MXC_INT_EMI_BOOT          97
+#define MX51_MXC_INT_CTI1_TG3          98
+#define MX51_MXC_INT_SMC_RX            99
+#define MX51_MXC_INT_VPU_IDLE          100
+#define MX51_MXC_INT_EMI_NFC           101
+#define MX51_MXC_INT_GPU_IDLE          102
 
 /* silicon revisions specific to i.MX51 */
-#define MX51_CHIP_REV_1_0      0x10
-#define MX51_CHIP_REV_1_1      0x11
-#define MX51_CHIP_REV_1_2      0x12
-#define MX51_CHIP_REV_1_3      0x13
-#define MX51_CHIP_REV_2_0      0x20
-#define MX51_CHIP_REV_2_1      0x21
-#define MX51_CHIP_REV_2_2      0x22
-#define MX51_CHIP_REV_2_3      0x23
-#define MX51_CHIP_REV_3_0      0x30
-#define MX51_CHIP_REV_3_1      0x31
-#define MX51_CHIP_REV_3_2      0x32
-
-/* Mandatory defines used globally */
+#define MX51_CHIP_REV_1_0              0x10
+#define MX51_CHIP_REV_1_1              0x11
+#define MX51_CHIP_REV_1_2              0x12
+#define MX51_CHIP_REV_1_3              0x13
+#define MX51_CHIP_REV_2_0              0x20
+#define MX51_CHIP_REV_2_1              0x21
+#define MX51_CHIP_REV_2_2              0x22
+#define MX51_CHIP_REV_2_3              0x23
+#define MX51_CHIP_REV_3_0              0x30
+#define MX51_CHIP_REV_3_1              0x31
+#define MX51_CHIP_REV_3_2              0x32
 
 #if !defined(__ASSEMBLY__) && !defined(__MXC_BOOT_UNCOMPRESS)
-
 extern int mx51_revision(void);
 #endif
 
-#endif /*  __ASM_ARCH_MXC_MX51_H__ */
+/* tape-out 1 defines */
+#define MX51_TZIC_BASE_ADDR_TO1                0x8fffc000
+
+#endif /* ifndef __MACH_MX51_H__ */
index 4acd1143a9bdd7444c12ca547ed957b47ef302d6..95be51bfe9a966d5f30e94cdfa7607a43b3a8c58 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Copyright (C) 1999 ARM Limited
  *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *  Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ *  Copyright 2004-2008 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
@@ -28,8 +28,34 @@ static inline void arch_idle(void)
                mxc91231_prepare_idle();
        }
 #endif
-
-       cpu_do_idle();
+       /* fix i.MX31 errata TLSbo65953 and i.MX35 errata ENGcm09472 */
+       if (cpu_is_mx31() || cpu_is_mx35()) {
+               unsigned long reg = 0;
+               __asm__ __volatile__(
+                       /* disable I and D cache */
+                       "mrc p15, 0, %0, c1, c0, 0\n"
+                       "bic %0, %0, #0x00001000\n"
+                       "bic %0, %0, #0x00000004\n"
+                       "mcr p15, 0, %0, c1, c0, 0\n"
+                       /* invalidate I cache */
+                       "mov %0, #0\n"
+                       "mcr p15, 0, %0, c7, c5, 0\n"
+                       /* clear and invalidate D cache */
+                       "mov %0, #0\n"
+                       "mcr p15, 0, %0, c7, c14, 0\n"
+                       /* WFI */
+                       "mov %0, #0\n"
+                       "mcr p15, 0, %0, c7, c0, 4\n"
+                       "nop\n" "nop\n" "nop\n" "nop\n"
+                       "nop\n" "nop\n" "nop\n"
+                       /* enable I and D cache */
+                       "mrc p15, 0, %0, c1, c0, 0\n"
+                       "orr %0, %0, #0x00001000\n"
+                       "orr %0, %0, #0x00000004\n"
+                       "mcr p15, 0, %0, c1, c0, 0\n"
+                       : "=r" (reg));
+       } else
+               cpu_do_idle();
 }
 
 void arch_reset(char mode, const char *cmd);
index d9bd37e4667a23f04e3f20ba0fd4fcd8f599b6d6..9dd9c2085aad4f63b19f76e2277c2eb0ad72333c 100644 (file)
@@ -99,6 +99,7 @@ static __inline__ void __arch_decomp_setup(unsigned long arch_id)
                uart_base = MX3X_UART2_BASE_ADDR;
                break;
        case MACH_TYPE_MX51_BABBAGE:
+       case MACH_TYPE_EUKREA_CPUIMX51SD:
                uart_base = MX51_UART1_BASE_ADDR;
                break;
        default:
diff --git a/arch/arm/plat-mxc/iram_alloc.c b/arch/arm/plat-mxc/iram_alloc.c
new file mode 100644 (file)
index 0000000..074c386
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2010 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., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/genalloc.h>
+#include <mach/iram.h>
+
+static unsigned long iram_phys_base;
+static void __iomem *iram_virt_base;
+static struct gen_pool *iram_pool;
+
+static inline void __iomem *iram_phys_to_virt(unsigned long p)
+{
+       return iram_virt_base + (p - iram_phys_base);
+}
+
+void __iomem *iram_alloc(unsigned int size, unsigned long *dma_addr)
+{
+       if (!iram_pool)
+               return NULL;
+
+       *dma_addr = gen_pool_alloc(iram_pool, size);
+       pr_debug("iram alloc - %dB@0x%lX\n", size, *dma_addr);
+       if (!*dma_addr)
+               return NULL;
+       return iram_phys_to_virt(*dma_addr);
+}
+EXPORT_SYMBOL(iram_alloc);
+
+void iram_free(unsigned long addr, unsigned int size)
+{
+       if (!iram_pool)
+               return;
+
+       gen_pool_free(iram_pool, addr, size);
+}
+EXPORT_SYMBOL(iram_free);
+
+int __init iram_init(unsigned long base, unsigned long size)
+{
+       iram_phys_base = base;
+
+       iram_pool = gen_pool_create(PAGE_SHIFT, -1);
+       if (!iram_pool)
+               return -ENOMEM;
+
+       gen_pool_add(iram_pool, base, size, -1);
+       iram_virt_base = ioremap(iram_phys_base, size);
+       if (!iram_virt_base)
+               return -EIO;
+
+       pr_debug("i.MX IRAM pool: %ld KB@0x%p\n", size / 1024, iram_virt_base);
+       return 0;
+}
index 977c8f9a07a2194322deada32da2afd0481d50ad..85e6fd212a414efa02526762123b0b4d20653d9a 100644 (file)
@@ -102,6 +102,22 @@ static void __nmk_gpio_make_input(struct nmk_gpio_chip *nmk_chip,
        writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
 }
 
+static void __nmk_gpio_set_output(struct nmk_gpio_chip *nmk_chip,
+                                 unsigned offset, int val)
+{
+       if (val)
+               writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATS);
+       else
+               writel(1 << offset, nmk_chip->addr + NMK_GPIO_DATC);
+}
+
+static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,
+                                 unsigned offset, int val)
+{
+       writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
+       __nmk_gpio_set_output(nmk_chip, offset, val);
+}
+
 static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
                             pin_cfg_t cfg)
 {
@@ -118,20 +134,29 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
                [3] /* illegal */       = "??"
        };
        static const char *slpmnames[] = {
-               [NMK_GPIO_SLPM_INPUT]           = "input",
-               [NMK_GPIO_SLPM_NOCHANGE]        = "no-change",
+               [NMK_GPIO_SLPM_INPUT]           = "input/wakeup",
+               [NMK_GPIO_SLPM_NOCHANGE]        = "no-change/no-wakeup",
        };
 
        int pin = PIN_NUM(cfg);
        int pull = PIN_PULL(cfg);
        int af = PIN_ALT(cfg);
        int slpm = PIN_SLPM(cfg);
+       int output = PIN_DIR(cfg);
+       int val = PIN_VAL(cfg);
 
-       dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s\n",
-               pin, afnames[af], pullnames[pull], slpmnames[slpm]);
+       dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s (%s%s)\n",
+               pin, afnames[af], pullnames[pull], slpmnames[slpm],
+               output ? "output " : "input",
+               output ? (val ? "high" : "low") : "");
+
+       if (output)
+               __nmk_gpio_make_output(nmk_chip, offset, val);
+       else {
+               __nmk_gpio_make_input(nmk_chip, offset);
+               __nmk_gpio_set_pull(nmk_chip, offset, pull);
+       }
 
-       __nmk_gpio_make_input(nmk_chip, offset);
-       __nmk_gpio_set_pull(nmk_chip, offset, pull);
        __nmk_gpio_set_slpm(nmk_chip, offset, slpm);
        __nmk_gpio_set_mode(nmk_chip, offset, af);
 }
@@ -200,6 +225,10 @@ EXPORT_SYMBOL(nmk_config_pins);
  * changed to an input (with pullup/down enabled) in sleep and deep sleep.  If
  * @mode is NMK_GPIO_SLPM_NOCHANGE, the pin remains in the state it was
  * configured even when in sleep and deep sleep.
+ *
+ * On DB8500v2 onwards, this setting loses the previous meaning and instead
+ * indicates if wakeup detection is enabled on the pin.  Note that
+ * enable_irq_wake() will automatically enable wakeup detection.
  */
 int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
 {
@@ -367,7 +396,27 @@ static void nmk_gpio_irq_unmask(unsigned int irq)
 
 static int nmk_gpio_irq_set_wake(unsigned int irq, unsigned int on)
 {
-       return nmk_gpio_irq_modify(irq, WAKE, on);
+       struct nmk_gpio_chip *nmk_chip;
+       unsigned long flags;
+       int gpio;
+
+       gpio = NOMADIK_IRQ_TO_GPIO(irq);
+       nmk_chip = get_irq_chip_data(irq);
+       if (!nmk_chip)
+               return -EINVAL;
+
+       spin_lock_irqsave(&nmk_chip->lock, flags);
+#ifdef CONFIG_ARCH_U8500
+       if (cpu_is_u8500v2()) {
+               __nmk_gpio_set_slpm(nmk_chip, gpio,
+                                   on ? NMK_GPIO_SLPM_WAKEUP_ENABLE
+                                      : NMK_GPIO_SLPM_WAKEUP_DISABLE);
+       }
+#endif
+       __nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, on);
+       spin_unlock_irqrestore(&nmk_chip->lock, flags);
+
+       return 0;
 }
 
 static int nmk_gpio_irq_set_type(unsigned int irq, unsigned int type)
@@ -495,12 +544,8 @@ static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
 {
        struct nmk_gpio_chip *nmk_chip =
                container_of(chip, struct nmk_gpio_chip, chip);
-       u32 bit = 1 << offset;
 
-       if (val)
-               writel(bit, nmk_chip->addr + NMK_GPIO_DATS);
-       else
-               writel(bit, nmk_chip->addr + NMK_GPIO_DATC);
+       __nmk_gpio_set_output(nmk_chip, offset, val);
 }
 
 static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
@@ -509,8 +554,7 @@ static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
        struct nmk_gpio_chip *nmk_chip =
                container_of(chip, struct nmk_gpio_chip, chip);
 
-       writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRS);
-       nmk_gpio_set_output(chip, offset, val);
+       __nmk_gpio_make_output(nmk_chip, offset, val);
 
        return 0;
 }
@@ -534,7 +578,7 @@ static struct gpio_chip nmk_gpio_template = {
        .can_sleep              = 0,
 };
 
-static int __init nmk_gpio_probe(struct platform_device *dev)
+static int __devinit nmk_gpio_probe(struct platform_device *dev)
 {
        struct nmk_gpio_platform_data *pdata = dev->dev.platform_data;
        struct nmk_gpio_chip *nmk_chip;
index aba355101f492687e39e303fff8b26ceb761541e..67b113d639d825f6072f2abe4f4251bccc480fda 100644 (file)
@@ -65,7 +65,9 @@ enum nmk_gpio_pull {
 /* Sleep mode */
 enum nmk_gpio_slpm {
        NMK_GPIO_SLPM_INPUT,
+       NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT,
        NMK_GPIO_SLPM_NOCHANGE,
+       NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE,
 };
 
 extern int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode);
index 7eed11c1038d768025998bcb55aab8b78f015df8..8c5ae3f2acf8dc6700079008c7058816808f9a62 100644 (file)
  *     bit  9..10 - Alternate Function Selection
  *     bit 11..12 - Pull up/down state
  *     bit     13 - Sleep mode behaviour
+ *     bit     14 - (sleep mode) Direction
+ *     bit     15 - (sleep mode) Value (if output)
  *
  * to facilitate the definition, the following macros are provided
  *
  * PIN_CFG_DEFAULT - default config (0):
  *                  pull up/down = disabled
- *                  sleep mode = input
+ *                  sleep mode = input/wakeup
+ *                  (sleep mode) direction = input
+ *                  (sleep mode) value = low
  *
  * PIN_CFG        - default config with alternate function
  * PIN_CFG_PULL           - default config with alternate function and pull up/down
@@ -53,8 +57,36 @@ typedef unsigned long pin_cfg_t;
 #define PIN_SLPM_SHIFT         13
 #define PIN_SLPM_MASK          (0x1 << PIN_SLPM_SHIFT)
 #define PIN_SLPM(x)            (((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT)
-#define PIN_SLPM_INPUT         (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT)
+#define PIN_SLPM_MAKE_INPUT    (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT)
 #define PIN_SLPM_NOCHANGE      (NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT)
+/* These two replace the above in DB8500v2+ */
+#define PIN_SLPM_WAKEUP_ENABLE (NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT)
+#define PIN_SLPM_WAKEUP_DISABLE        (NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT)
+
+#define PIN_DIR_SHIFT          14
+#define PIN_DIR_MASK           (0x1 << PIN_DIR_SHIFT)
+#define PIN_DIR(x)             (((x) & PIN_DIR_MASK) >> PIN_DIR_SHIFT)
+#define PIN_DIR_INPUT          (0 << PIN_DIR_SHIFT)
+#define PIN_DIR_OUTPUT         (1 << PIN_DIR_SHIFT)
+
+#define PIN_VAL_SHIFT          15
+#define PIN_VAL_MASK           (0x1 << PIN_VAL_SHIFT)
+#define PIN_VAL(x)             (((x) & PIN_VAL_MASK) >> PIN_VAL_SHIFT)
+#define PIN_VAL_LOW            (0 << PIN_VAL_SHIFT)
+#define PIN_VAL_HIGH           (1 << PIN_VAL_SHIFT)
+
+/* Shortcuts.  Use these instead of separate DIR and VAL.  */
+#define PIN_INPUT              PIN_DIR_INPUT
+#define PIN_OUTPUT_LOW         (PIN_DIR_OUTPUT | PIN_VAL_LOW)
+#define PIN_OUTPUT_HIGH                (PIN_DIR_OUTPUT | PIN_VAL_HIGH)
+
+/*
+ * These are the same as the ones above, but should make more sense to the
+ * reader when seen along with a setting a pin to AF mode.
+ */
+#define PIN_SLPM_INPUT         PIN_INPUT
+#define PIN_SLPM_OUTPUT_LOW    PIN_OUTPUT_LOW
+#define PIN_SLPM_OUTPUT_HIGH   PIN_OUTPUT_HIGH
 
 #define PIN_CFG_DEFAULT                (PIN_PULL_NONE | PIN_SLPM_INPUT)
 
index 0054b9501a53976a384cde437b43be7c03cc582a..71934817e17228ffb01cfffc6a5fe2b872009964 100644 (file)
@@ -173,11 +173,7 @@ static int check_fbmem_region(int region_idx, struct omapfb_mem_region *rg,
 
 static int valid_sdram(unsigned long addr, unsigned long size)
 {
-       struct memblock_property res;
-
-       res.base = addr;
-       res.size = size;
-       return !memblock_find(&res) && res.base == addr && res.size == size;
+       return memblock_is_region_memory(addr, size);
 }
 
 static int reserve_sdram(unsigned long addr, unsigned long size)
index 5177a9c5a25acb62966f14763cf6aff842ee5a11..ecd6a488c497c28fda8aea2c3412a95b67e05cc7 100644 (file)
@@ -18,6 +18,7 @@
 #define OMAP_ARCH_SMP_H
 
 #include <asm/hardware/gic.h>
+#include <asm/smp_mpidr.h>
 
 /* Needed for secondary core boot */
 extern void omap_secondary_startup(void);
@@ -33,15 +34,4 @@ 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
similarity index 83%
rename from arch/arm/mach-pxa/include/mach/pxa27x_keypad.h
rename to arch/arm/plat-pxa/include/plat/pxa27x_keypad.h
index 7b4eadc6df3a8c7762329304b1cec2fefbc900ff..abcc36eb12425ac04a28da7e61f6e9fa171ddac0 100644 (file)
  *
  * 4. matrix key and direct key will use the same debounce_interval by
  *    default, which should be sufficient in most cases
+ *
+ * pxa168 keypad platform specific parameter
+ *
+ * NOTE:
+ * clear_wakeup_event callback is a workaround required to clear the
+ * keypad interrupt. The keypad wake must be cleared in addition to
+ * reading the MI/DI bits in the KPC register.
  */
 struct pxa27x_keypad_platform_data {
 
@@ -52,6 +59,9 @@ struct pxa27x_keypad_platform_data {
 
        /* key debounce interval */
        unsigned int    debounce_interval;
+
+       /* clear wakeup event requirement for pxa168 */
+       void            (*clear_wakeup_event)(void);
 };
 
 extern void pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info);
index c6a855db2fb6f327bc962b0b3e1913630c9252d6..25960966af7c7f1acf54c168ddc06e36ca97b91c 100644 (file)
@@ -7,7 +7,7 @@
 
 config PLAT_S5P
        bool
-       depends on (ARCH_S5P6440 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5PV310)
+       depends on (ARCH_S5P64X0 || ARCH_S5P6442 || ARCH_S5PC100 || ARCH_S5PV210 || ARCH_S5PV310)
        default y
        select ARM_VIC if !ARCH_S5PV310
        select ARM_GIC if ARCH_S5PV310
@@ -30,7 +30,7 @@ config S5P_EXT_INT
        bool
        help
          Use the external interrupts (other than GPIO interrupts.)
-         Note: Do not choose this for S5P6440.
+         Note: Do not choose this for S5P6440 and S5P6450.
 
 config S5P_DEV_FIMC0
        bool
@@ -46,3 +46,8 @@ config S5P_DEV_FIMC2
        bool
        help
          Compile in platform device definitions for FIMC controller 2
+
+config S5P_DEV_ONENAND
+       bool
+       help
+         Compile in platform device definition for OneNAND controller
index b2e029673950fb028b2a936a2d0bbf7d9ee771e3..f3e917e27da870341a5d7c9d6b0c56b5964f9430 100644 (file)
@@ -24,3 +24,4 @@ obj-$(CONFIG_S5P_EXT_INT)     += irq-eint.o
 obj-$(CONFIG_S5P_DEV_FIMC0)    += dev-fimc0.o
 obj-$(CONFIG_S5P_DEV_FIMC1)    += dev-fimc1.o
 obj-$(CONFIG_S5P_DEV_FIMC2)    += dev-fimc2.o
+obj-$(CONFIG_S5P_DEV_ONENAND)  += dev-onenand.o
index b5e255265f20de4085bac619341f8bb9c1c40fd7..8aaf4e6b60c300760c443aa6fe4548fe165ff3b6 100644 (file)
@@ -74,6 +74,13 @@ struct clk clk_fout_epll = {
        .ctrlbit        = (1 << 31),
 };
 
+/* DPLL clock output */
+struct clk clk_fout_dpll = {
+       .name           = "fout_dpll",
+       .id             = -1,
+       .ctrlbit        = (1 << 31),
+};
+
 /* VPLL clock output */
 struct clk clk_fout_vpll = {
        .name           = "fout_vpll",
@@ -122,6 +129,17 @@ struct clksrc_sources clk_src_epll = {
        .nr_sources     = ARRAY_SIZE(clk_src_epll_list),
 };
 
+/* Possible clock sources for DPLL Mux */
+static struct clk *clk_src_dpll_list[] = {
+       [0] = &clk_fin_dpll,
+       [1] = &clk_fout_dpll,
+};
+
+struct clksrc_sources clk_src_dpll = {
+       .sources        = clk_src_dpll_list,
+       .nr_sources     = ARRAY_SIZE(clk_src_dpll_list),
+};
+
 struct clk clk_vpll = {
        .name           = "vpll",
        .id             = -1,
@@ -145,6 +163,7 @@ static struct clk *s5p_clks[] __initdata = {
        &clk_fout_apll,
        &clk_fout_mpll,
        &clk_fout_epll,
+       &clk_fout_dpll,
        &clk_fout_vpll,
        &clk_arm,
        &clk_vpll,
index b07a078fd28449b80c9171d46f10975a5998b2b9..74f7f5a5446cdaf4bdc9a3212f1dc9679611abfb 100644 (file)
@@ -19,6 +19,7 @@
 #include <plat/cpu.h>
 #include <plat/s5p6440.h>
 #include <plat/s5p6442.h>
+#include <plat/s5p6450.h>
 #include <plat/s5pc100.h>
 #include <plat/s5pv210.h>
 #include <plat/s5pv310.h>
@@ -27,6 +28,7 @@
 
 static const char name_s5p6440[] = "S5P6440";
 static const char name_s5p6442[] = "S5P6442";
+static const char name_s5p6450[] = "S5P6450";
 static const char name_s5pc100[] = "S5PC100";
 static const char name_s5pv210[] = "S5PV210/S5PC110";
 static const char name_s5pv310[] = "S5PV310";
@@ -38,7 +40,7 @@ static struct cpu_table cpu_ids[] __initdata = {
                .map_io         = s5p6440_map_io,
                .init_clocks    = s5p6440_init_clocks,
                .init_uarts     = s5p6440_init_uarts,
-               .init           = s5p6440_init,
+               .init           = s5p64x0_init,
                .name           = name_s5p6440,
        }, {
                .idcode         = 0x36442000,
@@ -48,6 +50,14 @@ static struct cpu_table cpu_ids[] __initdata = {
                .init_uarts     = s5p6442_init_uarts,
                .init           = s5p6442_init,
                .name           = name_s5p6442,
+       }, {
+               .idcode         = 0x36450000,
+               .idmask         = 0xffffff00,
+               .map_io         = s5p6450_map_io,
+               .init_clocks    = s5p6450_init_clocks,
+               .init_uarts     = s5p6450_init_uarts,
+               .init           = s5p64x0_init,
+               .name           = name_s5p6450,
        }, {
                .idcode         = 0x43100000,
                .idmask         = 0xfffff000,
@@ -88,33 +98,11 @@ static struct map_desc s5p_iodesc[] __initdata = {
                .pfn            = __phys_to_pfn(S5P_PA_SYSCON),
                .length         = SZ_64K,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S3C_VA_UART,
-               .pfn            = __phys_to_pfn(S3C_PA_UART),
-               .length         = SZ_512K,
-               .type           = MT_DEVICE,
-#ifdef CONFIG_ARM_VIC
-       }, {
-               .virtual        = (unsigned long)VA_VIC0,
-               .pfn            = __phys_to_pfn(S5P_PA_VIC0),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)VA_VIC1,
-               .pfn            = __phys_to_pfn(S5P_PA_VIC1),
-               .length         = SZ_16K,
-               .type           = MT_DEVICE,
-#endif
        }, {
                .virtual        = (unsigned long)S3C_VA_TIMER,
                .pfn            = __phys_to_pfn(S5P_PA_TIMER),
                .length         = SZ_16K,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)S5P_VA_GPIO,
-               .pfn            = __phys_to_pfn(S5P_PA_GPIO),
-               .length         = SZ_4K,
-               .type           = MT_DEVICE,
        }, {
                .virtual        = (unsigned long)S3C_VA_WATCHDOG,
                .pfn            = __phys_to_pfn(S3C_PA_WDT),
similarity index 59%
rename from arch/arm/mach-s5pv210/dev-onenand.c
rename to arch/arm/plat-s5p/dev-onenand.c
index f8ede33ee82b8e1d0acee891e54d6772a628d650..6db926202caa6adcb193b899e21eb78584c28ff0 100644 (file)
@@ -1,10 +1,12 @@
-/*
- * linux/arch/arm/mach-s5pv210/dev-onenand.c
+/* linux/arch/arm/plat-s5p/dev-onenand.c
+ *
+ * Copyright 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
  *  Copyright (c) 2008-2010 Samsung Electronics
  *  Kyungmin Park <kyungmin.park@samsung.com>
  *
- * S5PC110 series device definition for OneNAND devices
+ * S5P series device definition for OneNAND devices
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include <mach/irqs.h>
 #include <mach/map.h>
 
-static struct resource s5pc110_onenand_resources[] = {
+static struct resource s5p_onenand_resources[] = {
        [0] = {
-               .start  = S5PC110_PA_ONENAND,
-               .end    = S5PC110_PA_ONENAND + SZ_128K - 1,
+               .start  = S5P_PA_ONENAND,
+               .end    = S5P_PA_ONENAND + SZ_128K - 1,
                .flags  = IORESOURCE_MEM,
        },
        [1] = {
-               .start  = S5PC110_PA_ONENAND_DMA,
-               .end    = S5PC110_PA_ONENAND_DMA + SZ_8K - 1,
+               .start  = S5P_PA_ONENAND_DMA,
+               .end    = S5P_PA_ONENAND_DMA + SZ_8K - 1,
                .flags  = IORESOURCE_MEM,
        },
        [2] = {
@@ -37,19 +39,19 @@ static struct resource s5pc110_onenand_resources[] = {
        },
 };
 
-struct platform_device s5pc110_device_onenand = {
+struct platform_device s5p_device_onenand = {
        .name           = "s5pc110-onenand",
        .id             = -1,
-       .num_resources  = ARRAY_SIZE(s5pc110_onenand_resources),
-       .resource       = s5pc110_onenand_resources,
+       .num_resources  = ARRAY_SIZE(s5p_onenand_resources),
+       .resource       = s5p_onenand_resources,
 };
 
-void s5pc110_onenand_set_platdata(struct onenand_platform_data *pdata)
+void s5p_onenand_set_platdata(struct onenand_platform_data *pdata)
 {
        struct onenand_platform_data *pd;
 
        pd = kmemdup(pdata, sizeof(struct onenand_platform_data), GFP_KERNEL);
        if (!pd)
                printk(KERN_ERR "%s: no memory for platform data\n", __func__);
-       s5pc110_device_onenand.dev.platform_data = pd;
+       s5p_device_onenand.dev.platform_data = pd;
 }
index a89331ef4ae172b97d6f21aba05fd8cd80c7eb09..6a7342886171fde25d9c531f4e86db6c7ef52f1b 100644 (file)
@@ -119,6 +119,56 @@ static struct resource s5p_uart3_resource[] = {
 #endif
 };
 
+static struct resource s5p_uart4_resource[] = {
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 4
+       [0] = {
+               .start  = S5P_PA_UART4,
+               .end    = S5P_PA_UART4 + S5P_SZ_UART,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_S5P_UART_RX4,
+               .end    = IRQ_S5P_UART_RX4,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = IRQ_S5P_UART_TX4,
+               .end    = IRQ_S5P_UART_TX4,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = IRQ_S5P_UART_ERR4,
+               .end    = IRQ_S5P_UART_ERR4,
+               .flags  = IORESOURCE_IRQ,
+       },
+#endif
+};
+
+static struct resource s5p_uart5_resource[] = {
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 5
+       [0] = {
+               .start  = S5P_PA_UART5,
+               .end    = S5P_PA_UART5 + S5P_SZ_UART,
+               .flags  = IORESOURCE_MEM,
+       },
+       [1] = {
+               .start  = IRQ_S5P_UART_RX5,
+               .end    = IRQ_S5P_UART_RX5,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [2] = {
+               .start  = IRQ_S5P_UART_TX5,
+               .end    = IRQ_S5P_UART_TX5,
+               .flags  = IORESOURCE_IRQ,
+       },
+       [3] = {
+               .start  = IRQ_S5P_UART_ERR5,
+               .end    = IRQ_S5P_UART_ERR5,
+               .flags  = IORESOURCE_IRQ,
+       },
+#endif
+};
+
 struct s3c24xx_uart_resources s5p_uart_resources[] __initdata = {
        [0] = {
                .resources      = s5p_uart0_resource,
@@ -136,4 +186,12 @@ struct s3c24xx_uart_resources s5p_uart_resources[] __initdata = {
                .resources      = s5p_uart3_resource,
                .nr_resources   = ARRAY_SIZE(s5p_uart3_resource),
        },
+       [4] = {
+               .resources      = s5p_uart4_resource,
+               .nr_resources   = ARRAY_SIZE(s5p_uart4_resource),
+       },
+       [5] = {
+               .resources      = s5p_uart5_resource,
+               .nr_resources   = ARRAY_SIZE(s5p_uart5_resource),
+       },
 };
index 4e8fe08cb70d96ad13dee8c1288e95f206c4bb17..bf28fadee7ae07c931174fab01d14875e396b316 100644 (file)
@@ -47,6 +47,7 @@ static inline unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con,
 }
 
 #define PLL46XX_KDIV_MASK      (0xFFFF)
+#define PLL4650C_KDIV_MASK     (0xFFF)
 #define PLL46XX_MDIV_MASK      (0x1FF)
 #define PLL46XX_PDIV_MASK      (0x3F)
 #define PLL46XX_SDIV_MASK      (0x7)
@@ -57,6 +58,7 @@ static inline unsigned long s5p_get_pll45xx(unsigned long baseclk, u32 pll_con,
 enum pll46xx_type_t {
        pll_4600,
        pll_4650,
+       pll_4650c,
 };
 
 static inline unsigned long s5p_get_pll46xx(unsigned long baseclk,
@@ -72,6 +74,11 @@ static inline unsigned long s5p_get_pll46xx(unsigned long baseclk,
        sdiv = (pll_con0 >> PLL46XX_SDIV_SHIFT) & PLL46XX_SDIV_MASK;
        kdiv = pll_con1 & PLL46XX_KDIV_MASK;
 
+       if (pll_type == pll_4650c)
+               kdiv = pll_con1 & PLL4650C_KDIV_MASK;
+       else
+               kdiv = pll_con1 & PLL46XX_KDIV_MASK;
+
        tmp = baseclk;
 
        if (pll_type == pll_4600) {
index 09418b1101fe582a374b4ded78010e36de392d11..17036c898409adafc0756b2064bb77e9f1e8e187 100644 (file)
@@ -1,7 +1,7 @@
 /* linux/arch/arm/plat-s5p/include/plat/s5p-clock.h
  *
- * Copyright 2009 Samsung Electronics Co., Ltd.
- *             http://www.samsung.com/
+ * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
  *
  * Header file for s5p clock support
  *
@@ -20,6 +20,7 @@
 #define clk_fin_apll clk_ext_xtal_mux
 #define clk_fin_mpll clk_ext_xtal_mux
 #define clk_fin_epll clk_ext_xtal_mux
+#define clk_fin_dpll clk_ext_xtal_mux
 #define clk_fin_vpll clk_ext_xtal_mux
 #define clk_fin_hpll clk_ext_xtal_mux
 
@@ -30,6 +31,7 @@ extern struct clk s5p_clk_27m;
 extern struct clk clk_fout_apll;
 extern struct clk clk_fout_mpll;
 extern struct clk clk_fout_epll;
+extern struct clk clk_fout_dpll;
 extern struct clk clk_fout_vpll;
 extern struct clk clk_arm;
 extern struct clk clk_vpll;
@@ -37,8 +39,8 @@ extern struct clk clk_vpll;
 extern struct clksrc_sources clk_src_apll;
 extern struct clksrc_sources clk_src_mpll;
 extern struct clksrc_sources clk_src_epll;
+extern struct clksrc_sources clk_src_dpll;
 
-extern int s5p6440_clk48m_ctrl(struct clk *clk, int enable);
 extern int s5p_gatectrl(void __iomem *reg, struct clk *clk, int enable);
 
 #endif /* __ASM_PLAT_S5P_CLOCK_H */
index a4cd75afeb3bf4efcd09dce436e198b341b58a54..528585d2cafcef8a0bae0926fd2318ede7d4a474 100644 (file)
 
  /* Common init code for S5P6440 related SoCs */
 
-extern void s5p6440_common_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 extern void s5p6440_register_clocks(void);
 extern void s5p6440_setup_clocks(void);
 
 #ifdef CONFIG_CPU_S5P6440
 
-extern  int s5p6440_init(void);
+extern  int s5p64x0_init(void);
 extern void s5p6440_init_irq(void);
 extern void s5p6440_map_io(void);
 extern void s5p6440_init_clocks(int xtal);
 
-#define s5p6440_init_uarts s5p6440_common_init_uarts
+extern void s5p6440_init_uarts(struct s3c2410_uartcfg *cfg, int no);
 
 #else
 #define s5p6440_init_clocks NULL
 #define s5p6440_init_uarts NULL
 #define s5p6440_map_io NULL
-#define s5p6440_init NULL
+#define s5p64x0_init NULL
 #endif
 
 /* S5P6440 timer */
diff --git a/arch/arm/plat-s5p/include/plat/s5p6450.h b/arch/arm/plat-s5p/include/plat/s5p6450.h
new file mode 100644 (file)
index 0000000..640a41c
--- /dev/null
@@ -0,0 +1,36 @@
+/* arch/arm/plat-s5p/include/plat/s5p6450.h
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Header file for s5p6450 cpu 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.
+*/
+
+/* Common init code for S5P6450 related SoCs */
+
+extern void s5p6450_register_clocks(void);
+extern void s5p6450_setup_clocks(void);
+
+#ifdef CONFIG_CPU_S5P6450
+
+extern  int s5p64x0_init(void);
+extern void s5p6450_init_irq(void);
+extern void s5p6450_map_io(void);
+extern void s5p6450_init_clocks(int xtal);
+
+extern void s5p6450_init_uarts(struct s3c2410_uartcfg *cfg, int no);
+
+#else
+#define s5p6450_init_clocks NULL
+#define s5p6450_init_uarts NULL
+#define s5p6450_map_io NULL
+#define s5p64x0_init NULL
+#endif
+
+/* S5P6450 timer */
+
+extern struct sys_timer s5p6450_timer;
index 6412933d6fbb813050b840e1d71e788758b9a9fc..9addb3dfb4bc31d83227acc18bcd654da748d380 100644 (file)
@@ -79,7 +79,7 @@ extern struct sysdev_class s3c2442_sysclass;
 extern struct sysdev_class s3c2443_sysclass;
 extern struct sysdev_class s3c6410_sysclass;
 extern struct sysdev_class s3c64xx_sysclass;
-extern struct sysdev_class s5p6440_sysclass;
+extern struct sysdev_class s5p64x0_sysclass;
 extern struct sysdev_class s5p6442_sysclass;
 extern struct sysdev_class s5pv210_sysclass;
 
index 85f6f23a510f56cd1b9ce5f1f7871f0923b26c11..7d448e13879241c8a62da6f26604ea00ecc1a3d1 100644 (file)
@@ -67,13 +67,15 @@ extern struct platform_device s5pv210_device_spi0;
 extern struct platform_device s5pv210_device_spi1;
 extern struct platform_device s5p6440_device_spi0;
 extern struct platform_device s5p6440_device_spi1;
+extern struct platform_device s5p6450_device_spi0;
+extern struct platform_device s5p6450_device_spi1;
 
 extern struct platform_device s3c_device_hwmon;
 
 extern struct platform_device s3c_device_nand;
 extern struct platform_device s3c_device_onenand;
 extern struct platform_device s3c64xx_device_onenand1;
-extern struct platform_device s5pc110_device_onenand;
+extern struct platform_device s5p_device_onenand;
 
 extern struct platform_device s3c_device_usbgadget;
 extern struct platform_device s3c_device_usb_hsotg;
@@ -95,6 +97,9 @@ extern struct platform_device s5p6442_device_spi;
 extern struct platform_device s5p6440_device_pcm;
 extern struct platform_device s5p6440_device_iis;
 
+extern struct platform_device s5p6450_device_iis0;
+extern struct platform_device s5p6450_device_pcm0;
+
 extern struct platform_device s5pc100_device_ac97;
 extern struct platform_device s5pc100_device_pcm0;
 extern struct platform_device s5pc100_device_pcm1;
index 5fe6721b57f7060acd8180522c3d2df41ad8cf62..81074421312068bfc24e5f9329d8d44d60538c8b 100644 (file)
@@ -32,6 +32,12 @@ enum dma_ch {
        DMACH_UART2_TX,
        DMACH_UART3_RX,
        DMACH_UART3_TX,
+       DMACH_UART4_RX,
+       DMACH_UART4_TX,
+       DMACH_UART5_RX,
+       DMACH_UART5_TX,
+       DMACH_USI_RX,
+       DMACH_USI_TX,
        DMACH_IRDA,
        DMACH_I2S0_RX,
        DMACH_I2S0_TX,
@@ -64,6 +70,20 @@ enum dma_ch {
        DMACH_MSM_REQ2,
        DMACH_MSM_REQ1,
        DMACH_MSM_REQ0,
+       DMACH_SLIMBUS0_RX,
+       DMACH_SLIMBUS0_TX,
+       DMACH_SLIMBUS0AUX_RX,
+       DMACH_SLIMBUS0AUX_TX,
+       DMACH_SLIMBUS1_RX,
+       DMACH_SLIMBUS1_TX,
+       DMACH_SLIMBUS2_RX,
+       DMACH_SLIMBUS2_TX,
+       DMACH_SLIMBUS3_RX,
+       DMACH_SLIMBUS3_TX,
+       DMACH_SLIMBUS4_RX,
+       DMACH_SLIMBUS4_TX,
+       DMACH_SLIMBUS5_RX,
+       DMACH_SLIMBUS5_TX,
        /* END Marker, also used to denote a reserved channel */
        DMACH_MAX,
 };
index e5aba8f95b791355f8d01a77347482053099933d..ff1a561b326ee028aa66467e758e12ac03a63b25 100644 (file)
@@ -32,6 +32,8 @@ struct s3c64xx_spi_csinfo {
  * struct s3c64xx_spi_info - SPI Controller defining structure
  * @src_clk_nr: Clock source index for the CLK_CFG[SPI_CLKSEL] field.
  * @src_clk_name: Platform name of the corresponding clock.
+ * @clk_from_cmu: If the SPI clock/prescalar control block is present
+ *     by the platform's clock-management-unit and not in SPI controller.
  * @num_cs: Number of CS this controller emulates.
  * @cfg_gpio: Configure pins for this SPI controller.
  * @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6
@@ -41,6 +43,7 @@ struct s3c64xx_spi_csinfo {
 struct s3c64xx_spi_info {
        int src_clk_nr;
        char *src_clk_name;
+       bool clk_from_cmu;
 
        int num_cs;
 
@@ -65,7 +68,7 @@ struct s3c64xx_spi_info {
 extern void s3c64xx_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 extern void s5pc100_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 extern void s5pv210_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
-extern void s5p6440_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
+extern void s5p64x0_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 extern void s5p6442_spi_set_info(int cntrlr, int src_clk_nr, int num_cs);
 
 #endif /* __S3C64XX_PLAT_SPI_H */
index 37fa593884ee64d345add30e2ca9738e238e3511..e91270e4f640329ce1424b1ad7c37a89dead7626 100644 (file)
 #include <linux/amba/serial.h>
 #include <mach/spear.h>
 
-               .macro  addruart, rx
-               mrc     p15, 0, \rx, c1, c0
-               tst     \rx, #1                                 @ MMU enabled?
-               moveq   \rx, #SPEAR_DBG_UART_BASE               @ Physical base
-               movne   \rx, #VA_SPEAR_DBG_UART_BASE            @ Virtual base
+               .macro  addruart, rp, rv
+               mov     \rp, #SPEAR_DBG_UART_BASE               @ Physical base
+               mov     \rv, #VA_SPEAR_DBG_UART_BASE            @ Virtual base
                .endm
 
                .macro  senduart, rd, rx
index 1b9348bf0e4926b542bea6d1bfcc4a9cd2e29440..d3a0985c96817f1dfd9471d7ab2a0f2d13644b48 100644 (file)
  * http://www.gnu.org/copyleft/gpl.html
  */
 
-               .macro  addruart, rx, tmp
-               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
+               .macro  addruart, rp, rv
+               mov     \rp,      #0x00070000
+               add     \rv, \rp, #0xf0000000   @ virtual base
+               add     \rp, \rp, #0x80000000   @ physical base
                .endm
 
                .macro  senduart,rd,rx
diff --git a/arch/arm/plat-tcc/Kconfig b/arch/arm/plat-tcc/Kconfig
new file mode 100644 (file)
index 0000000..1bf4995
--- /dev/null
@@ -0,0 +1,20 @@
+if ARCH_TCC_926
+
+menu "Telechips ARM926-based CPUs"
+
+choice
+       prompt "Telechips CPU type:"
+       default ARCH_TCC8K
+
+config ARCH_TCC8K
+       bool TCC8000
+       select USB_ARCH_HAS_OHCI
+       help
+         Support for Telechips TCC8000 systems
+
+endchoice
+
+source "arch/arm/mach-tcc8k/Kconfig"
+
+endmenu
+endif
diff --git a/arch/arm/plat-tcc/Makefile b/arch/arm/plat-tcc/Makefile
new file mode 100644 (file)
index 0000000..eceabc8
--- /dev/null
@@ -0,0 +1,3 @@
+# "Telechips Platform Common Modules"
+
+obj-y := clock.o system.o
diff --git a/arch/arm/plat-tcc/clock.c b/arch/arm/plat-tcc/clock.c
new file mode 100644 (file)
index 0000000..f3ced10
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Clock framework for Telechips SoCs
+ * Based on arch/arm/plat-mxc/clock.c
+ *
+ * Copyright (C) 2004 - 2005 Nokia corporation
+ * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
+ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
+ * Copyright 2010 Hans J. Koch, hjk@linutronix.de
+ *
+ * Licensed under the terms of the GPL v2.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+
+#include <mach/clock.h>
+#include <mach/hardware.h>
+
+static DEFINE_MUTEX(clocks_mutex);
+
+/*-------------------------------------------------------------------------
+ * Standard clock functions defined in include/linux/clk.h
+ *-------------------------------------------------------------------------*/
+
+static void __clk_disable(struct clk *clk)
+{
+       BUG_ON(clk->refcount == 0);
+
+       if (!(--clk->refcount) && clk->disable) {
+               /* Unconditionally disable the clock in hardware */
+               clk->disable(clk);
+               /* recursively disable parents */
+               if (clk->parent)
+                       __clk_disable(clk->parent);
+       }
+}
+
+static int __clk_enable(struct clk *clk)
+{
+       int ret = 0;
+
+       if (clk->refcount++ == 0 && clk->enable) {
+               if (clk->parent)
+                       ret = __clk_enable(clk->parent);
+               if (ret)
+                       return ret;
+               else
+                       return clk->enable(clk);
+       }
+
+       return 0;
+}
+
+/* This function increments the reference count on the clock and enables the
+ * clock if not already enabled. The parent clock tree is recursively enabled
+ */
+int clk_enable(struct clk *clk)
+{
+       int ret = 0;
+
+       if (!clk)
+               return -EINVAL;
+
+       mutex_lock(&clocks_mutex);
+       ret = __clk_enable(clk);
+       mutex_unlock(&clocks_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+/* This function decrements the reference count on the clock and disables
+ * the clock when reference count is 0. The parent clock tree is
+ * recursively disabled
+ */
+void clk_disable(struct clk *clk)
+{
+       if (!clk)
+               return;
+
+       mutex_lock(&clocks_mutex);
+       __clk_disable(clk);
+       mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+/* Retrieve the *current* clock rate. If the clock itself
+ * does not provide a special calculation routine, ask
+ * its parent and so on, until one is able to return
+ * a valid clock rate
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+       if (!clk)
+               return 0UL;
+
+       if (clk->get_rate)
+               return clk->get_rate(clk);
+
+       return clk_get_rate(clk->parent);
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+/* Round the requested clock rate to the nearest supported
+ * rate that is less than or equal to the requested rate.
+ * This is dependent on the clock's current parent.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       if (!clk)
+               return 0;
+       if (!clk->round_rate)
+               return 0;
+
+       return clk->round_rate(clk, rate);
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+/* Set the clock to the requested clock rate. The rate must
+ * match a supported rate exactly based on what clk_round_rate returns
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       int ret = -EINVAL;
+
+       if (!clk)
+               return ret;
+       if (!clk->set_rate || !rate)
+               return ret;
+
+       mutex_lock(&clocks_mutex);
+       ret = clk->set_rate(clk, rate);
+       mutex_unlock(&clocks_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+/* Set the clock's parent to another clock source */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       struct clk *old;
+       int ret = -EINVAL;
+
+       if (!clk)
+               return ret;
+       if (!clk->set_parent || !parent)
+               return ret;
+
+       mutex_lock(&clocks_mutex);
+       old = clk->parent;
+       if (clk->refcount)
+               __clk_enable(parent);
+       ret = clk->set_parent(clk, parent);
+       if (ret)
+               old = parent;
+       if (clk->refcount)
+               __clk_disable(old);
+       mutex_unlock(&clocks_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+/* Retrieve the clock's parent clock source */
+struct clk *clk_get_parent(struct clk *clk)
+{
+       if (!clk)
+               return NULL;
+
+       return clk->parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
diff --git a/arch/arm/plat-tcc/include/mach/clkdev.h b/arch/arm/plat-tcc/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/plat-tcc/include/mach/clock.h b/arch/arm/plat-tcc/include/mach/clock.h
new file mode 100644 (file)
index 0000000..a12f58a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Low level clock header file for Telechips TCC architecture
+ * (C) 2010 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the GPL v2.
+ */
+
+#ifndef __ASM_ARCH_TCC_CLOCK_H__
+#define __ASM_ARCH_TCC_CLOCK_H__
+
+#ifndef __ASSEMBLY__
+
+struct clk {
+       struct clk *parent;
+       /* id number of a root clock, 0 for normal clocks */
+       int root_id;
+       /* Reference count of clock enable/disable */
+       int refcount;
+       /* Address of associated BCLKCTRx register. Must be set. */
+       void __iomem *bclkctr;
+       /* Bit position for BCLKCTRx. Must be set. */
+       int bclk_shift;
+       /* Address of ACLKxxx register, if any. */
+       void __iomem *aclkreg;
+       /* get the current clock rate (always a fresh value) */
+       unsigned long (*get_rate) (struct clk *);
+       /* Function ptr to set the clock to a new rate. The rate must match a
+          supported rate returned from round_rate. Leave blank if clock is not
+          programmable */
+       int (*set_rate) (struct clk *, unsigned long);
+       /* Function ptr to round the requested clock rate to the nearest
+          supported rate that is less than or equal to the requested rate. */
+       unsigned long (*round_rate) (struct clk *, unsigned long);
+       /* Function ptr to enable the clock. Leave blank if clock can not
+          be gated. */
+       int (*enable) (struct clk *);
+       /* Function ptr to disable the clock. Leave blank if clock can not
+          be gated. */
+       void (*disable) (struct clk *);
+       /* Function ptr to set the parent clock of the clock. */
+       int (*set_parent) (struct clk *, struct clk *);
+};
+
+int clk_register(struct clk *clk);
+void clk_unregister(struct clk *clk);
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_ARCH_MXC_CLOCK_H__ */
diff --git a/arch/arm/plat-tcc/include/mach/debug-macro.S b/arch/arm/plat-tcc/include/mach/debug-macro.S
new file mode 100644 (file)
index 0000000..7662f73
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 1994-1999 Russell King
+ * Copyright (C) 2008-2009 Telechips
+ * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.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.
+ *
+ */
+
+               .macro  addruart, rp, rv
+               moveq   \rp, #0x90000000        @ physical base address
+               movne   \rv, #0xF1000000        @ virtual base
+               orr     \rp, \rp, #0x00007000   @ UART0
+               orr     \rv, \rv, #0x00007000   @ UART0
+               .endm
+
+               .macro  senduart,rd,rx
+               strb    \rd, [\rx, #0x44]
+               .endm
+
+               .macro  waituart,rd,rx
+               .endm
+
+               .macro  busyuart,rd,rx
+1001:
+               ldr \rd, [\rx, #0x14]
+               tst \rd, #0x20
+
+               beq 1001b
+               .endm
diff --git a/arch/arm/plat-tcc/include/mach/entry-macro.S b/arch/arm/plat-tcc/include/mach/entry-macro.S
new file mode 100644 (file)
index 0000000..748f401
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * include/asm-arm/arch-tcc83x/entry-macro.S
+ *
+ * Author : <linux@telechips.com>
+ * Created: June 10, 2008
+ * Description: Low-level IRQ helper macros for Telechips-based platforms
+ *
+ * Copyright (C) 2008-2009 Telechips
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <mach/hardware.h>
+#include <mach/irqs.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, =0xF2003000 @ base address of PIC registers
+
+               @@ read MREQ register of PIC0
+
+               mov     \irqnr, #0
+               ldr     \irqstat, [\base, #0x00000014 ] @ lower 32 interrupts
+               cmp     \irqstat, #0
+               bne     1001f
+
+               @@ read MREQ register of PIC1
+
+               ldr     \irqstat, [\base, #0x00000094]  @ upper 32 interrupts
+               cmp     \irqstat, #0
+               beq     1002f
+               mov     \irqnr, #0x20
+
+1001:
+               movs    \tmp, \irqstat, lsl #16
+               movne   \irqstat, \tmp
+               addeq   \irqnr, \irqnr, #16
+
+               movs    \tmp, \irqstat, lsl #8
+               movne   \irqstat, \tmp
+               addeq   \irqnr, \irqnr, #8
+
+               movs    \tmp, \irqstat, lsl #4
+               movne   \irqstat, \tmp
+               addeq   \irqnr, \irqnr, #4
+
+               movs    \tmp, \irqstat, lsl #2
+               movne   \irqstat, \tmp
+               addeq   \irqnr, \irqnr, #2
+
+               movs    \tmp, \irqstat, lsl #1
+               addeq   \irqnr, \irqnr, #1
+               orrs    \base, \base, #1
+1002:
+               @@ exit here, Z flag unset if IRQ
+
+       .endm
diff --git a/arch/arm/plat-tcc/include/mach/hardware.h b/arch/arm/plat-tcc/include/mach/hardware.h
new file mode 100644 (file)
index 0000000..e70d126
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Author: RidgeRun, Inc. Greg Lonnon <glonnon@ridgerun.com>
+ * Reorganized for Linux-2.6 by Tony Lindgren <tony@atomide.com>
+ *                          and Dirk Behme <dirk.behme@de.bosch.com>
+ * Rewritten by:    <linux@telechips.com>
+ * Description: Hardware definitions for TCC8300 processors and boards
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Copyright (C) 2008-2009 Telechips
+ *
+ * Modifications for mainline (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GNU Pulic License version 2.
+ */
+
+#ifndef __ASM_ARCH_TCC_HARDWARE_H
+#define __ASM_ARCH_TCC_HARDWARE_H
+
+#include <asm/sizes.h>
+#ifndef __ASSEMBLER__
+#include <asm/types.h>
+#endif
+#include <mach/io.h>
+
+/*
+ * ----------------------------------------------------------------------------
+ * Clocks
+ * ----------------------------------------------------------------------------
+ */
+#define CLKGEN_REG_BASE                0xfffece00
+#define ARM_CKCTL              (CLKGEN_REG_BASE + 0x0)
+#define ARM_IDLECT1            (CLKGEN_REG_BASE + 0x4)
+#define ARM_IDLECT2            (CLKGEN_REG_BASE + 0x8)
+#define ARM_EWUPCT             (CLKGEN_REG_BASE + 0xC)
+#define ARM_RSTCT1             (CLKGEN_REG_BASE + 0x10)
+#define ARM_RSTCT2             (CLKGEN_REG_BASE + 0x14)
+#define ARM_SYSST              (CLKGEN_REG_BASE + 0x18)
+#define ARM_IDLECT3            (CLKGEN_REG_BASE + 0x24)
+
+/* DPLL control registers */
+#define DPLL_CTL               0xfffecf00
+
+#endif /* __ASM_ARCH_TCC_HARDWARE_H */
diff --git a/arch/arm/plat-tcc/include/mach/io.h b/arch/arm/plat-tcc/include/mach/io.h
new file mode 100644 (file)
index 0000000..3e911d3
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * IO definitions for TCC8000 processors and boards
+ *
+ * Copyright (C) 1997-1999 Russell King
+ * Copyright (C) 2008-2009 Telechips
+ * Copyright (C) 2010 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GNU Public License version 2.
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+/*
+ * We don't actually have real ISA nor PCI buses, but there is so many
+ * drivers out there that might just work if we fake them...
+ */
+#define __io(a)                        __typesafe_io(a)
+#define __mem_pci(a)           (a)
+
+#endif
diff --git a/arch/arm/plat-tcc/include/mach/irqs.h b/arch/arm/plat-tcc/include/mach/irqs.h
new file mode 100644 (file)
index 0000000..da86389
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * IRQ definitions for TCC8xxx
+ *
+ * Copyright (C) 2008-2009 Telechips
+ * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPL v2.
+ *
+ */
+
+#ifndef __ASM_ARCH_TCC_IRQS_H
+#define __ASM_ARCH_TCC_IRQS_H
+
+#define NR_IRQS 64
+
+/* PIC0 interrupts */
+#define INT_ADMA1      0
+#define INT_BDMA       1
+#define INT_ADMA0      2
+#define INT_GDMA1      3
+#define INT_I2S0RX     4
+#define INT_I2S0TX     5
+#define INT_TC         6
+#define INT_UART0      7
+#define INT_USBD       8
+#define INT_SPI0TX     9
+#define INT_UDMA       10
+#define INT_LIRQ       11
+#define INT_GDMA2      12
+#define INT_GDMA0      13
+#define INT_TC32       14
+#define INT_LCD                15
+#define INT_ADC                16
+#define INT_I2C                17
+#define INT_RTCP       18
+#define INT_RTCA       19
+#define INT_NFC                20
+#define INT_SD0                21
+#define INT_GSB0       22
+#define INT_PK         23
+#define INT_USBH0      24
+#define INT_USBH1      25
+#define INT_G2D                26
+#define INT_ECC                27
+#define INT_SPI0RX     28
+#define INT_UART1      29
+#define INT_MSCL       30
+#define INT_GSB1       31
+/* PIC1 interrupts */
+#define INT_E0         32
+#define INT_E1         33
+#define INT_E2         34
+#define INT_E3         35
+#define INT_E4         36
+#define INT_E5         37
+#define INT_E6         38
+#define INT_E7         39
+#define INT_UART2      40
+#define INT_UART3      41
+#define INT_SPI1TX     42
+#define INT_SPI1RX     43
+#define INT_GSB2       44
+#define INT_SPDIF      45
+#define INT_CDIF       46
+#define INT_VBON       47
+#define INT_VBOFF      48
+#define INT_SD1                49
+#define INT_UART4      50
+#define INT_GDMA3      51
+#define INT_I2S1RX     52
+#define INT_I2S1TX     53
+#define INT_CAN0       54
+#define INT_CAN1       55
+#define INT_GSB3       56
+#define INT_KRST       57
+#define INT_UNUSED     58
+#define INT_SD0D3      59
+#define INT_SD1D3      60
+#define INT_GPS0       61
+#define INT_GPS1       62
+#define INT_GPS2       63
+
+#endif  /* ASM_ARCH_TCC_IRQS_H */
diff --git a/arch/arm/plat-tcc/include/mach/memory.h b/arch/arm/plat-tcc/include/mach/memory.h
new file mode 100644 (file)
index 0000000..cd91ba8
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 1999 ARM Limited
+ * Copyright (C) 2000 RidgeRun, Inc.
+ * Copyright (C) 2008-2009 Telechips
+ * Copyright (C) 2010 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPL v2.
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET            UL(0x20000000)
+
+#endif
diff --git a/arch/arm/plat-tcc/include/mach/system.h b/arch/arm/plat-tcc/include/mach/system.h
new file mode 100644 (file)
index 0000000..909e603
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Author: <linux@telechips.com>
+ * Created: June 10, 2008
+ * Description: LINUX SYSTEM FUNCTIONS for TCC83x
+ *
+ * Copyright (C) 2008-2009 Telechips
+ *
+ * Licensed under the terms of the GPL v2.
+ *
+ */
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+#include <linux/clk.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+extern void plat_tcc_reboot(void);
+
+static inline void arch_idle(void)
+{
+       cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+       plat_tcc_reboot();
+}
+
+#endif
diff --git a/arch/arm/plat-tcc/include/mach/tcc8k-regs.h b/arch/arm/plat-tcc/include/mach/tcc8k-regs.h
new file mode 100644 (file)
index 0000000..1d94282
--- /dev/null
@@ -0,0 +1,807 @@
+/*
+ * Telechips TCC8000 register definitions
+ *
+ * (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPLv2.
+ */
+
+#ifndef TCC8K_REGS_H
+#define TCC8K_REGS_H
+
+#include <linux/types.h>
+
+#define EXT_SDRAM_BASE         0x20000000
+#define INT_SRAM_BASE          0x30000000
+#define INT_SRAM_SIZE          SZ_32K
+#define CS0_BASE               0x40000000
+#define CS1_BASE               0x50000000
+#define CS1_SIZE               SZ_64K
+#define CS2_BASE               0x60000000
+#define CS3_BASE               0x70000000
+#define AHB_PERI_BASE          0x80000000
+#define AHB_PERI_SIZE          SZ_64K
+#define APB0_PERI_BASE         0x90000000
+#define APB0_PERI_SIZE         SZ_128K
+#define APB1_PERI_BASE         0x98000000
+#define APB1_PERI_SIZE         SZ_128K
+#define DATA_TCM_BASE          0xa0000000
+#define DATA_TCM_SIZE          SZ_8K
+#define EXT_MEM_CTRL_BASE      0xf0000000
+#define EXT_MEM_CTRL_SIZE      SZ_4K
+
+#define CS1_BASE_VIRT          (void __iomem *)0xf7000000
+#define AHB_PERI_BASE_VIRT     (void __iomem *)0xf4000000
+#define APB0_PERI_BASE_VIRT    (void __iomem *)0xf1000000
+#define APB1_PERI_BASE_VIRT    (void __iomem *)0xf2000000
+#define EXT_MEM_CTRL_BASE_VIRT (void __iomem *)0xf3000000
+#define INT_SRAM_BASE_VIRT     (void __iomem *)0xf5000000
+#define DATA_TCM_BASE_VIRT     (void __iomem *)0xf6000000
+
+#define __REG(x)     (*((volatile u32 *)(x)))
+
+/* USB Device Controller Registers */
+#define UDC_BASE       (AHB_PERI_BASE_VIRT + 0x8000)
+#define UDC_BASE_PHYS  (AHB_PERI_BASE + 0x8000)
+
+#define UDC_IR_OFFS            0x00
+#define UDC_EIR_OFFS           0x04
+#define UDC_EIER_OFFS          0x08
+#define UDC_FAR_OFFS           0x0c
+#define UDC_FNR_OFFS           0x10
+#define UDC_EDR_OFFS           0x14
+#define UDC_RT_OFFS            0x18
+#define UDC_SSR_OFFS           0x1c
+#define UDC_SCR_OFFS           0x20
+#define UDC_EP0SR_OFFS         0x24
+#define UDC_EP0CR_OFFS         0x28
+
+#define UDC_ESR_OFFS           0x2c
+#define UDC_ECR_OFFS           0x30
+#define UDC_BRCR_OFFS          0x34
+#define UDC_BWCR_OFFS          0x38
+#define UDC_MPR_OFFS           0x3c
+#define UDC_DCR_OFFS           0x40
+#define UDC_DTCR_OFFS          0x44
+#define UDC_DFCR_OFFS          0x48
+#define UDC_DTTCR1_OFFS                0x4c
+#define UDC_DTTCR2_OFFS                0x50
+#define UDC_ESR2_OFFS          0x54
+
+#define UDC_SCR2_OFFS          0x58
+#define UDC_EP0BUF_OFFS                0x60
+#define UDC_EP1BUF_OFFS                0x64
+#define UDC_EP2BUF_OFFS                0x68
+#define UDC_EP3BUF_OFFS                0x6c
+#define UDC_PLICR_OFFS         0xa0
+#define UDC_PCR_OFFS           0xa4
+
+#define UDC_UPCR0_OFFS         0xc8
+#define UDC_UPCR1_OFFS         0xcc
+#define UDC_UPCR2_OFFS         0xd0
+#define UDC_UPCR3_OFFS         0xd4
+
+/* Bits in UDC_EIR */
+#define UDC_EIR_EP0I           (1 << 0)
+#define UDC_EIR_EP1I           (1 << 1)
+#define UDC_EIR_EP2I           (1 << 2)
+#define UDC_EIR_EP3I           (1 << 3)
+#define UDC_EIR_EPI_MASK       0x0f
+
+/* Bits in UDC_EIER */
+#define UDC_EIER_EP0IE         (1 << 0)
+#define UDC_EIER_EP1IE         (1 << 1)
+#define UDC_EIER_EP2IE         (1 << 2)
+#define UDC_EIER_EP3IE         (1 << 3)
+
+/* Bits in UDC_FNR */
+#define UDC_FNR_FN_MASK                0x7ff
+#define UDC_FNR_SM             (1 << 13)
+#define UDC_FNR_FTL            (1 << 14)
+
+/* Bits in UDC_SSR */
+#define UDC_SSR_HFRES          (1 << 0)
+#define UDC_SSR_HFSUSP         (1 << 1)
+#define UDC_SSR_HFRM           (1 << 2)
+#define UDC_SSR_SDE            (1 << 3)
+#define UDC_SSR_HSP            (1 << 4)
+#define UDC_SSR_DM             (1 << 5)
+#define UDC_SSR_DP             (1 << 6)
+#define UDC_SSR_TBM            (1 << 7)
+#define UDC_SSR_VBON           (1 << 8)
+#define UDC_SSR_VBOFF          (1 << 9)
+#define UDC_SSR_EOERR          (1 << 10)
+#define UDC_SSR_DCERR          (1 << 11)
+#define UDC_SSR_TCERR          (1 << 12)
+#define UDC_SSR_BSERR          (1 << 13)
+#define UDC_SSR_TMERR          (1 << 14)
+#define UDC_SSR_BAERR          (1 << 15)
+
+/* Bits in UDC_SCR */
+#define UDC_SCR_HRESE          (1 << 0)
+#define UDC_SCR_HSSPE          (1 << 1)
+#define UDC_SCR_RRDE           (1 << 5)
+#define UDC_SCR_SPDEN          (1 << 6)
+#define UDC_SCR_DIEN           (1 << 12)
+
+/* Bits in UDC_EP0SR */
+#define UDC_EP0SR_RSR          (1 << 0)
+#define UDC_EP0SR_TST          (1 << 1)
+#define UDC_EP0SR_SHT          (1 << 4)
+#define UDC_EP0SR_LWO          (1 << 6)
+
+/* Bits in UDC_EP0CR */
+#define UDC_EP0CR_ESS          (1 << 1)
+
+/* Bits in UDC_ESR */
+#define UDC_ESR_RPS            (1 << 0)
+#define UDC_ESR_TPS            (1 << 1)
+#define UDC_ESR_LWO            (1 << 4)
+#define UDC_ESR_FFS            (1 << 6)
+
+/* Bits in UDC_ECR */
+#define UDC_ECR_ESS            (1 << 1)
+#define UDC_ECR_CDP            (1 << 2)
+
+#define UDC_ECR_FLUSH          (1 << 6)
+#define UDC_ECR_DUEN           (1 << 7)
+
+/* Bits in UDC_UPCR0 */
+#define UDC_UPCR0_VBD          (1 << 1)
+#define UDC_UPCR0_VBDS         (1 << 6)
+#define UDC_UPCR0_RCD_12       (0x0 << 9)
+#define UDC_UPCR0_RCD_24       (0x1 << 9)
+#define UDC_UPCR0_RCD_48       (0x2 << 9)
+#define UDC_UPCR0_RCS_EXT      (0x1 << 11)
+#define UDC_UPCR0_RCS_XTAL     (0x0 << 11)
+
+/* Bits in UDC_UPCR1 */
+#define UDC_UPCR1_CDT(x)       ((x) << 0)
+#define UDC_UPCR1_OTGT(x)      ((x) << 3)
+#define UDC_UPCR1_SQRXT(x)     ((x) << 8)
+#define UDC_UPCR1_TXFSLST(x)   ((x) << 12)
+
+/* Bits in UDC_UPCR2 */
+#define UDC_UPCR2_TP           (1 << 0)
+#define UDC_UPCR2_TXRT(x)      ((x) << 2)
+#define UDC_UPCR2_TXVRT(x)     ((x) << 5)
+#define UDC_UPCR2_OPMODE(x)    ((x) << 9)
+#define UDC_UPCR2_XCVRSEL(x)   ((x) << 12)
+#define UDC_UPCR2_TM           (1 << 14)
+
+/* USB Host Controller registers */
+#define USBH0_BASE     (AHB_PERI_BASE_VIRT + 0xb000)
+#define USBH1_BASE     (AHB_PERI_BASE_VIRT + 0xb800)
+
+#define OHCI_INT_ENABLE_OFFS   0x10
+
+#define RH_DESCRIPTOR_A_OFFS   0x48
+#define RH_DESCRIPTOR_B_OFFS   0x4c
+
+#define USBHTCFG0_OFFS         0x100
+#define USBHHCFG0_OFFS         0x104
+#define USBHHCFG1_OFFS         0x104
+
+/* DMA controller registers */
+#define DMAC0_BASE     (AHB_PERI_BASE + 0x4000)
+#define DMAC1_BASE     (AHB_PERI_BASE + 0xa000)
+#define DMAC2_BASE     (AHB_PERI_BASE + 0x4800)
+#define DMAC3_BASE     (AHB_PERI_BASE + 0xa800)
+
+#define DMAC_CH_OFFSET(ch)     (ch * 0x30)
+
+#define ST_SADR_OFFS           0x00
+#define SPARAM_OFFS            0x04
+#define C_SADR_OFFS            0x0c
+#define ST_DADR_OFFS           0x10
+#define DPARAM_OFFS            0x14
+#define C_DADR_OFFS            0x1c
+#define HCOUNT_OFFS            0x20
+#define CHCTRL_OFFS            0x24
+#define RPTCTRL_OFFS           0x28
+#define EXTREQ_A_OFFS          0x2c
+
+/* Bits in CHCTRL register */
+#define CHCTRL_EN              (1 << 0)
+
+#define CHCTRL_IEN             (1 << 2)
+#define CHCTRL_FLAG            (1 << 3)
+#define CHCTRL_WSIZE8          (0 << 4)
+#define CHCTRL_WSIZE16         (1 << 4)
+#define CHCTRL_WSIZE32         (2 << 4)
+
+#define CHCTRL_BSIZE1          (0 << 6)
+#define CHCTRL_BSIZE2          (1 << 6)
+#define CHCTRL_BSIZE4          (2 << 6)
+#define CHCTRL_BSIZE8          (3 << 6)
+
+#define CHCTRL_TYPE_SINGLE_E   (0 << 8)
+#define CHCTRL_TYPE_HW         (1 << 8)
+#define CHCTRL_TYPE_SW         (2 << 8)
+#define CHCTRL_TYPE_SINGLE_L   (3 << 8)
+
+#define CHCTRL_BST             (1 << 10)
+
+/* Use DMA controller 0, channel 2 for USB */
+#define USB_DMA_BASE           (DMAC0_BASE + DMAC_CH_OFFSET(2))
+
+/* NAND flash controller registers */
+#define NFC_BASE       (AHB_PERI_BASE_VIRT + 0xd000)
+#define NFC_BASE_PHYS  (AHB_PERI_BASE + 0xd000)
+
+#define NFC_CMD_OFFS           0x00
+#define NFC_LADDR_OFFS         0x04
+#define NFC_BADDR_OFFS         0x08
+#define NFC_SADDR_OFFS         0x0c
+#define NFC_WDATA_OFFS         0x10
+#define NFC_LDATA_OFFS         0x20
+#define NFC_SDATA_OFFS         0x40
+#define NFC_CTRL_OFFS          0x50
+#define NFC_PSTART_OFFS                0x54
+#define NFC_RSTART_OFFS                0x58
+#define NFC_DSIZE_OFFS         0x5c
+#define NFC_IREQ_OFFS          0x60
+#define NFC_RST_OFFS           0x64
+#define NFC_CTRL1_OFFS         0x68
+#define NFC_MDATA_OFFS         0x70
+
+#define NFC_WDATA_PHYS_ADDR    (NFC_BASE_PHYS + NFC_WDATA_OFFS)
+
+/* Bits in NFC_CTRL */
+#define NFC_CTRL_BHLD_MASK     (0xf << 0)
+#define NFC_CTRL_BPW_MASK      (0xf << 4)
+#define NFC_CTRL_BSTP_MASK     (0xf << 8)
+#define NFC_CTRL_CADDR_MASK    (0x7 << 12)
+#define NFC_CTRL_CADDR_1       (0x0 << 12)
+#define NFC_CTRL_CADDR_2       (0x1 << 12)
+#define NFC_CTRL_CADDR_3       (0x2 << 12)
+#define NFC_CTRL_CADDR_4       (0x3 << 12)
+#define NFC_CTRL_CADDR_5       (0x4 << 12)
+#define NFC_CTRL_MSK           (1 << 15)
+#define NFC_CTRL_PSIZE256      (0 << 16)
+#define NFC_CTRL_PSIZE512      (1 << 16)
+#define NFC_CTRL_PSIZE1024     (2 << 16)
+#define NFC_CTRL_PSIZE2048     (3 << 16)
+#define NFC_CTRL_PSIZE4096     (4 << 16)
+#define NFC_CTRL_PSIZE_MASK    (7 << 16)
+#define NFC_CTRL_BSIZE1                (0 << 19)
+#define NFC_CTRL_BSIZE2                (1 << 19)
+#define NFC_CTRL_BSIZE4                (2 << 19)
+#define NFC_CTRL_BSIZE8                (3 << 19)
+#define NFC_CTRL_BSIZE_MASK    (3 << 19)
+#define NFC_CTRL_RDY           (1 << 21)
+#define NFC_CTRL_CS0SEL                (1 << 22)
+#define NFC_CTRL_CS1SEL                (1 << 23)
+#define NFC_CTRL_CS2SEL                (1 << 24)
+#define NFC_CTRL_CS3SEL                (1 << 25)
+#define NFC_CTRL_CSMASK                (0xf << 22)
+#define NFC_CTRL_BW            (1 << 26)
+#define NFC_CTRL_FS            (1 << 27)
+#define NFC_CTRL_DEN           (1 << 28)
+#define NFC_CTRL_READ_IEN      (1 << 29)
+#define NFC_CTRL_PROG_IEN      (1 << 30)
+#define NFC_CTRL_RDY_IEN       (1 << 31)
+
+/* Bits in NFC_IREQ */
+#define NFC_IREQ_IRQ0          (1 << 0)
+#define NFC_IREQ_IRQ1          (1 << 1)
+#define NFC_IREQ_IRQ2          (1 << 2)
+
+#define NFC_IREQ_FLAG0         (1 << 4)
+#define NFC_IREQ_FLAG1         (1 << 5)
+#define NFC_IREQ_FLAG2         (1 << 6)
+
+/* MMC controller registers */
+#define MMC0_BASE      (AHB_PERI_BASE_VIRT + 0xe000)
+#define MMC1_BASE      (AHB_PERI_BASE_VIRT + 0xe800)
+
+/* UART base addresses */
+
+#define UART0_BASE     (APB0_PERI_BASE_VIRT + 0x07000)
+#define UART0_BASE_PHYS        (APB0_PERI_BASE + 0x07000)
+#define UART1_BASE     (APB0_PERI_BASE_VIRT + 0x08000)
+#define UART1_BASE_PHYS        (APB0_PERI_BASE + 0x08000)
+#define UART2_BASE     (APB0_PERI_BASE_VIRT + 0x09000)
+#define UART2_BASE_PHYS        (APB0_PERI_BASE + 0x09000)
+#define UART3_BASE     (APB0_PERI_BASE_VIRT + 0x0a000)
+#define UART3_BASE_PHYS        (APB0_PERI_BASE + 0x0a000)
+#define UART4_BASE     (APB0_PERI_BASE_VIRT + 0x15000)
+#define UART4_BASE_PHYS        (APB0_PERI_BASE + 0x15000)
+
+#define UART_BASE      UART0_BASE
+#define UART_BASE_PHYS UART0_BASE_PHYS
+
+/* ECC controller */
+#define ECC_CTR_BASE   (APB0_PERI_BASE_VIRT + 0xd000)
+
+#define ECC_CTRL_OFFS          0x00
+#define ECC_BASE_OFFS          0x04
+#define ECC_MASK_OFFS          0x08
+#define ECC_CLEAR_OFFS         0x0c
+#define ECC4_0_OFFS            0x10
+#define ECC4_1_OFFS            0x14
+
+#define ECC_EADDR0_OFFS                0x50
+
+#define ECC_ERRNUM_OFFS                0x90
+#define ECC_IREQ_OFFS          0x94
+
+/* Bits in ECC_CTRL */
+#define ECC_CTRL_ECC4_DIEN     (1 << 28)
+#define ECC_CTRL_ECC8_DIEN     (1 << 29)
+#define ECC_CTRL_ECC12_DIEN    (1 << 30)
+#define ECC_CTRL_ECC_DISABLE   0x0
+#define ECC_CTRL_ECC_SLC_ENC   0x8
+#define ECC_CTRL_ECC_SLC_DEC   0x9
+#define ECC_CTRL_ECC4_ENC      0xa
+#define ECC_CTRL_ECC4_DEC      0xb
+#define ECC_CTRL_ECC8_ENC      0xc
+#define ECC_CTRL_ECC8_DEC      0xd
+#define ECC_CTRL_ECC12_ENC     0xe
+#define ECC_CTRL_ECC12_DEC     0xf
+
+/* Bits in ECC_IREQ */
+#define ECC_IREQ_E4DI          (1 << 4)
+
+#define ECC_IREQ_E4DF          (1 << 20)
+#define ECC_IREQ_E4EF          (1 << 21)
+
+/* Interrupt controller */
+
+#define PIC0_BASE      (APB1_PERI_BASE_VIRT + 0x3000)
+#define PIC0_BASE_PHYS (APB1_PERI_BASE + 0x3000)
+
+#define PIC0_IEN_OFFS          0x00
+#define PIC0_CREQ_OFFS         0x04
+#define PIC0_IREQ_OFFS         0x08
+#define PIC0_IRQSEL_OFFS       0x0c
+#define PIC0_SRC_OFFS          0x10
+#define PIC0_MREQ_OFFS         0x14
+#define PIC0_TSTREQ_OFFS       0x18
+#define PIC0_POL_OFFS          0x1c
+#define PIC0_IRQ_OFFS          0x20
+#define PIC0_FIQ_OFFS          0x24
+#define PIC0_MIRQ_OFFS         0x28
+#define PIC0_MFIQ_OFFS         0x2c
+#define PIC0_TMODE_OFFS                0x30
+#define PIC0_SYNC_OFFS         0x34
+#define PIC0_WKUP_OFFS         0x38
+#define PIC0_TMODEA_OFFS       0x3c
+#define PIC0_INTOEN_OFFS       0x40
+#define PIC0_MEN0_OFFS         0x44
+#define PIC0_MEN_OFFS          0x48
+
+#define PIC0_IEN               __REG(PIC0_BASE + PIC0_IEN_OFFS)
+#define PIC0_IEN_PHYS          __REG(PIC0_BASE_PHYS + PIC0_IEN_OFFS)
+#define PIC0_CREQ              __REG(PIC0_BASE + PIC0_CREQ_OFFS)
+#define PIC0_CREQ_PHYS         __REG(PIC0_BASE_PHYS + PIC0_CREQ_OFFS)
+#define PIC0_IREQ              __REG(PIC0_BASE + PIC0_IREQ_OFFS)
+#define PIC0_IRQSEL            __REG(PIC0_BASE + PIC0_IRQSEL_OFFS)
+#define PIC0_IRQSEL_PHYS       __REG(PIC0_BASE_PHYS + PIC0_IRQSEL_OFFS)
+#define PIC0_SRC               __REG(PIC0_BASE + PIC0_SRC_OFFS)
+#define PIC0_MREQ              __REG(PIC0_BASE + PIC0_MREQ_OFFS)
+#define PIC0_TSTREQ            __REG(PIC0_BASE + PIC0_TSTREQ_OFFS)
+#define PIC0_POL               __REG(PIC0_BASE + PIC0_POL_OFFS)
+#define PIC0_IRQ               __REG(PIC0_BASE + PIC0_IRQ_OFFS)
+#define PIC0_FIQ               __REG(PIC0_BASE + PIC0_FIQ_OFFS)
+#define PIC0_MIRQ              __REG(PIC0_BASE + PIC0_MIRQ_OFFS)
+#define PIC0_MFIQ              __REG(PIC0_BASE + PIC0_MFIQ_OFFS)
+#define PIC0_TMODE             __REG(PIC0_BASE + PIC0_TMODE_OFFS)
+#define PIC0_TMODE_PHYS                __REG(PIC0_BASE_PHYS + PIC0_TMODE_OFFS)
+#define PIC0_SYNC              __REG(PIC0_BASE + PIC0_SYNC_OFFS)
+#define PIC0_WKUP              __REG(PIC0_BASE + PIC0_WKUP_OFFS)
+#define PIC0_TMODEA            __REG(PIC0_BASE + PIC0_TMODEA_OFFS)
+#define PIC0_INTOEN            __REG(PIC0_BASE + PIC0_INTOEN_OFFS)
+#define PIC0_MEN0              __REG(PIC0_BASE + PIC0_MEN0_OFFS)
+#define PIC0_MEN               __REG(PIC0_BASE + PIC0_MEN_OFFS)
+
+#define PIC1_BASE      (APB1_PERI_BASE_VIRT + 0x3080)
+
+#define PIC1_IEN_OFFS          0x00
+#define PIC1_CREQ_OFFS         0x04
+#define PIC1_IREQ_OFFS         0x08
+#define PIC1_IRQSEL_OFFS       0x0c
+#define PIC1_SRC_OFFS          0x10
+#define PIC1_MREQ_OFFS         0x14
+#define PIC1_TSTREQ_OFFS       0x18
+#define PIC1_POL_OFFS          0x1c
+#define PIC1_IRQ_OFFS          0x20
+#define PIC1_FIQ_OFFS          0x24
+#define PIC1_MIRQ_OFFS         0x28
+#define PIC1_MFIQ_OFFS         0x2c
+#define PIC1_TMODE_OFFS                0x30
+#define PIC1_SYNC_OFFS         0x34
+#define PIC1_WKUP_OFFS         0x38
+#define PIC1_TMODEA_OFFS       0x3c
+#define PIC1_INTOEN_OFFS       0x40
+#define PIC1_MEN1_OFFS         0x44
+#define PIC1_MEN_OFFS          0x48
+
+#define PIC1_IEN       __REG(PIC1_BASE + PIC1_IEN_OFFS)
+#define PIC1_CREQ      __REG(PIC1_BASE + PIC1_CREQ_OFFS)
+#define PIC1_IREQ      __REG(PIC1_BASE + PIC1_IREQ_OFFS)
+#define PIC1_IRQSEL    __REG(PIC1_BASE + PIC1_IRQSEL_OFFS)
+#define PIC1_SRC       __REG(PIC1_BASE + PIC1_SRC_OFFS)
+#define PIC1_MREQ      __REG(PIC1_BASE + PIC1_MREQ_OFFS)
+#define PIC1_TSTREQ    __REG(PIC1_BASE + PIC1_TSTREQ_OFFS)
+#define PIC1_POL       __REG(PIC1_BASE + PIC1_POL_OFFS)
+#define PIC1_IRQ       __REG(PIC1_BASE + PIC1_IRQ_OFFS)
+#define PIC1_FIQ       __REG(PIC1_BASE + PIC1_FIQ_OFFS)
+#define PIC1_MIRQ      __REG(PIC1_BASE + PIC1_MIRQ_OFFS)
+#define PIC1_MFIQ      __REG(PIC1_BASE + PIC1_MFIQ_OFFS)
+#define PIC1_TMODE     __REG(PIC1_BASE + PIC1_TMODE_OFFS)
+#define PIC1_SYNC      __REG(PIC1_BASE + PIC1_SYNC_OFFS)
+#define PIC1_WKUP      __REG(PIC1_BASE + PIC1_WKUP_OFFS)
+#define PIC1_TMODEA    __REG(PIC1_BASE + PIC1_TMODEA_OFFS)
+#define PIC1_INTOEN    __REG(PIC1_BASE + PIC1_INTOEN_OFFS)
+#define PIC1_MEN1      __REG(PIC1_BASE + PIC1_MEN1_OFFS)
+#define PIC1_MEN       __REG(PIC1_BASE + PIC1_MEN_OFFS)
+
+/* Timer registers */
+#define TIMER_BASE             (APB1_PERI_BASE_VIRT + 0x4000)
+#define TIMER_BASE_PHYS                (APB1_PERI_BASE + 0x4000)
+
+#define TWDCFG_OFFS            0x70
+
+#define TC32EN_OFFS            0x80
+#define TC32LDV_OFFS           0x84
+#define TC32CMP0_OFFS          0x88
+#define TC32CMP1_OFFS          0x8c
+#define TC32PCNT_OFFS          0x90
+#define TC32MCNT_OFFS          0x94
+#define TC32IRQ_OFFS           0x98
+
+/* Bits in TC32EN */
+#define TC32EN_PRESCALE_MASK   0x00ffffff
+#define TC32EN_ENABLE          (1 << 24)
+#define TC32EN_LOADZERO                (1 << 25)
+#define TC32EN_STOPMODE                (1 << 26)
+#define TC32EN_LDM0            (1 << 28)
+#define TC32EN_LDM1            (1 << 29)
+
+/* Bits in TC32IRQ */
+#define TC32IRQ_MSTAT_MASK     0x0000001f
+#define TC32IRQ_RSTAT_MASK     (0x1f << 8)
+#define TC32IRQ_IRQEN0         (1 << 16)
+#define TC32IRQ_IRQEN1         (1 << 17)
+#define TC32IRQ_IRQEN2         (1 << 18)
+#define TC32IRQ_IRQEN3         (1 << 19)
+#define TC32IRQ_IRQEN4         (1 << 20)
+#define TC32IRQ_RSYNC          (1 << 30)
+#define TC32IRQ_IRQCLR         (1 << 31)
+
+/* GPIO registers */
+#define GPIOPD_BASE            (APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOPD_DAT_OFFS                0x00
+#define GPIOPD_DOE_OFFS                0x04
+#define GPIOPD_FS0_OFFS                0x08
+#define GPIOPD_FS1_OFFS                0x0c
+#define GPIOPD_FS2_OFFS                0x10
+#define GPIOPD_RPU_OFFS                0x30
+#define GPIOPD_RPD_OFFS                0x34
+#define GPIOPD_DV0_OFFS                0x38
+#define GPIOPD_DV1_OFFS                0x3c
+
+#define GPIOPS_BASE            (APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOPS_DAT_OFFS                0x40
+#define GPIOPS_DOE_OFFS                0x44
+#define GPIOPS_FS0_OFFS                0x48
+#define GPIOPS_FS1_OFFS                0x4c
+#define GPIOPS_FS2_OFFS                0x50
+#define GPIOPS_FS3_OFFS                0x54
+#define GPIOPS_RPU_OFFS                0x70
+#define GPIOPS_RPD_OFFS                0x74
+#define GPIOPS_DV0_OFFS                0x78
+#define GPIOPS_DV1_OFFS                0x7c
+
+#define GPIOPS_FS1_SDH0_BITS   0x000000ff
+#define GPIOPS_FS1_SDH1_BITS   0x0000ff00
+
+#define GPIOPU_BASE            (APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOPU_DAT_OFFS                0x80
+#define GPIOPU_DOE_OFFS                0x84
+#define GPIOPU_FS0_OFFS                0x88
+#define GPIOPU_FS1_OFFS                0x8c
+#define GPIOPU_FS2_OFFS                0x90
+#define GPIOPU_RPU_OFFS                0xb0
+#define GPIOPU_RPD_OFFS                0xb4
+#define GPIOPU_DV0_OFFS                0xb8
+#define GPIOPU_DV1_OFFS                0xbc
+
+#define GPIOPU_FS0_TXD0                (1 << 0)
+#define GPIOPU_FS0_RXD0                (1 << 1)
+#define GPIOPU_FS0_CTS0                (1 << 2)
+#define GPIOPU_FS0_RTS0                (1 << 3)
+#define GPIOPU_FS0_TXD1                (1 << 4)
+#define GPIOPU_FS0_RXD1                (1 << 5)
+#define GPIOPU_FS0_CTS1                (1 << 6)
+#define GPIOPU_FS0_RTS1                (1 << 7)
+#define GPIOPU_FS0_TXD2                (1 << 8)
+#define GPIOPU_FS0_RXD2                (1 << 9)
+#define GPIOPU_FS0_CTS2                (1 << 10)
+#define GPIOPU_FS0_RTS2                (1 << 11)
+#define GPIOPU_FS0_TXD3                (1 << 12)
+#define GPIOPU_FS0_RXD3                (1 << 13)
+#define GPIOPU_FS0_CTS3                (1 << 14)
+#define GPIOPU_FS0_RTS3                (1 << 15)
+#define GPIOPU_FS0_TXD4                (1 << 16)
+#define GPIOPU_FS0_RXD4                (1 << 17)
+#define GPIOPU_FS0_CTS4                (1 << 18)
+#define GPIOPU_FS0_RTS4                (1 << 19)
+
+#define GPIOFC_BASE            (APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOFC_DAT_OFFS                0xc0
+#define GPIOFC_DOE_OFFS                0xc4
+#define GPIOFC_FS0_OFFS                0xc8
+#define GPIOFC_FS1_OFFS                0xcc
+#define GPIOFC_FS2_OFFS                0xd0
+#define GPIOFC_FS3_OFFS                0xd4
+#define GPIOFC_RPU_OFFS                0xf0
+#define GPIOFC_RPD_OFFS                0xf4
+#define GPIOFC_DV0_OFFS                0xf8
+#define GPIOFC_DV1_OFFS                0xfc
+
+#define GPIOFD_BASE            (APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOFD_DAT_OFFS                0x100
+#define GPIOFD_DOE_OFFS                0x104
+#define GPIOFD_FS0_OFFS                0x108
+#define GPIOFD_FS1_OFFS                0x10c
+#define GPIOFD_FS2_OFFS                0x110
+#define GPIOFD_RPU_OFFS                0x130
+#define GPIOFD_RPD_OFFS                0x134
+#define GPIOFD_DV0_OFFS                0x138
+#define GPIOFD_DV1_OFFS                0x13c
+
+#define GPIOLC_BASE            (APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOLC_DAT_OFFS                0x140
+#define GPIOLC_DOE_OFFS                0x144
+#define GPIOLC_FS0_OFFS                0x148
+#define GPIOLC_FS1_OFFS                0x14c
+#define GPIOLC_RPU_OFFS                0x170
+#define GPIOLC_RPD_OFFS                0x174
+#define GPIOLC_DV0_OFFS                0x178
+#define GPIOLC_DV1_OFFS                0x17c
+
+#define GPIOLD_BASE            (APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOLD_DAT_OFFS                0x180
+#define GPIOLD_DOE_OFFS                0x184
+#define GPIOLD_FS0_OFFS                0x188
+#define GPIOLD_FS1_OFFS                0x18c
+#define GPIOLD_FS2_OFFS                0x190
+#define GPIOLD_RPU_OFFS                0x1b0
+#define GPIOLD_RPD_OFFS                0x1b4
+#define GPIOLD_DV0_OFFS                0x1b8
+#define GPIOLD_DV1_OFFS                0x1bc
+
+#define GPIOAD_BASE            (APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOAD_DAT_OFFS                0x1c0
+#define GPIOAD_DOE_OFFS                0x1c4
+#define GPIOAD_FS0_OFFS                0x1c8
+#define GPIOAD_RPU_OFFS                0x1f0
+#define GPIOAD_RPD_OFFS                0x1f4
+#define GPIOAD_DV0_OFFS                0x1f8
+#define GPIOAD_DV1_OFFS                0x1fc
+
+#define GPIOXC_BASE            (APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOXC_DAT_OFFS                0x200
+#define GPIOXC_DOE_OFFS                0x204
+#define GPIOXC_FS0_OFFS                0x208
+#define GPIOXC_RPU_OFFS                0x230
+#define GPIOXC_RPD_OFFS                0x234
+#define GPIOXC_DV0_OFFS                0x238
+#define GPIOXC_DV1_OFFS                0x23c
+
+#define GPIOXC_FS0             __REG(GPIOXC_BASE + GPIOXC_FS0_OFFS)
+
+#define GPIOXC_FS0_CS0         (1 << 26)
+#define GPIOXC_FS0_CS1         (1 << 27)
+
+#define GPIOXD_BASE            (APB1_PERI_BASE_VIRT + 0x5000)
+
+#define GPIOXD_DAT_OFFS                0x240
+#define GPIOXD_FS0_OFFS                0x248
+#define GPIOXD_RPU_OFFS                0x270
+#define GPIOXD_RPD_OFFS                0x274
+#define GPIOXD_DV0_OFFS                0x278
+#define GPIOXD_DV1_OFFS                0x27c
+
+#define GPIOPK_BASE            (APB1_PERI_BASE_VIRT + 0x1c000)
+
+#define GPIOPK_RST_OFFS                0x008
+#define GPIOPK_DAT_OFFS                0x100
+#define GPIOPK_DOE_OFFS                0x104
+#define GPIOPK_FS0_OFFS                0x108
+#define GPIOPK_FS1_OFFS                0x10c
+#define GPIOPK_FS2_OFFS                0x110
+#define GPIOPK_IRQST_OFFS      0x210
+#define GPIOPK_IRQEN_OFFS      0x214
+#define GPIOPK_IRQPOL_OFFS     0x218
+#define GPIOPK_IRQTM0_OFFS     0x21c
+#define GPIOPK_IRQTM1_OFFS     0x220
+#define GPIOPK_CTL_OFFS                0x22c
+
+#define PMGPIO_BASE            (APB1_PERI_BASE_VIRT + 0x10000)
+#define BACKUP_RAM_BASE                PMGPIO_BASE
+
+#define PMGPIO_DAT_OFFS                0x800
+#define PMGPIO_DOE_OFFS                0x804
+#define PMGPIO_FS0_OFFS                0x808
+#define PMGPIO_RPU_OFFS                0x810
+#define PMGPIO_RPD_OFFS                0x814
+#define PMGPIO_DV0_OFFS                0x818
+#define PMGPIO_DV1_OFFS                0x81c
+#define PMGPIO_EE0_OFFS                0x820
+#define PMGPIO_EE1_OFFS                0x824
+#define PMGPIO_CTL_OFFS                0x828
+#define PMGPIO_DI_OFFS         0x82c
+#define PMGPIO_STR_OFFS                0x830
+#define PMGPIO_STF_OFFS                0x834
+#define PMGPIO_POL_OFFS                0x838
+#define PMGPIO_APB_OFFS                0x800
+
+/* Clock controller registers */
+#define CKC_BASE       ((void __iomem *)(APB1_PERI_BASE_VIRT + 0x6000))
+
+#define CLKCTRL_OFFS           0x00
+#define PLL0CFG_OFFS           0x04
+#define PLL1CFG_OFFS           0x08
+#define CLKDIVC0_OFFS          0x0c
+
+#define BCLKCTR0_OFFS          0x14
+#define SWRESET0_OFFS          0x18
+
+#define BCLKCTR1_OFFS          0x60
+#define SWRESET1_OFFS          0x64
+#define PWDCTL_OFFS            0x68
+#define PLL2CFG_OFFS           0x6c
+#define CLKDIVC1_OFFS          0x70
+
+#define ACLKREF_OFFS           0x80
+#define ACLKI2C_OFFS           0x84
+#define ACLKSPI0_OFFS          0x88
+#define ACLKSPI1_OFFS          0x8c
+#define ACLKUART0_OFFS         0x90
+#define ACLKUART1_OFFS         0x94
+#define ACLKUART2_OFFS         0x98
+#define ACLKUART3_OFFS         0x9c
+#define ACLKUART4_OFFS         0xa0
+#define ACLKTCT_OFFS           0xa4
+#define ACLKTCX_OFFS           0xa8
+#define ACLKTCZ_OFFS           0xac
+#define ACLKADC_OFFS           0xb0
+#define ACLKDAI0_OFFS          0xb4
+#define ACLKDAI1_OFFS          0xb8
+#define ACLKLCD_OFFS           0xbc
+#define ACLKSPDIF_OFFS         0xc0
+#define ACLKUSBH_OFFS          0xc4
+#define ACLKSDH0_OFFS          0xc8
+#define ACLKSDH1_OFFS          0xcc
+#define ACLKC3DEC_OFFS         0xd0
+#define ACLKEXT_OFFS           0xd4
+#define ACLKCAN0_OFFS          0xd8
+#define ACLKCAN1_OFFS          0xdc
+#define ACLKGSB0_OFFS          0xe0
+#define ACLKGSB1_OFFS          0xe4
+#define ACLKGSB2_OFFS          0xe8
+#define ACLKGSB3_OFFS          0xec
+
+#define PLLxCFG_PD             (1 << 31)
+
+/* CLKCTRL bits */
+#define CLKCTRL_XE             (1 << 31)
+
+/* CLKDIVCx bits */
+#define CLKDIVC0_XTE           (1 << 7)
+#define CLKDIVC0_XE            (1 << 15)
+#define CLKDIVC0_P1E           (1 << 23)
+#define CLKDIVC0_P0E           (1 << 31)
+
+#define CLKDIVC1_P2E           (1 << 7)
+
+/* BCLKCTR0 clock bits */
+#define BCLKCTR0_USBD          (1 << 4)
+#define BCLKCTR0_ECC           (1 << 9)
+#define BCLKCTR0_USBH0         (1 << 11)
+#define BCLKCTR0_NFC           (1 << 16)
+
+/* BCLKCTR1 clock bits */
+#define BCLKCTR1_USBH1         (1 << 20)
+
+/* SWRESET0 bits */
+#define SWRESET0_USBD          (1 << 4)
+#define SWRESET0_USBH0         (1 << 11)
+
+/* SWRESET1 bits */
+#define SWRESET1_USBH1         (1 << 20)
+
+/* System clock sources.
+ * Note: These are the clock sources that serve as parents for
+ * all other clocks. They have no parents themselves.
+ *
+ * These values are used for struct clk->root_id. All clocks
+ * that are not system clock sources have this value set to
+ * CLK_SRC_NOROOT.
+ * The values for system clocks start with CLK_SRC_PLL0 == 0
+ * because this gives us exactly the values needed for the lower
+ * 4 bits of ACLK_* registers. Therefore, CLK_SRC_NOROOT is
+ * defined as -1 to not disturb the order.
+ */
+enum root_clks {
+       CLK_SRC_NOROOT = -1,
+       CLK_SRC_PLL0 = 0,
+       CLK_SRC_PLL1,
+       CLK_SRC_PLL0DIV,
+       CLK_SRC_PLL1DIV,
+       CLK_SRC_XI,
+       CLK_SRC_XIDIV,
+       CLK_SRC_XTI,
+       CLK_SRC_XTIDIV,
+       CLK_SRC_PLL2,
+       CLK_SRC_PLL2DIV,
+       CLK_SRC_PK0,
+       CLK_SRC_PK1,
+       CLK_SRC_PK2,
+       CLK_SRC_PK3,
+       CLK_SRC_PK4,
+       CLK_SRC_48MHZ
+};
+
+#define CLK_SRC_MASK           0xf
+
+/* Bits in ACLK* registers */
+#define ACLK_EN                (1 << 28)
+#define ACLK_SEL_SHIFT         24
+#define ACLK_SEL_MASK          0x0f000000
+#define ACLK_DIV_MASK          0x00000fff
+
+/* System configuration registers */
+
+#define SCFG_BASE              (APB1_PERI_BASE_VIRT + 0x13000)
+
+#define        BMI_OFFS                0x00
+#define AHBCON0_OFFS           0x04
+#define APBPWE_OFFS            0x08
+#define DTCMWAIT_OFFS          0x0c
+#define ECCSEL_OFFS            0x10
+#define AHBCON1_OFFS           0x14
+#define SDHCFG_OFFS            0x18
+#define REMAP_OFFS             0x20
+#define LCDSIAE_OFFS           0x24
+#define XMCCFG_OFFS            0xe0
+#define IMCCFG_OFFS            0xe4
+
+/* Values for ECCSEL */
+#define ECCSEL_EXTMEM          0x0
+#define ECCSEL_DTCM            0x1
+#define ECCSEL_INT_SRAM                0x2
+#define ECCSEL_AHB             0x3
+
+/* Bits in XMCCFG */
+#define XMCCFG_NFCE            (1 << 1)
+#define XMCCFG_FDXD            (1 << 2)
+
+/* External memory controller registers */
+
+#define EMC_BASE               EXT_MEM_CTRL_BASE
+
+#define SDCFG_OFFS             0x00
+#define SDFSM_OFFS             0x04
+#define MCFG_OFFS              0x08
+
+#define CSCFG0_OFFS            0x10
+#define CSCFG1_OFFS            0x14
+#define CSCFG2_OFFS            0x18
+#define CSCFG3_OFFS            0x1c
+
+#define MCFG_SDEN              (1 << 4)
+
+#endif /* TCC8K_REGS_H */
diff --git a/arch/arm/plat-tcc/include/mach/timex.h b/arch/arm/plat-tcc/include/mach/timex.h
new file mode 100644 (file)
index 0000000..057acbe
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * A definition needed by arch core code.
+ *
+ */
+#define CLOCK_TICK_RATE                (HZ * 100000UL)
diff --git a/arch/arm/plat-tcc/include/mach/uncompress.h b/arch/arm/plat-tcc/include/mach/uncompress.h
new file mode 100644 (file)
index 0000000..7a3e33a
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 Hans J. Koch <hjk@linutronix.de>
+ *
+ * This file is licensed under the terms of the GPL version 2.
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/types.h>
+
+#include <mach/tcc8k-regs.h>
+
+unsigned int system_rev;
+
+#define ID_MASK                        0x7fff
+
+static void putc(int c)
+{
+       u32 *uart_lsr = (u32 *)(UART_BASE_PHYS + (UART_LSR << 2));
+       u32 *uart_tx = (u32 *)(UART_BASE_PHYS + (UART_TX << 2));
+
+       while (!(*uart_lsr & UART_LSR_THRE))
+               barrier();
+       *uart_tx = c;
+}
+
+static inline void flush(void)
+{
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/arch/arm/plat-tcc/include/mach/vmalloc.h b/arch/arm/plat-tcc/include/mach/vmalloc.h
new file mode 100644 (file)
index 0000000..99414d9
--- /dev/null
@@ -0,0 +1,10 @@
+/*
+ * Author: <linux@telechips.com>
+ * Created: June 10, 2008
+ *
+ * Copyright (C) 2000 Russell King.
+ * Copyright (C) 2008-2009 Telechips
+ *
+ * Licensed under the terms of the GPL v2.
+ */
+#define VMALLOC_END    0xf0000000UL
diff --git a/arch/arm/plat-tcc/system.c b/arch/arm/plat-tcc/system.c
new file mode 100644 (file)
index 0000000..cc208fa
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * System functions for Telechips TCCxxxx SoCs
+ *
+ * Copyright (C) Hans J. Koch <hjk@linutronix.de>
+ *
+ * Licensed under the terms of the GPL v2.
+ *
+ */
+
+#include <linux/io.h>
+
+#include <mach/tcc8k-regs.h>
+
+/* System reboot */
+void plat_tcc_reboot(void)
+{
+       /* Make sure clocks are on */
+       __raw_writel(0xffffffff, CKC_BASE + BCLKCTR0_OFFS);
+
+       /* Enable watchdog reset */
+       __raw_writel(0x49, TIMER_BASE + TWDCFG_OFFS);
+       /* Wait for reset */
+       while(1)
+               ;
+}
index f51572772e217d5ba9b674ffa2a5d68e5f13ca00..9ac87255a03a335917d994ddaa855f1ba180da79 100644 (file)
@@ -90,6 +90,7 @@ config PLATFORM_AT32AP
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_ALLOCATOR
        select HAVE_FB_ATMEL
+       select HAVE_NET_MACB
 
 #
 # CPU types
index 93570daac38ac47360bc16868be7eb6ada8fbaa8..006e9487372dc2d188672f37e5731b6699f5fdc2 100644 (file)
@@ -8,16 +8,14 @@
 #ifndef __ASM_AVR32_IRQFLAGS_H
 #define __ASM_AVR32_IRQFLAGS_H
 
+#include <linux/types.h>
 #include <asm/sysreg.h>
 
-static inline unsigned long __raw_local_save_flags(void)
+static inline unsigned long arch_local_save_flags(void)
 {
        return sysreg_read(SR);
 }
 
-#define raw_local_save_flags(x)                                        \
-       do { (x) = __raw_local_save_flags(); } while (0)
-
 /*
  * This will restore ALL status register flags, not only the interrupt
  * mask flag.
@@ -25,44 +23,39 @@ static inline unsigned long __raw_local_save_flags(void)
  * The empty asm statement informs the compiler of this fact while
  * also serving as a barrier.
  */
-static inline void raw_local_irq_restore(unsigned long flags)
+static inline void arch_local_irq_restore(unsigned long flags)
 {
        sysreg_write(SR, flags);
        asm volatile("" : : : "memory", "cc");
 }
 
-static inline void raw_local_irq_disable(void)
+static inline void arch_local_irq_disable(void)
 {
        asm volatile("ssrf %0" : : "n"(SYSREG_GM_OFFSET) : "memory");
 }
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_enable(void)
 {
        asm volatile("csrf %0" : : "n"(SYSREG_GM_OFFSET) : "memory");
 }
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
        return (flags & SYSREG_BIT(GM)) != 0;
 }
 
-static inline int raw_irqs_disabled(void)
+static inline bool arch_irqs_disabled(void)
 {
-       unsigned long flags = __raw_local_save_flags();
-
-       return raw_irqs_disabled_flags(flags);
+       return arch_irqs_disabled_flags(arch_local_save_flags());
 }
 
-static inline unsigned long __raw_local_irq_save(void)
+static inline unsigned long arch_local_irq_save(void)
 {
-       unsigned long flags = __raw_local_save_flags();
+       unsigned long flags = arch_local_save_flags();
 
-       raw_local_irq_disable();
+       arch_local_irq_disable();
 
        return flags;
 }
 
-#define raw_local_irq_save(flags)                              \
-       do { (flags) = __raw_local_irq_save(); } while (0)
-
 #endif /* __ASM_AVR32_IRQFLAGS_H */
index ed4f8c6db0cdd12778ca41d561fa0760a7564dbe..4223cf08ce8359e377a87b4321e09c98863f158d 100644 (file)
 
 #define MIN_SPI_BAUD_VAL       2
 
-#define SPI_READ              0
-#define SPI_WRITE             1
-
-#define SPI_CTRL_OFF            0x0
-#define SPI_FLAG_OFF            0x4
-#define SPI_STAT_OFF            0x8
-#define SPI_TXBUFF_OFF          0xc
-#define SPI_RXBUFF_OFF          0x10
-#define SPI_BAUD_OFF            0x14
-#define SPI_SHAW_OFF            0x18
-
-
 #define BIT_CTL_ENABLE      0x4000
 #define BIT_CTL_OPENDRAIN   0x2000
 #define BIT_CTL_MASTER      0x1000
-#define BIT_CTL_POLAR       0x0800
-#define BIT_CTL_PHASE       0x0400
-#define BIT_CTL_BITORDER    0x0200
+#define BIT_CTL_CPOL        0x0800
+#define BIT_CTL_CPHA        0x0400
+#define BIT_CTL_LSBF        0x0200
 #define BIT_CTL_WORDSIZE    0x0100
-#define BIT_CTL_MISOENABLE  0x0020
+#define BIT_CTL_EMISO       0x0020
+#define BIT_CTL_PSSE        0x0010
+#define BIT_CTL_GM          0x0008
+#define BIT_CTL_SZ          0x0004
 #define BIT_CTL_RXMOD       0x0000
 #define BIT_CTL_TXMOD       0x0001
 #define BIT_CTL_TIMOD_DMA_TX 0x0003
 #define BIT_STU_SENDOVER    0x0001
 #define BIT_STU_RECVFULL    0x0020
 
-#define CFG_SPI_ENABLE      1
-#define CFG_SPI_DISABLE     0
-
-#define CFG_SPI_OUTENABLE   1
-#define CFG_SPI_OUTDISABLE  0
-
-#define CFG_SPI_ACTLOW      1
-#define CFG_SPI_ACTHIGH     0
-
-#define CFG_SPI_PHASESTART  1
-#define CFG_SPI_PHASEMID    0
-
-#define CFG_SPI_MASTER      1
-#define CFG_SPI_SLAVE       0
-
-#define CFG_SPI_SENELAST    0
-#define CFG_SPI_SENDZERO    1
-
-#define CFG_SPI_RCVFLUSH    1
-#define CFG_SPI_RCVDISCARD  0
-
-#define CFG_SPI_LSBFIRST    1
-#define CFG_SPI_MSBFIRST    0
-
-#define CFG_SPI_WORDSIZE16  1
-#define CFG_SPI_WORDSIZE8   0
-
-#define CFG_SPI_MISOENABLE   1
-#define CFG_SPI_MISODISABLE  0
-
-#define CFG_SPI_READ      0x00
-#define CFG_SPI_WRITE     0x01
-#define CFG_SPI_DMAREAD   0x02
-#define CFG_SPI_DMAWRITE  0x03
-
-#define CFG_SPI_CSCLEARALL  0
-#define CFG_SPI_CHIPSEL1    1
-#define CFG_SPI_CHIPSEL2    2
-#define CFG_SPI_CHIPSEL3    3
-#define CFG_SPI_CHIPSEL4    4
-#define CFG_SPI_CHIPSEL5    5
-#define CFG_SPI_CHIPSEL6    6
-#define CFG_SPI_CHIPSEL7    7
-
-#define CFG_SPI_CS1VALUE    1
-#define CFG_SPI_CS2VALUE    2
-#define CFG_SPI_CS3VALUE    3
-#define CFG_SPI_CS4VALUE    4
-#define CFG_SPI_CS5VALUE    5
-#define CFG_SPI_CS6VALUE    6
-#define CFG_SPI_CS7VALUE    7
-
-#define CMD_SPI_SET_BAUDRATE  2
-#define CMD_SPI_GET_SYSTEMCLOCK   25
-#define CMD_SPI_SET_WRITECONTINUOUS     26
+#define MAX_CTRL_CS          8  /* cs in spi controller */
 
 /* device.platform_data for SSP controller devices */
 struct bfin5xx_spi_master {
@@ -120,9 +57,7 @@ struct bfin5xx_spi_chip {
        u16 ctl_reg;
        u8 enable_dma;
        u8 bits_per_word;
-       u8 cs_change_per_word;
        u16 cs_chg_udelay; /* Some devices require 16-bit delays */
-       u32 cs_gpio;
        /* Value to send if no TX value is supplied, usually 0x0 or 0xFFFF */
        u16 idle_tx_val;
        u8 pio_interrupt; /* Enable spi data irq */
index d3b40449ca0e20e07efa820272748000ebd35961..40f94a704c0202ace94e99429d7b67cb241d40f1 100644 (file)
@@ -49,7 +49,7 @@
 #define prepare_arch_switch(next)              \
 do {                                           \
        ipipe_schedule_notify(current, next);   \
-       local_irq_disable_hw();                 \
+       hard_local_irq_disable();                       \
 } while (0)
 
 #define task_hijacked(p)                                               \
@@ -57,7 +57,7 @@ do {                                          \
                int __x__ = __ipipe_root_domain_p;                      \
                __clear_bit(IPIPE_SYNC_FLAG, &ipipe_root_cpudom_var(status)); \
                if (__x__)                                              \
-                       local_irq_enable_hw();                          \
+                       hard_local_irq_enable();                                \
                !__x__;                                                 \
        })
 
@@ -167,7 +167,7 @@ static inline unsigned long __ipipe_ffnz(unsigned long ul)
 #define __ipipe_run_isr(ipd, irq)                                      \
        do {                                                            \
                if (!__ipipe_pipeline_head_p(ipd))                      \
-                       local_irq_enable_hw();                          \
+                       hard_local_irq_enable();                                \
                if (ipd == ipipe_root_domain) {                         \
                        if (unlikely(ipipe_virtual_irq_p(irq))) {       \
                                irq_enter();                            \
@@ -183,7 +183,7 @@ static inline unsigned long __ipipe_ffnz(unsigned long ul)
                        __ipipe_run_irqtail();                          \
                        __set_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \
                }                                                       \
-               local_irq_disable_hw();                                 \
+               hard_local_irq_disable();                                       \
        } while (0)
 
 #define __ipipe_syscall_watched_p(p, sc)       \
index 813a1af3e865e589f5cf17a822796e79297a884f..41c4d70544ef4811cd23c85f03c68122221f7aae 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __ASM_BFIN_IRQFLAGS_H__
 #define __ASM_BFIN_IRQFLAGS_H__
 
+#include <mach/blackfin.h>
+
 #ifdef CONFIG_SMP
 # include <asm/pda.h>
 # include <asm/processor.h>
@@ -31,54 +33,108 @@ static inline unsigned long bfin_cli(void)
        return flags;
 }
 
-#ifdef CONFIG_IPIPE
-
-#include <linux/compiler.h>
-#include <linux/ipipe_base.h>
-#include <linux/ipipe_trace.h>
-
 #ifdef CONFIG_DEBUG_HWERR
 # define bfin_no_irqs 0x3f
 #else
 # define bfin_no_irqs 0x1f
 #endif
 
-#define raw_local_irq_disable()                                \
-       do {                                            \
-               ipipe_check_context(ipipe_root_domain); \
-               __ipipe_stall_root();                   \
-               barrier();                              \
-       } while (0)
+/*****************************************************************************/
+/*
+ * Hard, untraced CPU interrupt flag manipulation and access.
+ */
+static inline void __hard_local_irq_disable(void)
+{
+       bfin_cli();
+}
+
+static inline void __hard_local_irq_enable(void)
+{
+       bfin_sti(bfin_irq_flags);
+}
+
+static inline unsigned long hard_local_save_flags(void)
+{
+       return bfin_read_IMASK();
+}
 
-#define raw_local_irq_enable()                         \
-       do {                                            \
-               barrier();                              \
-               ipipe_check_context(ipipe_root_domain); \
-               __ipipe_unstall_root();                 \
-       } while (0)
+static inline unsigned long __hard_local_irq_save(void)
+{
+       unsigned long flags;
+       flags = bfin_cli();
+#ifdef CONFIG_DEBUG_HWERR
+       bfin_sti(0x3f);
+#endif
+       return flags;
+}
+
+static inline int hard_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags & ~0x3f) == 0;
+}
+
+static inline int hard_irqs_disabled(void)
+{
+       unsigned long flags = hard_local_save_flags();
+       return hard_irqs_disabled_flags(flags);
+}
+
+static inline void __hard_local_irq_restore(unsigned long flags)
+{
+       if (!hard_irqs_disabled_flags(flags))
+               __hard_local_irq_enable();
+}
+
+/*****************************************************************************/
+/*
+ * Interrupt pipe handling.
+ */
+#ifdef CONFIG_IPIPE
+
+#include <linux/compiler.h>
+#include <linux/ipipe_base.h>
+#include <linux/ipipe_trace.h>
+
+/*
+ * Interrupt pipe interface to linux/irqflags.h.
+ */
+static inline void arch_local_irq_disable(void)
+{
+       ipipe_check_context(ipipe_root_domain);
+       __ipipe_stall_root();
+       barrier();
+}
 
-#define raw_local_save_flags_ptr(x)                                    \
-       do {                                                            \
-               *(x) = __ipipe_test_root() ? bfin_no_irqs : bfin_irq_flags; \
-       } while (0)
+static inline void arch_local_irq_enable(void)
+{
+       barrier();
+       ipipe_check_context(ipipe_root_domain);
+       __ipipe_unstall_root();
+}
 
-#define raw_local_save_flags(x)                raw_local_save_flags_ptr(&(x))
+static inline unsigned long arch_local_save_flags(void)
+{
+       return __ipipe_test_root() ? bfin_no_irqs : bfin_irq_flags;
+}
 
-#define raw_irqs_disabled_flags(x)     ((x) == bfin_no_irqs)
+static inline int arch_irqs_disabled_flags(unsigned long flags)
+{
+       return flags == bfin_no_irqs;
+}
 
-#define raw_local_irq_save_ptr(x)                                      \
-       do {                                                            \
-               *(x) = __ipipe_test_and_stall_root() ? bfin_no_irqs : bfin_irq_flags; \
-               barrier();                                              \
-       } while (0)
+static inline void arch_local_irq_save_ptr(unsigned long *_flags)
+{
+       x = __ipipe_test_and_stall_root() ? bfin_no_irqs : bfin_irq_flags;
+       barrier();
+}
 
-#define raw_local_irq_save(x)                          \
-       do {                                            \
-               ipipe_check_context(ipipe_root_domain); \
-               raw_local_irq_save_ptr(&(x));           \
-       } while (0)
+static inline unsigned long arch_local_irq_save(void)
+{
+       ipipe_check_context(ipipe_root_domain);
+       return __hard_local_irq_save();
+}
 
-static inline unsigned long raw_mangle_irq_bits(int virt, unsigned long real)
+static inline unsigned long arch_mangle_irq_bits(int virt, unsigned long real)
 {
        /*
         * Merge virtual and real interrupt mask bits into a single
@@ -87,130 +143,79 @@ static inline unsigned long raw_mangle_irq_bits(int virt, unsigned long real)
        return (real & ~(1 << 31)) | ((virt != 0) << 31);
 }
 
-static inline int raw_demangle_irq_bits(unsigned long *x)
+static inline int arch_demangle_irq_bits(unsigned long *x)
 {
        int virt = (*x & (1 << 31)) != 0;
        *x &= ~(1L << 31);
        return virt;
 }
 
-static inline void local_irq_disable_hw_notrace(void)
+/*
+ * Interface to various arch routines that may be traced.
+ */
+#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
+static inline void hard_local_irq_disable(void)
 {
-       bfin_cli();
+       if (!hard_irqs_disabled()) {
+               __hard_local_irq_disable();
+               ipipe_trace_begin(0x80000000);
+       }
 }
 
-static inline void local_irq_enable_hw_notrace(void)
+static inline void hard_local_irq_enable(void)
 {
-       bfin_sti(bfin_irq_flags);
+       if (hard_irqs_disabled()) {
+               ipipe_trace_end(0x80000000);
+               __hard_local_irq_enable();
+       }
 }
 
-#define local_save_flags_hw(flags)                     \
-       do {                                            \
-               (flags) = bfin_read_IMASK();            \
-       } while (0)
-
-#define irqs_disabled_flags_hw(flags) (((flags) & ~0x3f) == 0)
-
-#define irqs_disabled_hw()                     \
-       ({                                      \
-       unsigned long flags;                    \
-       local_save_flags_hw(flags);             \
-       irqs_disabled_flags_hw(flags);          \
-       })
-
-static inline void local_irq_save_ptr_hw(unsigned long *flags)
+static inline unsigned long hard_local_irq_save(void)
 {
-       *flags = bfin_cli();
-#ifdef CONFIG_DEBUG_HWERR
-       bfin_sti(0x3f);
-#endif
+       unsigned long flags = hard_local_save_flags();
+       if (!hard_irqs_disabled_flags(flags)) {
+               __hard_local_irq_disable();
+               ipipe_trace_begin(0x80000001);
+       }
+       return flags;
 }
 
-#define local_irq_save_hw_notrace(flags)               \
-       do {                                            \
-               local_irq_save_ptr_hw(&(flags));        \
-       } while (0)
-
-static inline void local_irq_restore_hw_notrace(unsigned long flags)
+static inline void hard_local_irq_restore(unsigned long flags)
 {
-       if (!irqs_disabled_flags_hw(flags))
-               local_irq_enable_hw_notrace();
+       if (!hard_irqs_disabled_flags(flags)) {
+               ipipe_trace_end(0x80000001);
+               __hard_local_irq_enable();
+       }
 }
 
-#ifdef CONFIG_IPIPE_TRACE_IRQSOFF
-# define local_irq_disable_hw()                                \
-       do {                                            \
-               if (!irqs_disabled_hw()) {              \
-                       local_irq_disable_hw_notrace(); \
-                       ipipe_trace_begin(0x80000000);  \
-               }                                       \
-       } while (0)
-# define local_irq_enable_hw()                         \
-       do {                                            \
-               if (irqs_disabled_hw()) {               \
-                       ipipe_trace_end(0x80000000);    \
-                       local_irq_enable_hw_notrace();  \
-               }                                       \
-       } while (0)
-# define local_irq_save_hw(flags)                      \
-       do {                                            \
-               local_save_flags_hw(flags);             \
-               if (!irqs_disabled_flags_hw(flags)) {   \
-                       local_irq_disable_hw_notrace(); \
-                       ipipe_trace_begin(0x80000001);  \
-               }                                       \
-       } while (0)
-# define local_irq_restore_hw(flags)                   \
-       do {                                            \
-               if (!irqs_disabled_flags_hw(flags)) {   \
-                       ipipe_trace_end(0x80000001);    \
-                       local_irq_enable_hw_notrace();  \
-               }                                       \
-       } while (0)
 #else /* !CONFIG_IPIPE_TRACE_IRQSOFF */
-# define local_irq_disable_hw()                local_irq_disable_hw_notrace()
-# define local_irq_enable_hw()         local_irq_enable_hw_notrace()
-# define local_irq_save_hw(flags)      local_irq_save_hw_notrace(flags)
-# define local_irq_restore_hw(flags)   local_irq_restore_hw_notrace(flags)
+# define hard_local_irq_disable()      __hard_local_irq_disable()
+# define hard_local_irq_enable()       __hard_local_irq_enable()
+# define hard_local_irq_save()         __hard_local_irq_save()
+# define hard_local_irq_restore(flags) __hard_local_irq_restore(flags)
 #endif /* !CONFIG_IPIPE_TRACE_IRQSOFF */
 
 #else /* CONFIG_IPIPE */
 
-static inline void raw_local_irq_disable(void)
-{
-       bfin_cli();
-}
-static inline void raw_local_irq_enable(void)
-{
-       bfin_sti(bfin_irq_flags);
-}
-
-#define raw_local_save_flags(flags) do { (flags) = bfin_read_IMASK(); } while (0)
-
-#define raw_irqs_disabled_flags(flags) (((flags) & ~0x3f) == 0)
+/*
+ * Direct interface to linux/irqflags.h.
+ */
+#define arch_local_save_flags()                hard_local_save_flags()
+#define arch_local_irq_save(flags)     __hard_local_irq_save()
+#define arch_local_irq_restore(flags)  __hard_local_irq_restore(flags)
+#define arch_local_irq_enable()                __hard_local_irq_enable()
+#define arch_local_irq_disable()       __hard_local_irq_disable()
+#define arch_irqs_disabled_flags(flags)        hard_irqs_disabled_flags(flags)
+#define arch_irqs_disabled()           hard_irqs_disabled()
 
-static inline unsigned long __raw_local_irq_save(void)
-{
-       unsigned long flags = bfin_cli();
-#ifdef CONFIG_DEBUG_HWERR
-       bfin_sti(0x3f);
-#endif
-       return flags;
-}
-#define raw_local_irq_save(flags) do { (flags) = __raw_local_irq_save(); } while (0)
+/*
+ * Interface to various arch routines that may be traced.
+ */
+#define hard_local_irq_save()          __hard_local_irq_save()
+#define hard_local_irq_restore(flags)  __hard_local_irq_restore(flags)
+#define hard_local_irq_enable()                __hard_local_irq_enable()
+#define hard_local_irq_disable()       __hard_local_irq_disable()
 
-#define local_irq_save_hw(flags)       raw_local_irq_save(flags)
-#define local_irq_restore_hw(flags)    raw_local_irq_restore(flags)
-#define local_irq_enable_hw()          raw_local_irq_enable()
-#define local_irq_disable_hw()         raw_local_irq_disable()
-#define irqs_disabled_hw()             irqs_disabled()
 
 #endif /* !CONFIG_IPIPE */
-
-static inline void raw_local_irq_restore(unsigned long flags)
-{
-       if (!raw_irqs_disabled_flags(flags))
-               raw_local_irq_enable();
-}
-
 #endif
index e1a9b4624f919ddae4675b1a8ff122e89944c764..3828c70e7a2ecb2e7ef0651a102de174f8c3ca49 100644 (file)
@@ -97,8 +97,8 @@ static inline void __switch_mm(struct mm_struct *prev_mm, struct mm_struct *next
 }
 
 #ifdef CONFIG_IPIPE
-#define lock_mm_switch(flags)  local_irq_save_hw_cond(flags)
-#define unlock_mm_switch(flags)        local_irq_restore_hw_cond(flags)
+#define lock_mm_switch(flags)  flags = hard_local_irq_save_cond()
+#define unlock_mm_switch(flags)        hard_local_irq_restore_cond(flags)
 #else
 #define lock_mm_switch(flags)  do { (void)(flags); } while (0)
 #define unlock_mm_switch(flags)        do { (void)(flags); } while (0)
@@ -205,9 +205,9 @@ static inline void destroy_context(struct mm_struct *mm)
 }
 
 #define ipipe_mm_switch_protect(flags)         \
-       local_irq_save_hw_cond(flags)
+       flags = hard_local_irq_save_cond()
 
 #define ipipe_mm_switch_unprotect(flags)       \
-       local_irq_restore_hw_cond(flags)
+       hard_local_irq_restore_cond(flags)
 
 #endif
index dde19b1d25f51020cf359aeda42bfede292fd25e..19e2c7c3e63ac41bf62f2e55a4db10d6bf97a13f 100644 (file)
@@ -117,7 +117,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
        unsigned long tmp = 0;
        unsigned long flags;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        switch (size) {
        case 1:
@@ -139,7 +139,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
                         : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory");
                break;
        }
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
        return tmp;
 }
 
index dc07ed08b37f858403f716093d211d0793576b00..ca1c1f9debd68814c996f242ff91546f40e0133e 100644 (file)
@@ -349,13 +349,13 @@ inline void portmux_setup(unsigned short per)
 void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
 { \
        unsigned long flags; \
-       local_irq_save_hw(flags); \
+       flags = hard_local_irq_save(); \
        if (arg) \
                gpio_array[gpio_bank(gpio)]->name |= gpio_bit(gpio); \
        else \
                gpio_array[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \
        AWA_DUMMY_READ(name); \
-       local_irq_restore_hw(flags); \
+       hard_local_irq_restore(flags); \
 } \
 EXPORT_SYMBOL(set_gpio_ ## name);
 
@@ -371,14 +371,14 @@ void set_gpio_ ## name(unsigned gpio, unsigned short arg) \
 { \
        unsigned long flags; \
        if (ANOMALY_05000311 || ANOMALY_05000323) \
-               local_irq_save_hw(flags); \
+               flags = hard_local_irq_save(); \
        if (arg) \
                gpio_array[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \
        else \
                gpio_array[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \
        if (ANOMALY_05000311 || ANOMALY_05000323) { \
                AWA_DUMMY_READ(name); \
-               local_irq_restore_hw(flags); \
+               hard_local_irq_restore(flags); \
        } \
 } \
 EXPORT_SYMBOL(set_gpio_ ## name);
@@ -391,11 +391,11 @@ void set_gpio_toggle(unsigned gpio)
 {
        unsigned long flags;
        if (ANOMALY_05000311 || ANOMALY_05000323)
-               local_irq_save_hw(flags);
+               flags = hard_local_irq_save();
        gpio_array[gpio_bank(gpio)]->toggle = gpio_bit(gpio);
        if (ANOMALY_05000311 || ANOMALY_05000323) {
                AWA_DUMMY_READ(toggle);
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
        }
 }
 EXPORT_SYMBOL(set_gpio_toggle);
@@ -408,11 +408,11 @@ void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \
 { \
        unsigned long flags; \
        if (ANOMALY_05000311 || ANOMALY_05000323) \
-               local_irq_save_hw(flags); \
+               flags = hard_local_irq_save(); \
        gpio_array[gpio_bank(gpio)]->name = arg; \
        if (ANOMALY_05000311 || ANOMALY_05000323) { \
                AWA_DUMMY_READ(name); \
-               local_irq_restore_hw(flags); \
+               hard_local_irq_restore(flags); \
        } \
 } \
 EXPORT_SYMBOL(set_gpiop_ ## name);
@@ -433,11 +433,11 @@ unsigned short get_gpio_ ## name(unsigned gpio) \
        unsigned long flags; \
        unsigned short ret; \
        if (ANOMALY_05000311 || ANOMALY_05000323) \
-               local_irq_save_hw(flags); \
+               flags = hard_local_irq_save(); \
        ret = 0x01 & (gpio_array[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \
        if (ANOMALY_05000311 || ANOMALY_05000323) { \
                AWA_DUMMY_READ(name); \
-               local_irq_restore_hw(flags); \
+               hard_local_irq_restore(flags); \
        } \
        return ret; \
 } \
@@ -460,11 +460,11 @@ unsigned short get_gpiop_ ## name(unsigned gpio) \
        unsigned long flags; \
        unsigned short ret; \
        if (ANOMALY_05000311 || ANOMALY_05000323) \
-               local_irq_save_hw(flags); \
+               flags = hard_local_irq_save(); \
        ret = (gpio_array[gpio_bank(gpio)]->name); \
        if (ANOMALY_05000311 || ANOMALY_05000323) { \
                AWA_DUMMY_READ(name); \
-               local_irq_restore_hw(flags); \
+               hard_local_irq_restore(flags); \
        } \
        return ret; \
 } \
@@ -525,14 +525,14 @@ int gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl)
        if (check_gpio(gpio) < 0)
                return -EINVAL;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        if (ctrl)
                reserve(wakeup, gpio);
        else
                unreserve(wakeup, gpio);
 
        set_gpio_maskb(gpio, ctrl);
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 
        return 0;
 }
@@ -690,7 +690,7 @@ int peripheral_request(unsigned short per, const char *label)
 
        BUG_ON(ident >= MAX_RESOURCES);
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        /* If a pin can be muxed as either GPIO or peripheral, make
         * sure it is not already a GPIO pin when we request it.
@@ -701,7 +701,7 @@ int peripheral_request(unsigned short per, const char *label)
                printk(KERN_ERR
                       "%s: Peripheral %d is already reserved as GPIO by %s !\n",
                       __func__, ident, get_label(ident));
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return -EBUSY;
        }
 
@@ -730,7 +730,7 @@ int peripheral_request(unsigned short per, const char *label)
                        printk(KERN_ERR
                               "%s: Peripheral %d function %d is already reserved by %s !\n",
                               __func__, ident, P_FUNCT2MUX(per), get_label(ident));
-                       local_irq_restore_hw(flags);
+                       hard_local_irq_restore(flags);
                        return -EBUSY;
                }
        }
@@ -741,7 +741,7 @@ int peripheral_request(unsigned short per, const char *label)
        portmux_setup(per);
        port_setup(ident, PERIPHERAL_USAGE);
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
        set_label(ident, label);
 
        return 0;
@@ -780,10 +780,10 @@ void peripheral_free(unsigned short per)
        if (!(per & P_DEFINED))
                return;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        if (unlikely(!is_reserved(peri, ident, 0))) {
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return;
        }
 
@@ -794,7 +794,7 @@ void peripheral_free(unsigned short per)
 
        set_label(ident, "free");
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(peripheral_free);
 
@@ -828,7 +828,7 @@ int bfin_gpio_request(unsigned gpio, const char *label)
        if (check_gpio(gpio) < 0)
                return -EINVAL;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        /*
         * Allow that the identical GPIO can
@@ -837,7 +837,7 @@ int bfin_gpio_request(unsigned gpio, const char *label)
         */
 
        if (cmp_label(gpio, label) == 0) {
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return 0;
        }
 
@@ -846,7 +846,7 @@ int bfin_gpio_request(unsigned gpio, const char *label)
                        dump_stack();
                printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n",
                       gpio, get_label(gpio));
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return -EBUSY;
        }
        if (unlikely(is_reserved(peri, gpio, 1))) {
@@ -855,7 +855,7 @@ int bfin_gpio_request(unsigned gpio, const char *label)
                printk(KERN_ERR
                       "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
                       gpio, get_label(gpio));
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return -EBUSY;
        }
        if (unlikely(is_reserved(gpio_irq, gpio, 1))) {
@@ -871,7 +871,7 @@ int bfin_gpio_request(unsigned gpio, const char *label)
        reserve(gpio, gpio);
        set_label(gpio, label);
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 
        port_setup(gpio, GPIO_USAGE);
 
@@ -888,13 +888,13 @@ void bfin_gpio_free(unsigned gpio)
 
        might_sleep();
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        if (unlikely(!is_reserved(gpio, gpio, 0))) {
                if (system_state == SYSTEM_BOOTING)
                        dump_stack();
                gpio_error(gpio);
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return;
        }
 
@@ -902,7 +902,7 @@ void bfin_gpio_free(unsigned gpio)
 
        set_label(gpio, "free");
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(bfin_gpio_free);
 
@@ -913,7 +913,7 @@ int bfin_special_gpio_request(unsigned gpio, const char *label)
 {
        unsigned long flags;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        /*
         * Allow that the identical GPIO can
@@ -922,19 +922,19 @@ int bfin_special_gpio_request(unsigned gpio, const char *label)
         */
 
        if (cmp_label(gpio, label) == 0) {
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return 0;
        }
 
        if (unlikely(is_reserved(special_gpio, gpio, 1))) {
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n",
                       gpio, get_label(gpio));
 
                return -EBUSY;
        }
        if (unlikely(is_reserved(peri, gpio, 1))) {
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                printk(KERN_ERR
                       "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
                       gpio, get_label(gpio));
@@ -946,7 +946,7 @@ int bfin_special_gpio_request(unsigned gpio, const char *label)
        reserve(peri, gpio);
 
        set_label(gpio, label);
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
        port_setup(gpio, GPIO_USAGE);
 
        return 0;
@@ -959,18 +959,18 @@ void bfin_special_gpio_free(unsigned gpio)
 
        might_sleep();
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        if (unlikely(!is_reserved(special_gpio, gpio, 0))) {
                gpio_error(gpio);
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return;
        }
 
        unreserve(special_gpio, gpio);
        unreserve(peri, gpio);
        set_label(gpio, "free");
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(bfin_special_gpio_free);
 #endif
@@ -983,7 +983,7 @@ int bfin_gpio_irq_request(unsigned gpio, const char *label)
        if (check_gpio(gpio) < 0)
                return -EINVAL;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        if (unlikely(is_reserved(peri, gpio, 1))) {
                if (system_state == SYSTEM_BOOTING)
@@ -991,7 +991,7 @@ int bfin_gpio_irq_request(unsigned gpio, const char *label)
                printk(KERN_ERR
                       "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
                       gpio, get_label(gpio));
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return -EBUSY;
        }
        if (unlikely(is_reserved(gpio, gpio, 1)))
@@ -1002,7 +1002,7 @@ int bfin_gpio_irq_request(unsigned gpio, const char *label)
        reserve(gpio_irq, gpio);
        set_label(gpio, label);
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 
        port_setup(gpio, GPIO_USAGE);
 
@@ -1016,13 +1016,13 @@ void bfin_gpio_irq_free(unsigned gpio)
        if (check_gpio(gpio) < 0)
                return;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        if (unlikely(!is_reserved(gpio_irq, gpio, 0))) {
                if (system_state == SYSTEM_BOOTING)
                        dump_stack();
                gpio_error(gpio);
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return;
        }
 
@@ -1030,7 +1030,7 @@ void bfin_gpio_irq_free(unsigned gpio)
 
        set_label(gpio, "free");
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 
 static inline void __bfin_gpio_direction_input(unsigned gpio)
@@ -1052,10 +1052,10 @@ int bfin_gpio_direction_input(unsigned gpio)
                return -EINVAL;
        }
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        __bfin_gpio_direction_input(gpio);
        AWA_DUMMY_READ(inen);
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 
        return 0;
 }
@@ -1070,9 +1070,9 @@ void bfin_gpio_irq_prepare(unsigned gpio)
        port_setup(gpio, GPIO_USAGE);
 
 #ifdef CONFIG_BF54x
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        __bfin_gpio_direction_input(gpio);
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 #endif
 }
 
@@ -1094,7 +1094,7 @@ int bfin_gpio_direction_output(unsigned gpio, int value)
                return -EINVAL;
        }
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        gpio_array[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio);
        gpio_set_value(gpio, value);
@@ -1105,7 +1105,7 @@ int bfin_gpio_direction_output(unsigned gpio, int value)
 #endif
 
        AWA_DUMMY_READ(dir);
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 
        return 0;
 }
@@ -1120,11 +1120,11 @@ int bfin_gpio_get_value(unsigned gpio)
 
        if (unlikely(get_gpio_edge(gpio))) {
                int ret;
-               local_irq_save_hw(flags);
+               flags = hard_local_irq_save();
                set_gpio_edge(gpio, 0);
                ret = get_gpio_data(gpio);
                set_gpio_edge(gpio, 1);
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return ret;
        } else
                return get_gpio_data(gpio);
index 87b25b1b30ed6a317b6b57bf98d82de6241648a0..8de92299b3ee1d58df6871822e3a8ff65c0c52f0 100644 (file)
@@ -318,7 +318,7 @@ void flush_switched_cplbs(unsigned int cpu)
 
        nr_cplb_flush[cpu]++;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        _disable_icplb();
        for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
                icplb_tbl[cpu][i].data = 0;
@@ -332,7 +332,7 @@ void flush_switched_cplbs(unsigned int cpu)
                bfin_write32(DCPLB_DATA0 + i * 4, 0);
        }
        _enable_dcplb();
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 
 }
 
@@ -348,7 +348,7 @@ void set_mask_dcplbs(unsigned long *masks, unsigned int cpu)
                return;
        }
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        current_rwx_mask[cpu] = masks;
 
        if (L2_LENGTH && addr >= L2_START && addr < L2_START + L2_LENGTH) {
@@ -373,5 +373,5 @@ void set_mask_dcplbs(unsigned long *masks, unsigned int cpu)
                addr += PAGE_SIZE;
        }
        _enable_dcplb();
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
index 1a496cd71ba2427fb7dffa75cbc331d522b39275..3b1da4aff2a1ed560f2c7041d85ccdf571f4972e 100644 (file)
@@ -219,10 +219,10 @@ int __ipipe_syscall_root(struct pt_regs *regs)
 
        ret = __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs);
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        if (!__ipipe_root_domain_p) {
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                return 1;
        }
 
@@ -230,7 +230,7 @@ int __ipipe_syscall_root(struct pt_regs *regs)
        if ((p->irqpend_himask & IPIPE_IRQMASK_VIRT) != 0)
                __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT);
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 
        return -ret;
 }
@@ -239,14 +239,14 @@ unsigned long ipipe_critical_enter(void (*syncfn) (void))
 {
        unsigned long flags;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        return flags;
 }
 
 void ipipe_critical_exit(unsigned long flags)
 {
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 
 static void __ipipe_no_irqtail(void)
@@ -279,9 +279,9 @@ int ipipe_trigger_irq(unsigned irq)
                return -EINVAL;
 #endif
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        __ipipe_handle_irq(irq, NULL);
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 
        return 1;
 }
@@ -293,7 +293,7 @@ asmlinkage void __ipipe_sync_root(void)
 
        BUG_ON(irqs_disabled());
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        if (irq_tail_hook)
                irq_tail_hook();
@@ -303,7 +303,7 @@ asmlinkage void __ipipe_sync_root(void)
        if (ipipe_root_cpudom_var(irqpend_himask) != 0)
                __ipipe_sync_pipeline(IPIPE_IRQMASK_ANY);
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 
 void ___ipipe_sync_pipeline(unsigned long syncmask)
@@ -344,10 +344,10 @@ void __ipipe_stall_root(void)
 {
        unsigned long *p, flags;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        p = &__ipipe_root_status;
        __set_bit(IPIPE_STALL_FLAG, p);
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(__ipipe_stall_root);
 
@@ -356,10 +356,10 @@ unsigned long __ipipe_test_and_stall_root(void)
        unsigned long *p, flags;
        int x;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        p = &__ipipe_root_status;
        x = __test_and_set_bit(IPIPE_STALL_FLAG, p);
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 
        return x;
 }
@@ -371,10 +371,10 @@ unsigned long __ipipe_test_root(void)
        unsigned long flags;
        int x;
 
-       local_irq_save_hw_smp(flags);
+       flags = hard_local_irq_save_smp();
        p = &__ipipe_root_status;
        x = test_bit(IPIPE_STALL_FLAG, p);
-       local_irq_restore_hw_smp(flags);
+       hard_local_irq_restore_smp(flags);
 
        return x;
 }
@@ -384,10 +384,10 @@ void __ipipe_lock_root(void)
 {
        unsigned long *p, flags;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        p = &__ipipe_root_status;
        __set_bit(IPIPE_SYNCDEFER_FLAG, p);
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(__ipipe_lock_root);
 
@@ -395,9 +395,9 @@ void __ipipe_unlock_root(void)
 {
        unsigned long *p, flags;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        p = &__ipipe_root_status;
        __clear_bit(IPIPE_SYNCDEFER_FLAG, p);
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(__ipipe_unlock_root);
index 01f98cb964d2654e4d7c235e6db4d647f893696b..c86a3ed5f48fb24d5df1dd5328e2f63290c6ba1d 100644 (file)
@@ -65,11 +65,11 @@ static void default_idle(void)
 #ifdef CONFIG_IPIPE
        ipipe_suspend_domain();
 #endif
-       local_irq_disable_hw();
+       hard_local_irq_disable();
        if (!need_resched())
                idle_with_irq_disabled();
 
-       local_irq_enable_hw();
+       hard_local_irq_enable();
 }
 
 /*
index 59fcdf6b0138532604be9d8de4d1c93260029349..05b550891ce563f72db45d3700c38fde46eecba8 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/kallsyms.h>
 #include <linux/err.h>
 #include <linux/fs.h>
+#include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/trace.h>
 #include <asm/fixed_code.h>
index e548e9d1d6fac5a91b0824701c349883ec5cdac7..29498e59e71f4e7272fb38296abd8825115c0607 100644 (file)
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-       unsigned long flags, iwr0, iwr1;
-
-       if (val == bfin_read_PLL_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr0 = bfin_read32(SIC_IWR0);
-       iwr1 = bfin_read32(SIC_IWR1);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-       bfin_write32(SIC_IWR1, 0);
-
-       bfin_write16(PLL_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR0, iwr0);
-       bfin_write32(SIC_IWR1, iwr1);
-       local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-       unsigned long flags, iwr0, iwr1;
-
-       if (val == bfin_read_VR_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr0 = bfin_read32(SIC_IWR0);
-       iwr1 = bfin_read32(SIC_IWR1);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-       bfin_write32(SIC_IWR1, 0);
-
-       bfin_write16(VR_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR0, iwr0);
-       bfin_write32(SIC_IWR1, iwr1);
-       local_irq_restore_hw(flags);
-}
-
 #endif /* _CDEF_BF52X_H */
diff --git a/arch/blackfin/mach-bf518/include/mach/pll.h b/arch/blackfin/mach-bf518/include/mach/pll.h
new file mode 100644 (file)
index 0000000..d550298
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+       unsigned long flags, iwr0, iwr1;
+
+       if (val == bfin_read_PLL_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr0 = bfin_read32(SIC_IWR0);
+       iwr1 = bfin_read32(SIC_IWR1);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+       bfin_write32(SIC_IWR1, 0);
+
+       bfin_write16(PLL_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR0, iwr0);
+       bfin_write32(SIC_IWR1, iwr1);
+       hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+       unsigned long flags, iwr0, iwr1;
+
+       if (val == bfin_read_VR_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr0 = bfin_read32(SIC_IWR0);
+       iwr1 = bfin_read32(SIC_IWR1);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+       bfin_write32(SIC_IWR1, 0);
+
+       bfin_write16(VR_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR0, iwr0);
+       bfin_write32(SIC_IWR1, iwr1);
+       hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
index 12f2ad45314eb3c1bfbdaabc7ae96edc3bbb7ae4..11fb27bc427dfa291b6d3cf017395e8779cfa9c0 100644 (file)
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-       unsigned long flags, iwr0, iwr1;
-
-       if (val == bfin_read_PLL_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr0 = bfin_read32(SIC_IWR0);
-       iwr1 = bfin_read32(SIC_IWR1);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-       bfin_write32(SIC_IWR1, 0);
-
-       bfin_write16(PLL_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR0, iwr0);
-       bfin_write32(SIC_IWR1, iwr1);
-       local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-       unsigned long flags, iwr0, iwr1;
-
-       if (val == bfin_read_VR_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr0 = bfin_read32(SIC_IWR0);
-       iwr1 = bfin_read32(SIC_IWR1);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-       bfin_write32(SIC_IWR1, 0);
-
-       bfin_write16(VR_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR0, iwr0);
-       bfin_write32(SIC_IWR1, iwr1);
-       local_irq_restore_hw(flags);
-}
-
 #endif /* _CDEF_BF52X_H */
diff --git a/arch/blackfin/mach-bf527/include/mach/pll.h b/arch/blackfin/mach-bf527/include/mach/pll.h
new file mode 100644 (file)
index 0000000..24f1d7c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+       unsigned long flags, iwr0, iwr1;
+
+       if (val == bfin_read_PLL_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr0 = bfin_read32(SIC_IWR0);
+       iwr1 = bfin_read32(SIC_IWR1);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+       bfin_write32(SIC_IWR1, 0);
+
+       bfin_write16(PLL_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR0, iwr0);
+       bfin_write32(SIC_IWR1, iwr1);
+       hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+       unsigned long flags, iwr0, iwr1;
+
+       if (val == bfin_read_VR_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr0 = bfin_read32(SIC_IWR0);
+       iwr1 = bfin_read32(SIC_IWR1);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+       bfin_write32(SIC_IWR1, 0);
+
+       bfin_write16(VR_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR0, iwr0);
+       bfin_write32(SIC_IWR1, iwr1);
+       hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
index 842b4fa76ea992d31c932eced7876fabdb6083aa..84a06f677dffa056dffc3048586cf7c1c4205959 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/bfin5xx_spi.h>
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
+#include <mach/fio_flag.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
index 7349970db97860f8b0def99b000ed8c36c642cb8..b8474cac6b03f3470b144629d0e2067ef054044b 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/portmux.h>
+#include <mach/fio_flag.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
index c457eaa60239e4e2281553114302c1001eeabdff..29c219eff2ff4499ff951341b8469f5d7326a63e 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/reboot.h>
 #include <asm/portmux.h>
 #include <asm/dpmc.h>
+#include <mach/fio_flag.h>
 
 /*
  * Name the Board for the /proc/cpuinfo
index feb2392c43ea0ad68e3aa31fd2c40299d4caf0ea..401e524f532168c4e85690694e0f041d91962db7 100644 (file)
@@ -7,11 +7,6 @@
 #ifndef _CDEF_BF532_H
 #define _CDEF_BF532_H
 
-#include <asm/blackfin.h>
-
-/*include all Core registers and bit definitions*/
-#include "defBF532.h"
-
 /*include core specific register pointer definitions*/
 #include <asm/cdef_LPBlackfin.h>
 
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-#if ANOMALY_05000311
-#define BFIN_WRITE_FIO_FLAG(name) \
-static inline void bfin_write_FIO_FLAG_##name(unsigned short val) \
-{ \
-       unsigned long flags; \
-       local_irq_save_hw(flags); \
-       bfin_write16(FIO_FLAG_##name, val); \
-       bfin_read_CHIPID(); \
-       local_irq_restore_hw(flags); \
-}
-BFIN_WRITE_FIO_FLAG(D)
-BFIN_WRITE_FIO_FLAG(C)
-BFIN_WRITE_FIO_FLAG(S)
-BFIN_WRITE_FIO_FLAG(T)
-
-#define BFIN_READ_FIO_FLAG(name) \
-static inline u16 bfin_read_FIO_FLAG_##name(void) \
-{ \
-       unsigned long flags; \
-       u16 ret; \
-       local_irq_save_hw(flags); \
-       ret = bfin_read16(FIO_FLAG_##name); \
-       bfin_read_CHIPID(); \
-       local_irq_restore_hw(flags); \
-       return ret; \
-}
-BFIN_READ_FIO_FLAG(D)
-BFIN_READ_FIO_FLAG(C)
-BFIN_READ_FIO_FLAG(S)
-BFIN_READ_FIO_FLAG(T)
-
-#else
-#define bfin_write_FIO_FLAG_D(val)           bfin_write16(FIO_FLAG_D, val)
-#define bfin_write_FIO_FLAG_C(val)           bfin_write16(FIO_FLAG_C, val)
-#define bfin_write_FIO_FLAG_S(val)           bfin_write16(FIO_FLAG_S, val)
-#define bfin_write_FIO_FLAG_T(val)           bfin_write16(FIO_FLAG_T, val)
-#define bfin_read_FIO_FLAG_T()               bfin_read16(FIO_FLAG_T)
-#define bfin_read_FIO_FLAG_C()               bfin_read16(FIO_FLAG_C)
-#define bfin_read_FIO_FLAG_S()               bfin_read16(FIO_FLAG_S)
-#define bfin_read_FIO_FLAG_D()               bfin_read16(FIO_FLAG_D)
-#endif
-
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-       unsigned long flags, iwr;
-
-       if (val == bfin_read_PLL_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr = bfin_read32(SIC_IWR);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR, IWR_ENABLE(0));
-
-       bfin_write16(PLL_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR, iwr);
-       local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-       unsigned long flags, iwr;
-
-       if (val == bfin_read_VR_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr = bfin_read32(SIC_IWR);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR, IWR_ENABLE(0));
-
-       bfin_write16(VR_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR, iwr);
-       local_irq_restore_hw(flags);
-}
-
 #endif                         /* _CDEF_BF532_H */
diff --git a/arch/blackfin/mach-bf533/include/mach/fio_flag.h b/arch/blackfin/mach-bf533/include/mach/fio_flag.h
new file mode 100644 (file)
index 0000000..d0bfba0
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_FIO_FLAG_H
+#define _MACH_FIO_FLAG_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+#if ANOMALY_05000311
+#define BFIN_WRITE_FIO_FLAG(name) \
+static inline void bfin_write_FIO_FLAG_##name(unsigned short val) \
+{ \
+       unsigned long flags; \
+       flags = hard_local_irq_save(); \
+       bfin_write16(FIO_FLAG_##name, val); \
+       bfin_read_CHIPID(); \
+       hard_local_irq_restore(flags); \
+}
+BFIN_WRITE_FIO_FLAG(D)
+BFIN_WRITE_FIO_FLAG(C)
+BFIN_WRITE_FIO_FLAG(S)
+BFIN_WRITE_FIO_FLAG(T)
+
+#define BFIN_READ_FIO_FLAG(name) \
+static inline u16 bfin_read_FIO_FLAG_##name(void) \
+{ \
+       unsigned long flags; \
+       u16 ret; \
+       flags = hard_local_irq_save(); \
+       ret = bfin_read16(FIO_FLAG_##name); \
+       bfin_read_CHIPID(); \
+       hard_local_irq_restore(flags); \
+       return ret; \
+}
+BFIN_READ_FIO_FLAG(D)
+BFIN_READ_FIO_FLAG(C)
+BFIN_READ_FIO_FLAG(S)
+BFIN_READ_FIO_FLAG(T)
+
+#else
+#define bfin_write_FIO_FLAG_D(val)           bfin_write16(FIO_FLAG_D, val)
+#define bfin_write_FIO_FLAG_C(val)           bfin_write16(FIO_FLAG_C, val)
+#define bfin_write_FIO_FLAG_S(val)           bfin_write16(FIO_FLAG_S, val)
+#define bfin_write_FIO_FLAG_T(val)           bfin_write16(FIO_FLAG_T, val)
+#define bfin_read_FIO_FLAG_T()               bfin_read16(FIO_FLAG_T)
+#define bfin_read_FIO_FLAG_C()               bfin_read16(FIO_FLAG_C)
+#define bfin_read_FIO_FLAG_S()               bfin_read16(FIO_FLAG_S)
+#define bfin_read_FIO_FLAG_D()               bfin_read16(FIO_FLAG_D)
+#endif
+
+#endif /* _MACH_FIO_FLAG_H */
diff --git a/arch/blackfin/mach-bf533/include/mach/pll.h b/arch/blackfin/mach-bf533/include/mach/pll.h
new file mode 100644 (file)
index 0000000..169c106
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+       unsigned long flags, iwr;
+
+       if (val == bfin_read_PLL_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr = bfin_read32(SIC_IWR);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR, IWR_ENABLE(0));
+
+       bfin_write16(PLL_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR, iwr);
+       hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+       unsigned long flags, iwr;
+
+       if (val == bfin_read_VR_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr = bfin_read32(SIC_IWR);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR, IWR_ENABLE(0));
+
+       bfin_write16(VR_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR, iwr);
+       hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
index 91825c9bd226e1914acf714d7f6983a8c14a85f0..fbeb35e141357dca5abb489e0ad03dbcef69080c 100644 (file)
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-       unsigned long flags, iwr;
-
-       if (val == bfin_read_PLL_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr = bfin_read32(SIC_IWR);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR, IWR_ENABLE(0));
-
-       bfin_write16(PLL_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR, iwr);
-       local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-       unsigned long flags, iwr;
-
-       if (val == bfin_read_VR_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr = bfin_read32(SIC_IWR);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR, IWR_ENABLE(0));
-
-       bfin_write16(VR_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR, iwr);
-       local_irq_restore_hw(flags);
-}
-
 #endif                         /* _CDEF_BF534_H */
diff --git a/arch/blackfin/mach-bf537/include/mach/pll.h b/arch/blackfin/mach-bf537/include/mach/pll.h
new file mode 100644 (file)
index 0000000..169c106
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+       unsigned long flags, iwr;
+
+       if (val == bfin_read_PLL_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr = bfin_read32(SIC_IWR);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR, IWR_ENABLE(0));
+
+       bfin_write16(PLL_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR, iwr);
+       hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+       unsigned long flags, iwr;
+
+       if (val == bfin_read_VR_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr = bfin_read32(SIC_IWR);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR, IWR_ENABLE(0));
+
+       bfin_write16(VR_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR, iwr);
+       hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
index 66aa722cf6c89beb302816ab44f039ad35418dd3..085b06b8c0a5512935e91e3899fcfb211320a662 100644 (file)
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-       unsigned long flags, iwr0, iwr1;
-
-       if (val == bfin_read_PLL_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr0 = bfin_read32(SIC_IWR0);
-       iwr1 = bfin_read32(SIC_IWR1);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-       bfin_write32(SIC_IWR1, 0);
-
-       bfin_write16(PLL_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR0, iwr0);
-       bfin_write32(SIC_IWR1, iwr1);
-       local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-       unsigned long flags, iwr0, iwr1;
-
-       if (val == bfin_read_VR_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr0 = bfin_read32(SIC_IWR0);
-       iwr1 = bfin_read32(SIC_IWR1);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-       bfin_write32(SIC_IWR1, 0);
-
-       bfin_write16(VR_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR0, iwr0);
-       bfin_write32(SIC_IWR1, iwr1);
-       local_irq_restore_hw(flags);
-}
-
 #endif
diff --git a/arch/blackfin/mach-bf538/include/mach/pll.h b/arch/blackfin/mach-bf538/include/mach/pll.h
new file mode 100644 (file)
index 0000000..b30bbcd
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2008-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+       unsigned long flags, iwr0, iwr1;
+
+       if (val == bfin_read_PLL_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr0 = bfin_read32(SIC_IWR0);
+       iwr1 = bfin_read32(SIC_IWR1);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+       bfin_write32(SIC_IWR1, 0);
+
+       bfin_write16(PLL_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR0, iwr0);
+       bfin_write32(SIC_IWR1, iwr1);
+       hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+       unsigned long flags, iwr0, iwr1;
+
+       if (val == bfin_read_VR_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr0 = bfin_read32(SIC_IWR0);
+       iwr1 = bfin_read32(SIC_IWR1);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+       bfin_write32(SIC_IWR1, 0);
+
+       bfin_write16(VR_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR0, iwr0);
+       bfin_write32(SIC_IWR1, iwr1);
+       hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
index ea3ec4ea9e2bc3e699fe8c6b8ece46109e6270e2..0c16067df4f3730913d5d20fc6960e91050d6320 100644 (file)
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-       unsigned long flags, iwr0, iwr1, iwr2;
-
-       if (val == bfin_read_PLL_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr0 = bfin_read32(SIC_IWR0);
-       iwr1 = bfin_read32(SIC_IWR1);
-       iwr2 = bfin_read32(SIC_IWR2);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-       bfin_write32(SIC_IWR1, 0);
-       bfin_write32(SIC_IWR2, 0);
-
-       bfin_write16(PLL_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR0, iwr0);
-       bfin_write32(SIC_IWR1, iwr1);
-       bfin_write32(SIC_IWR2, iwr2);
-       local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-       unsigned long flags, iwr0, iwr1, iwr2;
-
-       if (val == bfin_read_VR_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr0 = bfin_read32(SIC_IWR0);
-       iwr1 = bfin_read32(SIC_IWR1);
-       iwr2 = bfin_read32(SIC_IWR2);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
-       bfin_write32(SIC_IWR1, 0);
-       bfin_write32(SIC_IWR2, 0);
-
-       bfin_write16(VR_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SIC_IWR0, iwr0);
-       bfin_write32(SIC_IWR1, iwr1);
-       bfin_write32(SIC_IWR2, iwr2);
-       local_irq_restore_hw(flags);
-}
-
 #endif /* _CDEF_BF54X_H */
 
diff --git a/arch/blackfin/mach-bf548/include/mach/pll.h b/arch/blackfin/mach-bf548/include/mach/pll.h
new file mode 100644 (file)
index 0000000..7865a09
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+       unsigned long flags, iwr0, iwr1, iwr2;
+
+       if (val == bfin_read_PLL_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr0 = bfin_read32(SIC_IWR0);
+       iwr1 = bfin_read32(SIC_IWR1);
+       iwr2 = bfin_read32(SIC_IWR2);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+       bfin_write32(SIC_IWR1, 0);
+       bfin_write32(SIC_IWR2, 0);
+
+       bfin_write16(PLL_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR0, iwr0);
+       bfin_write32(SIC_IWR1, iwr1);
+       bfin_write32(SIC_IWR2, iwr2);
+       hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+       unsigned long flags, iwr0, iwr1, iwr2;
+
+       if (val == bfin_read_VR_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr0 = bfin_read32(SIC_IWR0);
+       iwr1 = bfin_read32(SIC_IWR1);
+       iwr2 = bfin_read32(SIC_IWR2);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SIC_IWR0, IWR_ENABLE(0));
+       bfin_write32(SIC_IWR1, 0);
+       bfin_write32(SIC_IWR2, 0);
+
+       bfin_write16(VR_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SIC_IWR0, iwr0);
+       bfin_write32(SIC_IWR1, iwr1);
+       bfin_write32(SIC_IWR2, iwr2);
+       hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
index 81ecdb71c6afe4635f1bf6bdd010c5af8418299f..cc0416a5fa027a79815501dc5905fe945c771d96 100644 (file)
 /* These need to be last due to the cdef/linux inter-dependencies */
 #include <asm/irq.h>
 
-/* Writing to PLL_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_PLL_CTL(unsigned int val)
-{
-       unsigned long flags, iwr0, iwr1;
-
-       if (val == bfin_read_PLL_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr0 = bfin_read32(SICA_IWR0);
-       iwr1 = bfin_read32(SICA_IWR1);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SICA_IWR0, IWR_ENABLE(0));
-       bfin_write32(SICA_IWR1, 0);
-
-       bfin_write16(PLL_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SICA_IWR0, iwr0);
-       bfin_write32(SICA_IWR1, iwr1);
-       local_irq_restore_hw(flags);
-}
-
-/* Writing to VR_CTL initiates a PLL relock sequence. */
-static __inline__ void bfin_write_VR_CTL(unsigned int val)
-{
-       unsigned long flags, iwr0, iwr1;
-
-       if (val == bfin_read_VR_CTL())
-               return;
-
-       local_irq_save_hw(flags);
-       /* Enable the PLL Wakeup bit in SIC IWR */
-       iwr0 = bfin_read32(SICA_IWR0);
-       iwr1 = bfin_read32(SICA_IWR1);
-       /* Only allow PPL Wakeup) */
-       bfin_write32(SICA_IWR0, IWR_ENABLE(0));
-       bfin_write32(SICA_IWR1, 0);
-
-       bfin_write16(VR_CTL, val);
-       SSYNC();
-       asm("IDLE;");
-
-       bfin_write32(SICA_IWR0, iwr0);
-       bfin_write32(SICA_IWR1, iwr1);
-       local_irq_restore_hw(flags);
-}
-
 #endif                         /* _CDEF_BF561_H */
diff --git a/arch/blackfin/mach-bf561/include/mach/pll.h b/arch/blackfin/mach-bf561/include/mach/pll.h
new file mode 100644 (file)
index 0000000..f2b1fbd
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2005-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef _MACH_PLL_H
+#define _MACH_PLL_H
+
+#include <asm/blackfin.h>
+#include <asm/irqflags.h>
+
+/* Writing to PLL_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_PLL_CTL(unsigned int val)
+{
+       unsigned long flags, iwr0, iwr1;
+
+       if (val == bfin_read_PLL_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr0 = bfin_read32(SICA_IWR0);
+       iwr1 = bfin_read32(SICA_IWR1);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SICA_IWR0, IWR_ENABLE(0));
+       bfin_write32(SICA_IWR1, 0);
+
+       bfin_write16(PLL_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SICA_IWR0, iwr0);
+       bfin_write32(SICA_IWR1, iwr1);
+       hard_local_irq_restore(flags);
+}
+
+/* Writing to VR_CTL initiates a PLL relock sequence. */
+static __inline__ void bfin_write_VR_CTL(unsigned int val)
+{
+       unsigned long flags, iwr0, iwr1;
+
+       if (val == bfin_read_VR_CTL())
+               return;
+
+       flags = hard_local_irq_save();
+       /* Enable the PLL Wakeup bit in SIC IWR */
+       iwr0 = bfin_read32(SICA_IWR0);
+       iwr1 = bfin_read32(SICA_IWR1);
+       /* Only allow PPL Wakeup) */
+       bfin_write32(SICA_IWR0, IWR_ENABLE(0));
+       bfin_write32(SICA_IWR1, 0);
+
+       bfin_write16(VR_CTL, val);
+       SSYNC();
+       asm("IDLE;");
+
+       bfin_write32(SICA_IWR0, iwr0);
+       bfin_write32(SICA_IWR1, iwr1);
+       hard_local_irq_restore(flags);
+}
+
+#endif /* _MACH_PLL_H */
index 4391d03dc8455056c6984f6931d3bee246856220..f4cf11d362e1df4f67315a68714cac5faf6b293b 100644 (file)
@@ -134,7 +134,7 @@ static int bfin_target(struct cpufreq_policy *poli,
 
                cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
                if (cpu == CPUFREQ_CPU) {
-                       local_irq_save_hw(flags);
+                       flags = hard_local_irq_save();
                        plldiv = (bfin_read_PLL_DIV() & SSEL) |
                                                dpm_state_table[index].csel;
                        bfin_write_PLL_DIV(plldiv);
@@ -155,7 +155,7 @@ static int bfin_target(struct cpufreq_policy *poli,
                                loops_per_jiffy = cpufreq_scale(lpj_ref,
                                                lpj_ref_freq, freqs.new);
                        }
-                       local_irq_restore_hw(flags);
+                       hard_local_irq_restore(flags);
                }
                /* TODO: just test case for cycles clock source, remove later */
                cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
index 1c8c4c7245c3868eb9cfcc62b783bac6a7c90755..eaece5f84e428011d57a8943da8ad603762e9f27 100644 (file)
@@ -132,8 +132,8 @@ static void bfin_ack_noop(unsigned int irq)
 static void bfin_core_mask_irq(unsigned int irq)
 {
        bfin_irq_flags &= ~(1 << irq);
-       if (!irqs_disabled_hw())
-               local_irq_enable_hw();
+       if (!hard_irqs_disabled())
+               hard_local_irq_enable();
 }
 
 static void bfin_core_unmask_irq(unsigned int irq)
@@ -148,8 +148,8 @@ static void bfin_core_unmask_irq(unsigned int irq)
         * local_irq_enable just does "STI bfin_irq_flags", so it's exactly
         * what we need.
         */
-       if (!irqs_disabled_hw())
-               local_irq_enable_hw();
+       if (!hard_irqs_disabled())
+               hard_local_irq_enable();
        return;
 }
 
@@ -158,12 +158,12 @@ static void bfin_internal_mask_irq(unsigned int irq)
        unsigned long flags;
 
 #ifdef CONFIG_BF53x
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
                             ~(1 << SIC_SYSIRQ(irq)));
 #else
        unsigned mask_bank, mask_bit;
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        mask_bank = SIC_SYSIRQ(irq) / 32;
        mask_bit = SIC_SYSIRQ(irq) % 32;
        bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
@@ -173,7 +173,7 @@ static void bfin_internal_mask_irq(unsigned int irq)
                             ~(1 << mask_bit));
 #endif
 #endif
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 
 #ifdef CONFIG_SMP
@@ -186,12 +186,12 @@ static void bfin_internal_unmask_irq(unsigned int irq)
        unsigned long flags;
 
 #ifdef CONFIG_BF53x
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
                             (1 << SIC_SYSIRQ(irq)));
 #else
        unsigned mask_bank, mask_bit;
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        mask_bank = SIC_SYSIRQ(irq) / 32;
        mask_bit = SIC_SYSIRQ(irq) % 32;
 #ifdef CONFIG_SMP
@@ -207,7 +207,7 @@ static void bfin_internal_unmask_irq(unsigned int irq)
                        (1 << mask_bit));
 #endif
 #endif
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 
 #ifdef CONFIG_SMP
@@ -264,7 +264,7 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state)
        break;
        }
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        if (state) {
                bfin_sic_iwr[bank] |= (1 << bit);
@@ -275,7 +275,7 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state)
                vr_wakeup  &= ~wakeup;
        }
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 
        return 0;
 }
index 09c1fb410748436d096bc629805295acc086025f..80884b136a0c330b20180921baf58f7584a1401a 100644 (file)
@@ -25,7 +25,7 @@ void bfin_pm_suspend_standby_enter(void)
 {
        unsigned long flags;
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
        bfin_pm_standby_setup();
 
 #ifdef CONFIG_PM_BFIN_SLEEP_DEEPER
@@ -56,7 +56,7 @@ void bfin_pm_suspend_standby_enter(void)
        bfin_write_SIC_IWR(IWR_DISABLE_ALL);
 #endif
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
 }
 
 int bf53x_suspend_l1_mem(unsigned char *memptr)
@@ -149,12 +149,12 @@ int bfin_pm_suspend_mem_enter(void)
        wakeup |= GPWE;
 #endif
 
-       local_irq_save_hw(flags);
+       flags = hard_local_irq_save();
 
        ret = blackfin_dma_suspend();
 
        if (ret) {
-               local_irq_restore_hw(flags);
+               hard_local_irq_restore(flags);
                kfree(memptr);
                return ret;
        }
@@ -178,7 +178,7 @@ int bfin_pm_suspend_mem_enter(void)
        bfin_gpio_pm_hibernate_restore();
        blackfin_dma_resume();
 
-       local_irq_restore_hw(flags);
+       hard_local_irq_restore(flags);
        kfree(memptr);
 
        return 0;
diff --git a/arch/cris/include/arch-v10/arch/irqflags.h b/arch/cris/include/arch-v10/arch/irqflags.h
new file mode 100644 (file)
index 0000000..75ef189
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __ASM_CRIS_ARCH_IRQFLAGS_H
+#define __ASM_CRIS_ARCH_IRQFLAGS_H
+
+#include <linux/types.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+       asm volatile("move $ccr,%0" : "=rm" (flags) : : "memory");
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       asm volatile("di" : : : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       asm volatile("ei" : : : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags = arch_local_save_flags();
+       arch_local_irq_disable();
+       return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile("move %0,$ccr" : : "rm" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return !(flags & (1 << 5));
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* __ASM_CRIS_ARCH_IRQFLAGS_H */
index 4a9cd36c9e16e58b16e0dbb6f8e3a2db31145b86..935fde34aa15782db1fc2dd7c39e4b47c2a96992 100644 (file)
@@ -44,20 +44,4 @@ static inline unsigned long _get_base(char * addr)
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((struct __xchg_dummy *)(x))
 
-/* interrupt control.. */
-#define local_save_flags(x)    __asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory");
-#define local_irq_restore(x)   __asm__ __volatile__ ("move %0,$ccr" : : "rm" (x) : "memory");
-#define local_irq_disable()    __asm__ __volatile__ ( "di" : : :"memory");
-#define local_irq_enable()     __asm__ __volatile__ ( "ei" : : :"memory");
-
-#define irqs_disabled()                        \
-({                                     \
-       unsigned long flags;            \
-       local_save_flags(flags);        \
-       !(flags & (1<<5));              \
-})
-
-/* For spinlocks etc */
-#define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory");
-
 #endif
diff --git a/arch/cris/include/arch-v32/arch/irqflags.h b/arch/cris/include/arch-v32/arch/irqflags.h
new file mode 100644 (file)
index 0000000..041851f
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __ASM_CRIS_ARCH_IRQFLAGS_H
+#define __ASM_CRIS_ARCH_IRQFLAGS_H
+
+#include <linux/types.h>
+#include <arch/ptrace.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+       asm volatile("move $ccs,%0" : "=rm" (flags) : : "memory");
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       asm volatile("di" : : : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       asm volatile("ei" : : : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags = arch_local_save_flags();
+       arch_local_irq_disable();
+       return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile("move %0,$ccs" : : "rm" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return !(flags & (1 << I_CCS_BITNR));
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* __ASM_CRIS_ARCH_IRQFLAGS_H */
index 6ca90f1f110acd15aa4ee68171e3047ef7ec6a16..76cea99eaa6012a5e7f6335cf215e74dd1fc860c 100644 (file)
@@ -44,26 +44,4 @@ static inline unsigned long rdsp(void)
 struct __xchg_dummy { unsigned long a[100]; };
 #define __xg(x) ((struct __xchg_dummy *)(x))
 
-/* Used for interrupt control. */
-#define local_save_flags(x) \
-       __asm__ __volatile__ ("move $ccs, %0" : "=rm" (x) : : "memory");
-
-#define local_irq_restore(x) \
-       __asm__ __volatile__ ("move %0, $ccs" : : "rm" (x) : "memory");
-
-#define local_irq_disable()  __asm__ __volatile__ ("di" : : : "memory");
-#define local_irq_enable()   __asm__ __volatile__ ("ei" : : : "memory");
-
-#define irqs_disabled()                \
-({                             \
-       unsigned long flags;    \
-                               \
-       local_save_flags(flags);\
-       !(flags & (1 << I_CCS_BITNR));  \
-})
-
-/* Used for spinlocks, etc. */
-#define local_irq_save(x) \
-       __asm__ __volatile__ ("move $ccs, %0\n\tdi" : "=rm" (x) : : "memory");
-
 #endif /* _ASM_CRIS_ARCH_SYSTEM_H */
diff --git a/arch/cris/include/asm/irqflags.h b/arch/cris/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..943ba5c
--- /dev/null
@@ -0,0 +1 @@
+#include <arch/irqflags.h>
index 8657b084a922e3ff0cb5187130961ada08262cee..ea10592f7d75ccab1a4512b9e4f4f9c79da4cd3d 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __ASM_CRIS_SYSTEM_H
 #define __ASM_CRIS_SYSTEM_H
 
+#include <linux/irqflags.h>
 #include <arch/system.h>
 
 /* the switch_to macro calls resume, an asm function in entry.S which does the actual
index 16399bd249930c1a9e2e06f7d0da247b288b6d34..0f2417df63230fb90114d96e7cb5f583d48fab34 100644 (file)
@@ -7,6 +7,7 @@ config FRV
        default y
        select HAVE_IDE
        select HAVE_ARCH_TRACEHOOK
+       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
 
 config ZONE_DMA
diff --git a/arch/frv/include/asm/irqflags.h b/arch/frv/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..82f0b53
--- /dev/null
@@ -0,0 +1,158 @@
+/* FR-V interrupt handling
+ *
+ * Copyright (C) 2010 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_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+/*
+ * interrupt flag manipulation
+ * - use virtual interrupt management since touching the PSR is slow
+ *   - ICC2.Z: T if interrupts virtually disabled
+ *   - ICC2.C: F if interrupts really disabled
+ * - if Z==1 upon interrupt:
+ *   - C is set to 0
+ *   - interrupts are really disabled
+ *   - entry.S returns immediately
+ * - uses TIHI (TRAP if Z==0 && C==0) #2 to really reenable interrupts
+ *   - if taken, the trap:
+ *     - sets ICC2.C
+ *     - enables interrupts
+ */
+static inline void arch_local_irq_disable(void)
+{
+       /* set Z flag, but don't change the C flag */
+       asm volatile("  andcc   gr0,gr0,gr0,icc2        \n"
+                    :
+                    :
+                    : "memory", "icc2"
+                    );
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       /* clear Z flag and then test the C flag */
+       asm volatile("  oricc   gr0,#1,gr0,icc2         \n"
+                    "  tihi    icc2,gr0,#2             \n"
+                    :
+                    :
+                    : "memory", "icc2"
+                    );
+}
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+
+       asm volatile("movsg ccr,%0"
+                    : "=r"(flags)
+                    :
+                    : "memory");
+
+       /* shift ICC2.Z to bit 0 */
+       flags >>= 26;
+
+       /* make flags 1 if interrupts disabled, 0 otherwise */
+       return flags & 1UL;
+
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags = arch_local_save_flags();
+       arch_local_irq_disable();
+       return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       /* load the Z flag by turning 1 if disabled into 0 if disabled
+        * and thus setting the Z flag but not the C flag */
+       asm volatile("  xoricc  %0,#1,gr0,icc2          \n"
+                    /* then trap if Z=0 and C=0 */
+                    "  tihi    icc2,gr0,#2             \n"
+                    :
+                    : "r"(flags)
+                    : "memory", "icc2"
+                    );
+
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return flags;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+/*
+ * real interrupt flag manipulation
+ */
+#define __arch_local_irq_disable()                     \
+do {                                                   \
+       unsigned long psr;                              \
+       asm volatile("  movsg   psr,%0          \n"     \
+                    "  andi    %0,%2,%0        \n"     \
+                    "  ori     %0,%1,%0        \n"     \
+                    "  movgs   %0,psr          \n"     \
+                    : "=r"(psr)                        \
+                    : "i" (PSR_PIL_14), "i" (~PSR_PIL) \
+                    : "memory");                       \
+} while (0)
+
+#define __arch_local_irq_enable()                      \
+do {                                                   \
+       unsigned long psr;                              \
+       asm volatile("  movsg   psr,%0          \n"     \
+                    "  andi    %0,%1,%0        \n"     \
+                    "  movgs   %0,psr          \n"     \
+                    : "=r"(psr)                        \
+                    : "i" (~PSR_PIL)                   \
+                    : "memory");                       \
+} while (0)
+
+#define __arch_local_save_flags(flags)         \
+do {                                           \
+       typecheck(unsigned long, flags);        \
+       asm("movsg psr,%0"                      \
+           : "=r"(flags)                       \
+           :                                   \
+           : "memory");                        \
+} while (0)
+
+#define        __arch_local_irq_save(flags)                    \
+do {                                                   \
+       unsigned long npsr;                             \
+       typecheck(unsigned long, flags);                \
+       asm volatile("  movsg   psr,%0          \n"     \
+                    "  andi    %0,%3,%1        \n"     \
+                    "  ori     %1,%2,%1        \n"     \
+                    "  movgs   %1,psr          \n"     \
+                    : "=r"(flags), "=r"(npsr)          \
+                    : "i" (PSR_PIL_14), "i" (~PSR_PIL) \
+                    : "memory");                       \
+} while (0)
+
+#define        __arch_local_irq_restore(flags)                 \
+do {                                                   \
+       typecheck(unsigned long, flags);                \
+       asm volatile("  movgs   %0,psr          \n"     \
+                    :                                  \
+                    : "r" (flags)                      \
+                    : "memory");                       \
+} while (0)
+
+#define __arch_irqs_disabled()                 \
+       ((__get_PSR() & PSR_PIL) >= PSR_PIL_14)
+
+#endif /* _ASM_IRQFLAGS_H */
index efd22d9077ac3be05e0ce45b4d9cd5fa0f1a83ce..0a6d8d9ca45bdbb6398b2ff2882203743963ea8b 100644 (file)
@@ -36,142 +36,6 @@ do {                                                                        \
        mb();                                                           \
 } while(0)
 
-/*
- * interrupt flag manipulation
- * - use virtual interrupt management since touching the PSR is slow
- *   - ICC2.Z: T if interrupts virtually disabled
- *   - ICC2.C: F if interrupts really disabled
- * - if Z==1 upon interrupt:
- *   - C is set to 0
- *   - interrupts are really disabled
- *   - entry.S returns immediately
- * - uses TIHI (TRAP if Z==0 && C==0) #2 to really reenable interrupts
- *   - if taken, the trap:
- *     - sets ICC2.C
- *     - enables interrupts
- */
-#define local_irq_disable()                                    \
-do {                                                           \
-       /* set Z flag, but don't change the C flag */           \
-       asm volatile("  andcc   gr0,gr0,gr0,icc2        \n"     \
-                    :                                          \
-                    :                                          \
-                    : "memory", "icc2"                         \
-                    );                                         \
-} while(0)
-
-#define local_irq_enable()                                     \
-do {                                                           \
-       /* clear Z flag and then test the C flag */             \
-       asm volatile("  oricc   gr0,#1,gr0,icc2         \n"     \
-                    "  tihi    icc2,gr0,#2             \n"     \
-                    :                                          \
-                    :                                          \
-                    : "memory", "icc2"                         \
-                    );                                         \
-} while(0)
-
-#define local_save_flags(flags)                                        \
-do {                                                           \
-       typecheck(unsigned long, flags);                        \
-       asm volatile("movsg ccr,%0"                             \
-                    : "=r"(flags)                              \
-                    :                                          \
-                    : "memory");                               \
-                                                               \
-       /* shift ICC2.Z to bit 0 */                             \
-       flags >>= 26;                                           \
-                                                               \
-       /* make flags 1 if interrupts disabled, 0 otherwise */  \
-       flags &= 1UL;                                           \
-} while(0)
-
-#define irqs_disabled() \
-       ({unsigned long flags; local_save_flags(flags); !!flags; })
-
-#define        local_irq_save(flags)                   \
-do {                                           \
-       typecheck(unsigned long, flags);        \
-       local_save_flags(flags);                \
-       local_irq_disable();                    \
-} while(0)
-
-#define        local_irq_restore(flags)                                        \
-do {                                                                   \
-       typecheck(unsigned long, flags);                                \
-                                                                       \
-       /* load the Z flag by turning 1 if disabled into 0 if disabled  \
-        * and thus setting the Z flag but not the C flag */            \
-       asm volatile("  xoricc  %0,#1,gr0,icc2          \n"             \
-                    /* then test Z=0 and C=0 */                        \
-                    "  tihi    icc2,gr0,#2             \n"             \
-                    :                                                  \
-                    : "r"(flags)                                       \
-                    : "memory", "icc2"                                 \
-                    );                                                 \
-                                                                       \
-} while(0)
-
-/*
- * real interrupt flag manipulation
- */
-#define __local_irq_disable()                          \
-do {                                                   \
-       unsigned long psr;                              \
-       asm volatile("  movsg   psr,%0          \n"     \
-                    "  andi    %0,%2,%0        \n"     \
-                    "  ori     %0,%1,%0        \n"     \
-                    "  movgs   %0,psr          \n"     \
-                    : "=r"(psr)                        \
-                    : "i" (PSR_PIL_14), "i" (~PSR_PIL) \
-                    : "memory");                       \
-} while(0)
-
-#define __local_irq_enable()                           \
-do {                                                   \
-       unsigned long psr;                              \
-       asm volatile("  movsg   psr,%0          \n"     \
-                    "  andi    %0,%1,%0        \n"     \
-                    "  movgs   %0,psr          \n"     \
-                    : "=r"(psr)                        \
-                    : "i" (~PSR_PIL)                   \
-                    : "memory");                       \
-} while(0)
-
-#define __local_save_flags(flags)              \
-do {                                           \
-       typecheck(unsigned long, flags);        \
-       asm("movsg psr,%0"                      \
-           : "=r"(flags)                       \
-           :                                   \
-           : "memory");                        \
-} while(0)
-
-#define        __local_irq_save(flags)                         \
-do {                                                   \
-       unsigned long npsr;                             \
-       typecheck(unsigned long, flags);                \
-       asm volatile("  movsg   psr,%0          \n"     \
-                    "  andi    %0,%3,%1        \n"     \
-                    "  ori     %1,%2,%1        \n"     \
-                    "  movgs   %1,psr          \n"     \
-                    : "=r"(flags), "=r"(npsr)          \
-                    : "i" (PSR_PIL_14), "i" (~PSR_PIL) \
-                    : "memory");                       \
-} while(0)
-
-#define        __local_irq_restore(flags)                      \
-do {                                                   \
-       typecheck(unsigned long, flags);                \
-       asm volatile("  movgs   %0,psr          \n"     \
-                    :                                  \
-                    : "r" (flags)                      \
-                    : "memory");                       \
-} while(0)
-
-#define __irqs_disabled() \
-       ((__get_PSR() & PSR_PIL) >= PSR_PIL_14)
-
 /*
  * Force strict CPU ordering.
  */
index f4709756d0d9da2046c89fb12d5af54aa032492f..4ff2fb1e6b1694848eb688700e8be330a41a9c51 100644 (file)
@@ -5,4 +5,4 @@
 lib-y := \
        __ashldi3.o __lshrdi3.o __muldi3.o __ashrdi3.o __negdi2.o __ucmpdi2.o \
        checksum.o memcpy.o memset.o atomic-ops.o atomic64-ops.o \
-       outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o perf_event.o
+       outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o
diff --git a/arch/frv/lib/perf_event.c b/arch/frv/lib/perf_event.c
deleted file mode 100644 (file)
index 9ac5acf..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Performance event handling
- *
- * Copyright (C) 2009 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.
- */
-
-#include <linux/perf_event.h>
-
-/*
- * mark the performance event as pending
- */
-void set_perf_event_pending(void)
-{
-}
diff --git a/arch/h8300/include/asm/irqflags.h b/arch/h8300/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..9617cd5
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef _H8300_IRQFLAGS_H
+#define _H8300_IRQFLAGS_H
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+       asm volatile ("stc ccr,%w0" : "=r" (flags));
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       asm volatile ("orc  #0x80,ccr" : : : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       asm volatile ("andc #0x7f,ccr" : : : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags = arch_local_save_flags();
+       arch_local_irq_disable();
+       return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile ("ldc %w0,ccr" : : "r" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags & 0x80) == 0x80;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* _H8300_IRQFLAGS_H */
index 16bf1560ff680c87fad71fa4f06af4a0b2622213..2c2382e50d934b23dd28f4a2a6c4e7e01ce06f10 100644 (file)
@@ -2,6 +2,7 @@
 #define _H8300_SYSTEM_H
 
 #include <linux/linkage.h>
+#include <linux/irqflags.h>
 
 struct pt_regs;
 
@@ -51,31 +52,8 @@ asmlinkage void resume(void);
   (last) = _last;                                          \
 }
 
-#define __sti() asm volatile ("andc #0x7f,ccr")
-#define __cli() asm volatile ("orc  #0x80,ccr")
-
-#define __save_flags(x) \
-       asm volatile ("stc ccr,%w0":"=r" (x))
-
-#define __restore_flags(x) \
-       asm volatile ("ldc %w0,ccr": :"r" (x))
-
-#define        irqs_disabled()                 \
-({                                     \
-       unsigned char flags;            \
-       __save_flags(flags);            \
-       ((flags & 0x80) == 0x80);       \
-})
-
 #define iret() __asm__ __volatile__ ("rte": : :"memory", "sp", "cc")
 
-/* For spinlocks etc */
-#define local_irq_disable()    __cli()
-#define local_irq_enable()      __sti()
-#define local_irq_save(x)      ({ __save_flags(x); local_irq_disable(); })
-#define local_irq_restore(x)   __restore_flags(x)
-#define local_save_flags(x)     __save_flags(x)
-
 /*
  * Force strict CPU ordering.
  * Not really required on H8...
index ba22849ee3ec1c268f201553658a5f5931f38fc3..7c82fa1fc911fe44c7beef2d36af4a0240ce35ab 100644 (file)
@@ -53,6 +53,9 @@ config MMU
        bool
        default y
 
+config ARCH_DMA_ADDR_T_64BIT
+       def_bool y
+
 config NEED_DMA_MAP_STATE
        def_bool y
 
@@ -62,6 +65,9 @@ config NEED_SG_DMA_LENGTH
 config SWIOTLB
        bool
 
+config STACKTRACE_SUPPORT
+       def_bool y
+
 config GENERIC_LOCKBREAK
        def_bool n
 
@@ -683,8 +689,10 @@ source "lib/Kconfig"
 # Use the generic interrupt handling code in kernel/irq/:
 #
 config GENERIC_HARDIRQS
-       bool
-       default y
+       def_bool y
+
+config GENERIC_HARDIRQS_NO__DO_IRQ
+       def_bool y
 
 config GENERIC_IRQ_PROBE
        bool
diff --git a/arch/ia64/include/asm/compat.h b/arch/ia64/include/asm/compat.h
deleted file mode 100644 (file)
index 9301a28..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-#ifndef _ASM_IA64_COMPAT_H
-#define _ASM_IA64_COMPAT_H
-/*
- * Architecture specific compatibility types
- */
-#include <linux/types.h>
-
-#define COMPAT_USER_HZ         100
-#define COMPAT_UTS_MACHINE     "i686\0\0\0"
-
-typedef u32            compat_size_t;
-typedef s32            compat_ssize_t;
-typedef s32            compat_time_t;
-typedef s32            compat_clock_t;
-typedef s32            compat_key_t;
-typedef s32            compat_pid_t;
-typedef u16            __compat_uid_t;
-typedef u16            __compat_gid_t;
-typedef u32            __compat_uid32_t;
-typedef u32            __compat_gid32_t;
-typedef u16            compat_mode_t;
-typedef u32            compat_ino_t;
-typedef u16            compat_dev_t;
-typedef s32            compat_off_t;
-typedef s64            compat_loff_t;
-typedef u16            compat_nlink_t;
-typedef u16            compat_ipc_pid_t;
-typedef s32            compat_daddr_t;
-typedef u32            compat_caddr_t;
-typedef __kernel_fsid_t        compat_fsid_t;
-typedef s32            compat_timer_t;
-
-typedef s32            compat_int_t;
-typedef s32            compat_long_t;
-typedef s64 __attribute__((aligned(4))) compat_s64;
-typedef u32            compat_uint_t;
-typedef u32            compat_ulong_t;
-typedef u64 __attribute__((aligned(4))) compat_u64;
-
-struct compat_timespec {
-       compat_time_t   tv_sec;
-       s32             tv_nsec;
-};
-
-struct compat_timeval {
-       compat_time_t   tv_sec;
-       s32             tv_usec;
-};
-
-struct compat_stat {
-       compat_dev_t    st_dev;
-       u16             __pad1;
-       compat_ino_t    st_ino;
-       compat_mode_t   st_mode;
-       compat_nlink_t  st_nlink;
-       __compat_uid_t  st_uid;
-       __compat_gid_t  st_gid;
-       compat_dev_t    st_rdev;
-       u16             __pad2;
-       u32             st_size;
-       u32             st_blksize;
-       u32             st_blocks;
-       u32             st_atime;
-       u32             st_atime_nsec;
-       u32             st_mtime;
-       u32             st_mtime_nsec;
-       u32             st_ctime;
-       u32             st_ctime_nsec;
-       u32             __unused4;
-       u32             __unused5;
-};
-
-struct compat_flock {
-       short           l_type;
-       short           l_whence;
-       compat_off_t    l_start;
-       compat_off_t    l_len;
-       compat_pid_t    l_pid;
-};
-
-#define F_GETLK64      12
-#define F_SETLK64      13
-#define F_SETLKW64     14
-
-/*
- * IA32 uses 4 byte alignment for 64 bit quantities,
- * so we need to pack this structure.
- */
-struct compat_flock64 {
-       short           l_type;
-       short           l_whence;
-       compat_loff_t   l_start;
-       compat_loff_t   l_len;
-       compat_pid_t    l_pid;
-} __attribute__((packed));
-
-struct compat_statfs {
-       int             f_type;
-       int             f_bsize;
-       int             f_blocks;
-       int             f_bfree;
-       int             f_bavail;
-       int             f_files;
-       int             f_ffree;
-       compat_fsid_t   f_fsid;
-       int             f_namelen;      /* SunOS ignores this field. */
-       int             f_frsize;
-       int             f_spare[5];
-};
-
-#define COMPAT_RLIM_OLD_INFINITY       0x7fffffff
-#define COMPAT_RLIM_INFINITY           0xffffffff
-
-typedef u32            compat_old_sigset_t;    /* at least 32 bits */
-
-#define _COMPAT_NSIG           64
-#define _COMPAT_NSIG_BPW       32
-
-typedef u32            compat_sigset_word;
-
-#define COMPAT_OFF_T_MAX       0x7fffffff
-#define COMPAT_LOFF_T_MAX      0x7fffffffffffffffL
-
-struct compat_ipc64_perm {
-       compat_key_t key;
-       __compat_uid32_t uid;
-       __compat_gid32_t gid;
-       __compat_uid32_t cuid;
-       __compat_gid32_t cgid;
-       unsigned short mode;
-       unsigned short __pad1;
-       unsigned short seq;
-       unsigned short __pad2;
-       compat_ulong_t unused1;
-       compat_ulong_t unused2;
-};
-
-struct compat_semid64_ds {
-       struct compat_ipc64_perm sem_perm;
-       compat_time_t  sem_otime;
-       compat_ulong_t __unused1;
-       compat_time_t  sem_ctime;
-       compat_ulong_t __unused2;
-       compat_ulong_t sem_nsems;
-       compat_ulong_t __unused3;
-       compat_ulong_t __unused4;
-};
-
-struct compat_msqid64_ds {
-       struct compat_ipc64_perm msg_perm;
-       compat_time_t  msg_stime;
-       compat_ulong_t __unused1;
-       compat_time_t  msg_rtime;
-       compat_ulong_t __unused2;
-       compat_time_t  msg_ctime;
-       compat_ulong_t __unused3;
-       compat_ulong_t msg_cbytes;
-       compat_ulong_t msg_qnum;
-       compat_ulong_t msg_qbytes;
-       compat_pid_t   msg_lspid;
-       compat_pid_t   msg_lrpid;
-       compat_ulong_t __unused4;
-       compat_ulong_t __unused5;
-};
-
-struct compat_shmid64_ds {
-       struct compat_ipc64_perm shm_perm;
-       compat_size_t  shm_segsz;
-       compat_time_t  shm_atime;
-       compat_ulong_t __unused1;
-       compat_time_t  shm_dtime;
-       compat_ulong_t __unused2;
-       compat_time_t  shm_ctime;
-       compat_ulong_t __unused3;
-       compat_pid_t   shm_cpid;
-       compat_pid_t   shm_lpid;
-       compat_ulong_t shm_nattch;
-       compat_ulong_t __unused4;
-       compat_ulong_t __unused5;
-};
-
-/*
- * A pointer passed in from user mode. This should not be used for syscall parameters,
- * just declare them as pointers because the syscall entry code will have appropriately
- * converted them already.
- */
-typedef        u32             compat_uptr_t;
-
-static inline void __user *
-compat_ptr (compat_uptr_t uptr)
-{
-       return (void __user *) (unsigned long) uptr;
-}
-
-static inline compat_uptr_t
-ptr_to_compat(void __user *uptr)
-{
-       return (u32)(unsigned long)uptr;
-}
-
-static __inline__ void __user *
-arch_compat_alloc_user_space (long len)
-{
-       struct pt_regs *regs = task_pt_regs(current);
-       return (void __user *) (((regs->r12 & 0xffffffff) & -16) - len);
-}
-
-#endif /* _ASM_IA64_COMPAT_H */
index d514cd9edb49f45c9ac5871d407ec7ff65b0927e..8fb7d33a661f9e6de23ec01be699e4300ad4f363 100644 (file)
@@ -6,12 +6,6 @@
  *     David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
-
-#include <linux/threads.h>
-#include <linux/irq.h>
-
-#include <asm/processor.h>
-
 /*
  * No irq_cpustat_t for IA-64.  The data is held in the per-CPU data structure.
  */
 
 #define local_softirq_pending()                (local_cpu_data->softirq_pending)
 
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+#include <asm/processor.h>
+
 extern void __iomem *ipi_base_addr;
 
 void ack_bad_irq(unsigned int irq);
diff --git a/arch/ia64/include/asm/iommu_table.h b/arch/ia64/include/asm/iommu_table.h
new file mode 100644 (file)
index 0000000..92c8d36
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _ASM_IA64_IOMMU_TABLE_H
+#define _ASM_IA64_IOMMU_TABLE_H
+
+#define IOMMU_INIT_POST(_detect)
+
+#endif /* _ASM_IA64_IOMMU_TABLE_H */
diff --git a/arch/ia64/include/asm/irqflags.h b/arch/ia64/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..f82d6be
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * IRQ flags defines.
+ *
+ * Copyright (C) 1998-2003 Hewlett-Packard Co
+ *     David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
+ * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
+ */
+
+#ifndef _ASM_IA64_IRQFLAGS_H
+#define _ASM_IA64_IRQFLAGS_H
+
+#ifdef CONFIG_IA64_DEBUG_IRQ
+extern unsigned long last_cli_ip;
+static inline void arch_maybe_save_ip(unsigned long flags)
+{
+       if (flags & IA64_PSR_I)
+               last_cli_ip = ia64_getreg(_IA64_REG_IP);
+}
+#else
+#define arch_maybe_save_ip(flags) do {} while (0)
+#endif
+
+/*
+ * - clearing psr.i is implicitly serialized (visible by next insn)
+ * - setting psr.i requires data serialization
+ * - we need a stop-bit before reading PSR because we sometimes
+ *   write a floating-point register right before reading the PSR
+ *   and that writes to PSR.mfl
+ */
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       ia64_stop();
+#ifdef CONFIG_PARAVIRT
+       return ia64_get_psr_i();
+#else
+       return ia64_getreg(_IA64_REG_PSR);
+#endif
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags = arch_local_save_flags();
+
+       ia64_stop();
+       ia64_rsm(IA64_PSR_I);
+       arch_maybe_save_ip(flags);
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+#ifdef CONFIG_IA64_DEBUG_IRQ
+       arch_local_irq_save();
+#else
+       ia64_stop();
+       ia64_rsm(IA64_PSR_I);
+#endif
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       ia64_stop();
+       ia64_ssm(IA64_PSR_I);
+       ia64_srlz_d();
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+#ifdef CONFIG_IA64_DEBUG_IRQ
+       unsigned long old_psr = arch_local_save_flags();
+#endif
+       ia64_intrin_local_irq_restore(flags & IA64_PSR_I);
+       arch_maybe_save_ip(old_psr & ~flags);
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags & IA64_PSR_I) == 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+static inline void arch_safe_halt(void)
+{
+       ia64_pal_halt_light();  /* PAL_HALT_LIGHT */
+}
+
+
+#endif /* _ASM_IA64_IRQFLAGS_H */
index 9f342a574ce8c669310b6857b5b1ac7152f8bae0..6cca30705d50196e767049fcfc7d9768b850d342 100644 (file)
@@ -107,87 +107,11 @@ extern struct ia64_boot_param {
  */
 #define set_mb(var, value)     do { (var) = (value); mb(); } while (0)
 
-#define safe_halt()         ia64_pal_halt_light()    /* PAL_HALT_LIGHT */
-
 /*
  * The group barrier in front of the rsm & ssm are necessary to ensure
  * that none of the previous instructions in the same group are
  * affected by the rsm/ssm.
  */
-/* For spinlocks etc */
-
-/*
- * - clearing psr.i is implicitly serialized (visible by next insn)
- * - setting psr.i requires data serialization
- * - we need a stop-bit before reading PSR because we sometimes
- *   write a floating-point register right before reading the PSR
- *   and that writes to PSR.mfl
- */
-#ifdef CONFIG_PARAVIRT
-#define __local_save_flags()   ia64_get_psr_i()
-#else
-#define __local_save_flags()   ia64_getreg(_IA64_REG_PSR)
-#endif
-
-#define __local_irq_save(x)                    \
-do {                                           \
-       ia64_stop();                            \
-       (x) = __local_save_flags();             \
-       ia64_stop();                            \
-       ia64_rsm(IA64_PSR_I);                   \
-} while (0)
-
-#define __local_irq_disable()                  \
-do {                                           \
-       ia64_stop();                            \
-       ia64_rsm(IA64_PSR_I);                   \
-} while (0)
-
-#define __local_irq_restore(x) ia64_intrin_local_irq_restore((x) & IA64_PSR_I)
-
-#ifdef CONFIG_IA64_DEBUG_IRQ
-
-  extern unsigned long last_cli_ip;
-
-# define __save_ip()           last_cli_ip = ia64_getreg(_IA64_REG_IP)
-
-# define local_irq_save(x)                                     \
-do {                                                           \
-       unsigned long __psr;                                    \
-                                                               \
-       __local_irq_save(__psr);                                \
-       if (__psr & IA64_PSR_I)                                 \
-               __save_ip();                                    \
-       (x) = __psr;                                            \
-} while (0)
-
-# define local_irq_disable()   do { unsigned long __x; local_irq_save(__x); } while (0)
-
-# define local_irq_restore(x)                                  \
-do {                                                           \
-       unsigned long __old_psr, __psr = (x);                   \
-                                                               \
-       local_save_flags(__old_psr);                            \
-       __local_irq_restore(__psr);                             \
-       if ((__old_psr & IA64_PSR_I) && !(__psr & IA64_PSR_I))  \
-               __save_ip();                                    \
-} while (0)
-
-#else /* !CONFIG_IA64_DEBUG_IRQ */
-# define local_irq_save(x)     __local_irq_save(x)
-# define local_irq_disable()   __local_irq_disable()
-# define local_irq_restore(x)  __local_irq_restore(x)
-#endif /* !CONFIG_IA64_DEBUG_IRQ */
-
-#define local_irq_enable()     ({ ia64_stop(); ia64_ssm(IA64_PSR_I); ia64_srlz_d(); })
-#define local_save_flags(flags)        ({ ia64_stop(); (flags) = __local_save_flags(); })
-
-#define irqs_disabled()                                \
-({                                             \
-       unsigned long __ia64_id_flags;          \
-       local_save_flags(__ia64_id_flags);      \
-       (__ia64_id_flags & IA64_PSR_I) == 0;    \
-})
 
 #ifdef __KERNEL__
 
@@ -272,10 +196,6 @@ void cpu_idle_wait(void);
 
 void default_idle(void);
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-extern void account_system_vtime(struct task_struct *);
-#endif
-
 #endif /* __KERNEL__ */
 
 #endif /* __ASSEMBLY__ */
index db10b1e378b0470ec52828a19e78da43e26d31db..395c2f216dd899ddb6871db79b3f45e4f041d442 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_AUDIT)           += audit.o
 obj-$(CONFIG_PCI_MSI)          += msi_ia64.o
 mca_recovery-y                 += mca_drv.o mca_drv_asm.o
 obj-$(CONFIG_IA64_MC_ERR_INJECT)+= err_inject.o
+obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 
 obj-$(CONFIG_PARAVIRT)         += paravirt.o paravirtentry.o \
                                   paravirt_patch.o
index 71e35864d2e251a48630472071f5c9ae76af39e0..d52f1f78eff2ab01b126cc5ef35e2039400fddaf 100644 (file)
@@ -59,13 +59,13 @@ int __init init_cyclone_clock(void)
                return -ENODEV;
        }
        base = readq(reg);
+       iounmap(reg);
        if(!base){
                printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
                                " value.\n");
                use_cyclone = 0;
                return -ENODEV;
        }
-       iounmap(reg);
 
        /* setup PMCC */
        offset = (base + CYCLONE_PMCC_OFFSET);
index 7ded76658d2da69075bb0c748d73c8159beda9dd..22c38404f539eeb9ab268ca226db94d1e243e860 100644 (file)
 #define DBG(fmt...)
 #endif
 
-#define NR_PREALLOCATE_RTE_ENTRIES \
-       (PAGE_SIZE / sizeof(struct iosapic_rte_info))
-#define RTE_PREALLOCATED       (1)
-
 static DEFINE_SPINLOCK(iosapic_lock);
 
 /*
@@ -136,7 +132,6 @@ struct iosapic_rte_info {
        struct list_head rte_list;      /* RTEs sharing the same vector */
        char            rte_index;      /* IOSAPIC RTE index */
        int             refcnt;         /* reference counter */
-       unsigned int    flags;          /* flags */
        struct iosapic  *iosapic;
 } ____cacheline_aligned;
 
@@ -155,9 +150,6 @@ static struct iosapic_intr_info {
 
 static unsigned char pcat_compat __devinitdata;        /* 8259 compatibility flag */
 
-static int iosapic_kmalloc_ok;
-static LIST_HEAD(free_rte_list);
-
 static inline void
 iosapic_write(struct iosapic *iosapic, unsigned int reg, u32 val)
 {
@@ -394,7 +386,7 @@ iosapic_startup_level_irq (unsigned int irq)
 }
 
 static void
-iosapic_end_level_irq (unsigned int irq)
+iosapic_unmask_level_irq (unsigned int irq)
 {
        ia64_vector vec = irq_to_vector(irq);
        struct iosapic_rte_info *rte;
@@ -404,7 +396,8 @@ iosapic_end_level_irq (unsigned int irq)
        if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
                do_unmask_irq = 1;
                mask_irq(irq);
-       }
+       } else
+               unmask_irq(irq);
 
        list_for_each_entry(rte, &iosapic_intr_info[irq].rtes, rte_list)
                iosapic_eoi(rte->iosapic->addr, vec);
@@ -427,9 +420,8 @@ static struct irq_chip irq_type_iosapic_level = {
        .enable =       iosapic_enable_level_irq,
        .disable =      iosapic_disable_level_irq,
        .ack =          iosapic_ack_level_irq,
-       .end =          iosapic_end_level_irq,
        .mask =         mask_irq,
-       .unmask =       unmask_irq,
+       .unmask =       iosapic_unmask_level_irq,
        .set_affinity = iosapic_set_affinity
 };
 
@@ -552,37 +544,6 @@ iosapic_reassign_vector (int irq)
        }
 }
 
-static struct iosapic_rte_info * __init_refok iosapic_alloc_rte (void)
-{
-       int i;
-       struct iosapic_rte_info *rte;
-       int preallocated = 0;
-
-       if (!iosapic_kmalloc_ok && list_empty(&free_rte_list)) {
-               rte = alloc_bootmem(sizeof(struct iosapic_rte_info) *
-                                   NR_PREALLOCATE_RTE_ENTRIES);
-               for (i = 0; i < NR_PREALLOCATE_RTE_ENTRIES; i++, rte++)
-                       list_add(&rte->rte_list, &free_rte_list);
-       }
-
-       if (!list_empty(&free_rte_list)) {
-               rte = list_entry(free_rte_list.next, struct iosapic_rte_info,
-                                rte_list);
-               list_del(&rte->rte_list);
-               preallocated++;
-       } else {
-               rte = kmalloc(sizeof(struct iosapic_rte_info), GFP_ATOMIC);
-               if (!rte)
-                       return NULL;
-       }
-
-       memset(rte, 0, sizeof(struct iosapic_rte_info));
-       if (preallocated)
-               rte->flags |= RTE_PREALLOCATED;
-
-       return rte;
-}
-
 static inline int irq_is_shared (int irq)
 {
        return (iosapic_intr_info[irq].count > 1);
@@ -615,7 +576,7 @@ register_intr (unsigned int gsi, int irq, unsigned char delivery,
 
        rte = find_rte(irq, gsi);
        if (!rte) {
-               rte = iosapic_alloc_rte();
+               rte = kzalloc(sizeof (*rte), GFP_ATOMIC);
                if (!rte) {
                        printk(KERN_WARNING "%s: cannot allocate memory\n",
                               __func__);
@@ -658,6 +619,10 @@ register_intr (unsigned int gsi, int irq, unsigned char delivery,
                               idesc->chip->name, irq_type->name);
                idesc->chip = irq_type;
        }
+       if (trigger == IOSAPIC_EDGE)
+               __set_irq_handler_unlocked(irq, handle_edge_irq);
+       else
+               __set_irq_handler_unlocked(irq, handle_level_irq);
        return 0;
 }
 
@@ -1161,10 +1126,3 @@ map_iosapic_to_node(unsigned int gsi_base, int node)
        return;
 }
 #endif
-
-static int __init iosapic_enable_kmalloc (void)
-{
-       iosapic_kmalloc_ok = 1;
-       return 0;
-}
-core_initcall (iosapic_enable_kmalloc);
index f14c35f9b03a469cc8ef19e84283cf9d7071b90d..9a26015c3e50027d7cb88981881971feb3d88bc0 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/bitops.h>
 #include <linux/irq.h>
 #include <linux/ratelimit.h>
+#include <linux/acpi.h>
 
 #include <asm/delay.h>
 #include <asm/intrinsics.h>
@@ -635,6 +636,7 @@ ia64_native_register_percpu_irq (ia64_vector vec, struct irqaction *action)
        desc->chip = &irq_type_ia64_lsapic;
        if (action)
                setup_irq(irq, action);
+       set_irq_handler(irq, handle_percpu_irq);
 }
 
 void __init
@@ -650,6 +652,9 @@ ia64_native_register_ipi(void)
 void __init
 init_IRQ (void)
 {
+#ifdef CONFIG_ACPI
+       acpi_boot_init();
+#endif
        ia64_register_ipi();
        register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
 #ifdef CONFIG_SMP
index a0220dc5ff421effdc55e130aad53a6af39ba348..1753f6a30d55e6d66c5e3198a9b271601c89a39e 100644 (file)
@@ -2055,25 +2055,6 @@ ia64_mca_init(void)
 
        IA64_MCA_DEBUG("%s: registered OS INIT handler with SAL\n", __func__);
 
-       /*
-        *  Configure the CMCI/P vector and handler. Interrupts for CMC are
-        *  per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
-        */
-       register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
-       register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction);
-       ia64_mca_cmc_vector_setup();       /* Setup vector on BSP */
-
-       /* Setup the MCA rendezvous interrupt vector */
-       register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);
-
-       /* Setup the MCA wakeup interrupt vector */
-       register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
-
-#ifdef CONFIG_ACPI
-       /* Setup the CPEI/P handler */
-       register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
-#endif
-
        /* Initialize the areas set aside by the OS to buffer the
         * platform/processor error states for MCA/INIT/CMC
         * handling.
@@ -2103,6 +2084,25 @@ ia64_mca_late_init(void)
        if (!mca_init)
                return 0;
 
+       /*
+        *  Configure the CMCI/P vector and handler. Interrupts for CMC are
+        *  per-processor, so AP CMC interrupts are setup in smp_callin() (smpboot.c).
+        */
+       register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction);
+       register_percpu_irq(IA64_CMCP_VECTOR, &cmcp_irqaction);
+       ia64_mca_cmc_vector_setup();       /* Setup vector on BSP */
+
+       /* Setup the MCA rendezvous interrupt vector */
+       register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction);
+
+       /* Setup the MCA wakeup interrupt vector */
+       register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
+
+#ifdef CONFIG_ACPI
+       /* Setup the CPEI/P handler */
+       register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction);
+#endif
+
        register_hotcpu_notifier(&mca_cpu_notifier);
 
        /* Setup the CMCI/P vector and handler */
index 4a746ea838ff37b423f92f31a8eecc8207f6217a..00b19a416eab5b1fc6db10bb366c37c048f8c7c2 100644 (file)
@@ -104,8 +104,8 @@ static int ia64_msi_retrigger_irq(unsigned int irq)
  */
 static struct irq_chip ia64_msi_chip = {
        .name           = "PCI-MSI",
-       .mask           = mask_msi_irq,
-       .unmask         = unmask_msi_irq,
+       .irq_mask       = mask_msi_irq,
+       .irq_unmask     = unmask_msi_irq,
        .ack            = ia64_ack_msi_irq,
 #ifdef CONFIG_SMP
        .set_affinity   = ia64_set_msi_irq_affinity,
@@ -160,8 +160,8 @@ static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 
 static struct irq_chip dmar_msi_type = {
        .name = "DMAR_MSI",
-       .unmask = dmar_msi_unmask,
-       .mask = dmar_msi_mask,
+       .irq_unmask = dmar_msi_unmask,
+       .irq_mask = dmar_msi_mask,
        .ack = ia64_ack_msi_irq,
 #ifdef CONFIG_SMP
        .set_affinity = dmar_msi_set_affinity,
index fdf6f9d013e5b3f8b5ed3145543ca9ac34b8180a..77597e5ea60aca9429f29c26ec7973bf89a19683 100644 (file)
@@ -434,7 +434,7 @@ register_info(char *page)
        unsigned long phys_stacked;
        pal_hints_u_t hints;
        unsigned long iregs, dregs;
-       char *info_type[]={
+       static const char * const info_type[] = {
                "Implemented AR(s)",
                "AR(s) with read side-effects",
                "Implemented CR(s)",
index cce050e85c73558040fe7c4970e3beb69d7ee2a1..6b1852f7f972b80fcccc06ba0214acc321cd84e5 100644 (file)
@@ -1573,7 +1573,7 @@ pfm_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
                return -EINVAL;
        }
 
-       ctx = (pfm_context_t *)filp->private_data;
+       ctx = filp->private_data;
        if (ctx == NULL) {
                printk(KERN_ERR "perfmon: pfm_read: NULL ctx [%d]\n", task_pid_nr(current));
                return -EINVAL;
@@ -1673,7 +1673,7 @@ pfm_poll(struct file *filp, poll_table * wait)
                return 0;
        }
 
-       ctx = (pfm_context_t *)filp->private_data;
+       ctx = filp->private_data;
        if (ctx == NULL) {
                printk(KERN_ERR "perfmon: pfm_poll: NULL ctx [%d]\n", task_pid_nr(current));
                return 0;
@@ -1733,7 +1733,7 @@ pfm_fasync(int fd, struct file *filp, int on)
                return -EBADF;
        }
 
-       ctx = (pfm_context_t *)filp->private_data;
+       ctx = filp->private_data;
        if (ctx == NULL) {
                printk(KERN_ERR "perfmon: pfm_fasync NULL ctx [%d]\n", task_pid_nr(current));
                return -EBADF;
@@ -1841,7 +1841,7 @@ pfm_flush(struct file *filp, fl_owner_t id)
                return -EBADF;
        }
 
-       ctx = (pfm_context_t *)filp->private_data;
+       ctx = filp->private_data;
        if (ctx == NULL) {
                printk(KERN_ERR "perfmon: pfm_flush: NULL ctx [%d]\n", task_pid_nr(current));
                return -EBADF;
@@ -1984,7 +1984,7 @@ pfm_close(struct inode *inode, struct file *filp)
                return -EBADF;
        }
        
-       ctx = (pfm_context_t *)filp->private_data;
+       ctx = filp->private_data;
        if (ctx == NULL) {
                printk(KERN_ERR "perfmon: pfm_close: NULL ctx [%d]\n", task_pid_nr(current));
                return -EBADF;
@@ -4907,7 +4907,7 @@ restart_args:
                goto error_args;
        }
 
-       ctx = (pfm_context_t *)file->private_data;
+       ctx = file->private_data;
        if (unlikely(ctx == NULL)) {
                DPRINT(("no context for fd %d\n", fd));
                goto error_args;
index aa8b5fa1a8dec906c19b7ce99d6f721f60bb025b..45d7543b69cc5a3d7bf1819bb6992fbb227ae960 100644 (file)
@@ -642,7 +642,7 @@ salinfo_init(void)
        for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) {
                data = salinfo_data + i;
                data->type = i;
-               init_MUTEX(&data->mutex);
+               sema_init(&data->mutex, 1);
                dir = proc_mkdir(salinfo_log_name[i], salinfo_dir);
                if (!dir)
                        continue;
index 8fb958abf8d008e95259f209d4caf7e53420b009..911cf974970008c6e01a92c36c2d1233ece62f8a 100644 (file)
@@ -594,10 +594,6 @@ setup_arch (char **cmdline_p)
        cpu_init();     /* initialize the bootstrap CPU */
        mmu_context_init();     /* initialize context_id bitmap */
 
-#ifdef CONFIG_ACPI
-       acpi_boot_init();
-#endif
-
        paravirt_banner();
        paravirt_arch_setup_console(cmdline_p);
 
diff --git a/arch/ia64/kernel/stacktrace.c b/arch/ia64/kernel/stacktrace.c
new file mode 100644 (file)
index 0000000..5af2783
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * arch/ia64/kernel/stacktrace.c
+ *
+ * Stack trace management functions
+ *
+ */
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/module.h>
+
+static void
+ia64_do_save_stack(struct unw_frame_info *info, void *arg)
+{
+       struct stack_trace *trace = arg;
+       unsigned long ip;
+       int skip = trace->skip;
+
+       trace->nr_entries = 0;
+       do {
+               unw_get_ip(info, &ip);
+               if (ip == 0)
+                       break;
+               if (skip == 0) {
+                       trace->entries[trace->nr_entries++] = ip;
+                       if (trace->nr_entries == trace->max_entries)
+                               break;
+               } else
+                       skip--;
+       } while (unw_unwind(info) >= 0);
+}
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ */
+void save_stack_trace(struct stack_trace *trace)
+{
+       unw_init_running(ia64_do_save_stack, trace);
+}
+EXPORT_SYMBOL(save_stack_trace);
index b6c0e63a0bf61535386fff325adaf5f3e40e2932..fed6afa2e8a9014e65229e51e64fa4b1c13cc284 100644 (file)
@@ -1204,10 +1204,10 @@ desc_spill_sprel_p (unsigned char qp, unw_word t, unsigned char abreg, unw_word
 static inline unw_hash_index_t
 hash (unsigned long ip)
 {
-#      define hashmagic        0x9e3779b97f4a7c16UL    /* based on (sqrt(5)/2-1)*2^64 */
+       /* magic number = ((sqrt(5)-1)/2)*2^64 */
+       static const unsigned long hashmagic = 0x9e3779b97f4a7c16UL;
 
-       return (ip >> 4)*hashmagic >> (64 - UNW_LOG_HASH_SIZE);
-#undef hashmagic
+       return (ip >> 4) * hashmagic >> (64 - UNW_LOG_HASH_SIZE);
 }
 
 static inline long
@@ -1531,7 +1531,7 @@ build_script (struct unw_frame_info *info)
        struct unw_labeled_state *ls, *next;
        unsigned long ip = info->ip;
        struct unw_state_record sr;
-       struct unw_table *table;
+       struct unw_table *table, *prev;
        struct unw_reg_info *r;
        struct unw_insn insn;
        u8 *dp, *desc_end;
@@ -1560,11 +1560,26 @@ build_script (struct unw_frame_info *info)
 
        STAT(parse_start = ia64_get_itc());
 
+       prev = NULL;
        for (table = unw.tables; table; table = table->next) {
                if (ip >= table->start && ip < table->end) {
+                       /*
+                        * Leave the kernel unwind table at the very front,
+                        * lest moving it breaks some assumption elsewhere.
+                        * Otherwise, move the matching table to the second
+                        * position in the list so that traversals can benefit
+                        * from commonality in backtrace paths.
+                        */
+                       if (prev && prev != unw.tables) {
+                               /* unw is safe - we're already spinlocked */
+                               prev->next = table->next;
+                               table->next = unw.tables->next;
+                               unw.tables->next = table;
+                       }
                        e = lookup(table, ip - table->segment_base);
                        break;
                }
+               prev = table;
        }
        if (!e) {
                /* no info, return default unwinder (leaf proc, no mem stack, no saved regs)  */
index 0c72dd4638314523eeb8a71b6204826fc9777303..a5e500f02853003604979a9b1c8c7fe1f25e0b4c 100644 (file)
@@ -228,8 +228,8 @@ static int sn_msi_retrigger_irq(unsigned int irq)
 
 static struct irq_chip sn_msi_chip = {
        .name           = "PCI-MSI",
-       .mask           = mask_msi_irq,
-       .unmask         = unmask_msi_irq,
+       .irq_mask       = mask_msi_irq,
+       .irq_unmask     = unmask_msi_irq,
        .ack            = sn_ack_msi_irq,
 #ifdef CONFIG_SMP
        .set_affinity   = sn_set_msi_irq_affinity,
index 8adc6a14272abb990a104017eba40bf88aa2ebd0..3e8d350fdf39bf6bcdfaf314dd0cd5c9b0a0c4a9 100644 (file)
@@ -1136,7 +1136,6 @@ __initconst = {
 static void __init
 xen_patch_branch(unsigned long tag, unsigned long type)
 {
-       const unsigned long nelem =
-               sizeof(xen_branch_target) / sizeof(xen_branch_target[0]);
-       __paravirt_patch_apply_branch(tag, type, xen_branch_target, nelem);
+       __paravirt_patch_apply_branch(tag, type, xen_branch_target,
+                                       ARRAY_SIZE(xen_branch_target));
 }
diff --git a/arch/m32r/include/asm/irqflags.h b/arch/m32r/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..1f92d29
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2001  Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
+ * Copyright (C) 2004, 2006  Hirokazu Takata <takata at linux-m32r.org>
+ */
+
+#ifndef _ASM_M32R_IRQFLAGS_H
+#define _ASM_M32R_IRQFLAGS_H
+
+#include <linux/types.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+       asm volatile("mvfc %0,psw" : "=r"(flags));
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+#if !defined(CONFIG_CHIP_M32102) && !defined(CONFIG_CHIP_M32104)
+       asm volatile (
+               "clrpsw #0x40 -> nop"
+               : : : "memory");
+#else
+       unsigned long tmpreg0, tmpreg1;
+       asm volatile (
+               "ld24   %0, #0  ; Use 32-bit insn.                      \n\t"
+               "mvfc   %1, psw ; No interrupt can be accepted here.    \n\t"
+               "mvtc   %0, psw                                         \n\t"
+               "and3   %0, %1, #0xffbf                                 \n\t"
+               "mvtc   %0, psw                                         \n\t"
+               : "=&r" (tmpreg0), "=&r" (tmpreg1)
+               :
+               : "cbit", "memory");
+#endif
+}
+
+static inline void arch_local_irq_enable(void)
+{
+#if !defined(CONFIG_CHIP_M32102) && !defined(CONFIG_CHIP_M32104)
+       asm volatile (
+               "setpsw #0x40 -> nop"
+               : : : "memory");
+#else
+       unsigned long tmpreg;
+       asm volatile (
+               "mvfc   %0, psw;                \n\t"
+               "or3    %0, %0, #0x0040;        \n\t"
+               "mvtc   %0, psw;                \n\t"
+               : "=&r" (tmpreg)
+               :
+               : "cbit", "memory");
+#endif
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags;
+
+#if !(defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_M32104))
+       asm volatile (
+               "mvfc   %0, psw;        \n\t"
+               "clrpsw #0x40 -> nop;   \n\t"
+               : "=r" (flags)
+               :
+               : "memory");
+#else
+       unsigned long tmpreg;
+       asm volatile (
+               "ld24   %1, #0          \n\t"
+               "mvfc   %0, psw         \n\t"
+               "mvtc   %1, psw         \n\t"
+               "and3   %1, %0, #0xffbf \n\t"
+               "mvtc   %1, psw         \n\t"
+               : "=r" (flags), "=&r" (tmpreg)
+               :
+               : "cbit", "memory");
+#endif
+       return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile("mvtc %0,psw"
+                    :
+                    : "r" (flags)
+                    : "cbit", "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return !(flags & 0x40);
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* _ASM_M32R_IRQFLAGS_H */
index c980f5ba8de7dc01a2c34e7f64e42b84d0b6a744..13c46794ccb1aa3954b837ce7b652966730aa62e 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/compiler.h>
+#include <linux/irqflags.h>
 #include <asm/assembler.h>
 
 #ifdef __KERNEL__
        ); \
 } while(0)
 
-/* Interrupt Control */
-#if !defined(CONFIG_CHIP_M32102) && !defined(CONFIG_CHIP_M32104)
-#define local_irq_enable() \
-       __asm__ __volatile__ ("setpsw #0x40 -> nop": : :"memory")
-#define local_irq_disable() \
-       __asm__ __volatile__ ("clrpsw #0x40 -> nop": : :"memory")
-#else  /* CONFIG_CHIP_M32102 || CONFIG_CHIP_M32104 */
-static inline void local_irq_enable(void)
-{
-       unsigned long tmpreg;
-       __asm__ __volatile__(
-               "mvfc   %0, psw;                \n\t"
-               "or3    %0, %0, #0x0040;        \n\t"
-               "mvtc   %0, psw;                \n\t"
-       : "=&r" (tmpreg) : : "cbit", "memory");
-}
-
-static inline void local_irq_disable(void)
-{
-       unsigned long tmpreg0, tmpreg1;
-       __asm__ __volatile__(
-               "ld24   %0, #0  ; Use 32-bit insn. \n\t"
-               "mvfc   %1, psw ; No interrupt can be accepted here. \n\t"
-               "mvtc   %0, psw \n\t"
-               "and3   %0, %1, #0xffbf \n\t"
-               "mvtc   %0, psw \n\t"
-       : "=&r" (tmpreg0), "=&r" (tmpreg1) : : "cbit", "memory");
-}
-#endif /* CONFIG_CHIP_M32102 || CONFIG_CHIP_M32104 */
-
-#define local_save_flags(x) \
-       __asm__ __volatile__("mvfc %0,psw" : "=r"(x) : /* no input */)
-
-#define local_irq_restore(x) \
-       __asm__ __volatile__("mvtc %0,psw" : /* no outputs */ \
-               : "r" (x) : "cbit", "memory")
-
-#if !(defined(CONFIG_CHIP_M32102) || defined(CONFIG_CHIP_M32104))
-#define local_irq_save(x)                              \
-       __asm__ __volatile__(                           \
-               "mvfc   %0, psw;                \n\t"   \
-               "clrpsw #0x40 -> nop;           \n\t"   \
-               : "=r" (x) : /* no input */ : "memory")
-#else  /* CONFIG_CHIP_M32102 || CONFIG_CHIP_M32104 */
-#define local_irq_save(x)                              \
-       ({                                              \
-               unsigned long tmpreg;                   \
-               __asm__ __volatile__(                   \
-                       "ld24   %1, #0 \n\t"            \
-                       "mvfc   %0, psw \n\t"           \
-                       "mvtc   %1, psw \n\t"           \
-                       "and3   %1, %0, #0xffbf \n\t"   \
-                       "mvtc   %1, psw \n\t"           \
-                       : "=r" (x), "=&r" (tmpreg)      \
-                       : : "cbit", "memory");          \
-       })
-#endif /* CONFIG_CHIP_M32102 || CONFIG_CHIP_M32104 */
-
-#define irqs_disabled()                                        \
-       ({                                              \
-               unsigned long flags;                    \
-               local_save_flags(flags);                \
-               !(flags & 0x40);                        \
-       })
-
 #define nop()  __asm__ __volatile__ ("nop" : : )
 
 #define xchg(ptr, x)                                                   \
index 3c71f776872c51842a7959a911182b3c4afa3353..7db26f1f082d097f24ffa51da083694e05f47a5a 100644 (file)
@@ -51,7 +51,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-               seq_printf(p, " %14s", irq_desc[i].chip->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->name);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index 922fdfdadeaa220830d52a99f97a1cbe22e7ebd1..402a59d7219b6f368b38b4c9425ed79fa4279539 100644 (file)
@@ -65,7 +65,7 @@ static void shutdown_m32104ut_irq(unsigned int irq)
 
 static struct irq_chip m32104ut_irq_type =
 {
-       .typename = "M32104UT-IRQ",
+       .name = "M32104UT-IRQ",
        .startup = startup_m32104ut_irq,
        .shutdown = shutdown_m32104ut_irq,
        .enable = enable_m32104ut_irq,
index 9c1bc7487c1e652ff6bd9cb77ea79c5cdb989caf..80b1a026795aec2b8c8dae642143b4f5424538da 100644 (file)
@@ -71,7 +71,7 @@ static void shutdown_m32700ut_irq(unsigned int irq)
 
 static struct irq_chip m32700ut_irq_type =
 {
-       .typename = "M32700UT-IRQ",
+       .name = "M32700UT-IRQ",
        .startup = startup_m32700ut_irq,
        .shutdown = shutdown_m32700ut_irq,
        .enable = enable_m32700ut_irq,
@@ -148,7 +148,7 @@ static void shutdown_m32700ut_pld_irq(unsigned int irq)
 
 static struct irq_chip m32700ut_pld_irq_type =
 {
-       .typename = "M32700UT-PLD-IRQ",
+       .name = "M32700UT-PLD-IRQ",
        .startup = startup_m32700ut_pld_irq,
        .shutdown = shutdown_m32700ut_pld_irq,
        .enable = enable_m32700ut_pld_irq,
@@ -217,7 +217,7 @@ static void shutdown_m32700ut_lanpld_irq(unsigned int irq)
 
 static struct irq_chip m32700ut_lanpld_irq_type =
 {
-       .typename = "M32700UT-PLD-LAN-IRQ",
+       .name = "M32700UT-PLD-LAN-IRQ",
        .startup = startup_m32700ut_lanpld_irq,
        .shutdown = shutdown_m32700ut_lanpld_irq,
        .enable = enable_m32700ut_lanpld_irq,
@@ -286,7 +286,7 @@ static void shutdown_m32700ut_lcdpld_irq(unsigned int irq)
 
 static struct irq_chip m32700ut_lcdpld_irq_type =
 {
-       .typename = "M32700UT-PLD-LCD-IRQ",
+       .name = "M32700UT-PLD-LCD-IRQ",
        .startup = startup_m32700ut_lcdpld_irq,
        .shutdown = shutdown_m32700ut_lcdpld_irq,
        .enable = enable_m32700ut_lcdpld_irq,
index fb4b17799b66fd090b04f4d02364044f5558123d..ea00c84d6b1b2bb665bf0e88cf8ed885b2f96385 100644 (file)
@@ -65,7 +65,7 @@ static void shutdown_mappi_irq(unsigned int irq)
 
 static struct irq_chip mappi_irq_type =
 {
-       .typename = "MAPPI-IRQ",
+       .name = "MAPPI-IRQ",
        .startup = startup_mappi_irq,
        .shutdown = shutdown_mappi_irq,
        .enable = enable_mappi_irq,
index 6a65eda0a056c67ef039a34cc5d0326251be14d5..c049376d0270064869450bb56948a4edd57c068e 100644 (file)
@@ -72,7 +72,7 @@ static void shutdown_mappi2_irq(unsigned int irq)
 
 static struct irq_chip mappi2_irq_type =
 {
-       .typename = "MAPPI2-IRQ",
+       .name = "MAPPI2-IRQ",
        .startup = startup_mappi2_irq,
        .shutdown = shutdown_mappi2_irq,
        .enable = enable_mappi2_irq,
index 9c337aeac94b7db1a1d3d0f9307ef2116e15c687..882de25c6e8cc7d8f6bc9a55ef9a4c422fefcab2 100644 (file)
@@ -72,7 +72,7 @@ static void shutdown_mappi3_irq(unsigned int irq)
 
 static struct irq_chip mappi3_irq_type =
 {
-       .typename = "MAPPI3-IRQ",
+       .name = "MAPPI3-IRQ",
        .startup = startup_mappi3_irq,
        .shutdown = shutdown_mappi3_irq,
        .enable = enable_mappi3_irq,
index ed865741c38df1c6d9702e94bb17f033fdcca5c2..d11d93bf74f52bd4b14baea3e6fc3da16d83b271 100644 (file)
@@ -63,7 +63,7 @@ static void shutdown_oaks32r_irq(unsigned int irq)
 
 static struct irq_chip oaks32r_irq_type =
 {
-       .typename = "OAKS32R-IRQ",
+       .name = "OAKS32R-IRQ",
        .startup = startup_oaks32r_irq,
        .shutdown = shutdown_oaks32r_irq,
        .enable = enable_oaks32r_irq,
index 80d68065701963dff6107f6377bb7fc1c3416707..5f3402a2fbafe3c67cd549ac9c7335ff27aa3e1a 100644 (file)
@@ -72,7 +72,7 @@ static void shutdown_opsput_irq(unsigned int irq)
 
 static struct irq_chip opsput_irq_type =
 {
-       .typename = "OPSPUT-IRQ",
+       .name = "OPSPUT-IRQ",
        .startup = startup_opsput_irq,
        .shutdown = shutdown_opsput_irq,
        .enable = enable_opsput_irq,
@@ -149,7 +149,7 @@ static void shutdown_opsput_pld_irq(unsigned int irq)
 
 static struct irq_chip opsput_pld_irq_type =
 {
-       .typename = "OPSPUT-PLD-IRQ",
+       .name = "OPSPUT-PLD-IRQ",
        .startup = startup_opsput_pld_irq,
        .shutdown = shutdown_opsput_pld_irq,
        .enable = enable_opsput_pld_irq,
@@ -218,7 +218,7 @@ static void shutdown_opsput_lanpld_irq(unsigned int irq)
 
 static struct irq_chip opsput_lanpld_irq_type =
 {
-       .typename = "OPSPUT-PLD-LAN-IRQ",
+       .name = "OPSPUT-PLD-LAN-IRQ",
        .startup = startup_opsput_lanpld_irq,
        .shutdown = shutdown_opsput_lanpld_irq,
        .enable = enable_opsput_lanpld_irq,
index 757302660af84f2f09ffbb0e48fcf946ab27cd45..1beac7a51ed432ea386610b8b1bbe3132e04d6b7 100644 (file)
@@ -63,7 +63,7 @@ static void shutdown_mappi_irq(unsigned int irq)
 
 static struct irq_chip mappi_irq_type =
 {
-       .typename = "M32700-IRQ",
+       .name = "M32700-IRQ",
        .startup = startup_mappi_irq,
        .shutdown = shutdown_mappi_irq,
        .enable = enable_mappi_irq,
@@ -136,7 +136,7 @@ static void shutdown_m32700ut_pld_irq(unsigned int irq)
 
 static struct irq_chip m32700ut_pld_irq_type =
 {
-       .typename = "USRV-PLD-IRQ",
+       .name = "USRV-PLD-IRQ",
        .startup = startup_m32700ut_pld_irq,
        .shutdown = shutdown_m32700ut_pld_irq,
        .enable = enable_m32700ut_pld_irq,
index 907ed03d792f04bbf8b1aff2f07afa8534d2e237..80e41492aa2a0750018620d73c1387a36bbe265a 100644 (file)
@@ -28,7 +28,7 @@
  *                     M68K              COLDFIRE
  */
 
-#define ALLOWINT 0xf8ff
+#define ALLOWINT (~0x700)
 
 #ifdef __ASSEMBLY__
 
diff --git a/arch/m68k/include/asm/irqflags.h b/arch/m68k/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..4a5b284
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef _M68K_IRQFLAGS_H
+#define _M68K_IRQFLAGS_H
+
+#include <linux/types.h>
+#include <linux/hardirq.h>
+#include <linux/preempt.h>
+#include <asm/thread_info.h>
+#include <asm/entry.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+       asm volatile ("movew %%sr,%0" : "=d" (flags) : : "memory");
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+#ifdef CONFIG_COLDFIRE
+       asm volatile (
+               "move   %/sr,%%d0       \n\t"
+               "ori.l  #0x0700,%%d0    \n\t"
+               "move   %%d0,%/sr       \n"
+               : /* no outputs */
+               :
+               : "cc", "%d0", "memory");
+#else
+       asm volatile ("oriw  #0x0700,%%sr" : : : "memory");
+#endif
+}
+
+static inline void arch_local_irq_enable(void)
+{
+#if defined(CONFIG_COLDFIRE)
+       asm volatile (
+               "move   %/sr,%%d0       \n\t"
+               "andi.l #0xf8ff,%%d0    \n\t"
+               "move   %%d0,%/sr       \n"
+               : /* no outputs */
+               :
+               : "cc", "%d0", "memory");
+#else
+# if defined(CONFIG_MMU)
+       if (MACH_IS_Q40 || !hardirq_count())
+# endif
+               asm volatile (
+                       "andiw %0,%%sr"
+                       :
+                       : "i" (ALLOWINT)
+                       : "memory");
+#endif
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags = arch_local_save_flags();
+       arch_local_irq_disable();
+       return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile ("movew %0,%%sr" : : "d" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags & ~ALLOWINT) != 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* _M68K_IRQFLAGS_H */
index dbb6515ffd5b21f3d4a9e1544d7f6544ea604742..12053c44cccfe38d06ca1b556da85f1720f227dd 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/linkage.h>
 #include <linux/kernel.h>
+#include <linux/irqflags.h>
 #include <asm/segment.h>
 #include <asm/entry.h>
 
@@ -62,30 +63,6 @@ asmlinkage void resume(void);
 #define smp_wmb()      barrier()
 #define smp_read_barrier_depends()     ((void)0)
 
-/* interrupt control.. */
-#if 0
-#define local_irq_enable() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory")
-#else
-#include <linux/hardirq.h>
-#define local_irq_enable() ({                                                  \
-       if (MACH_IS_Q40 || !hardirq_count())                                    \
-               asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory");    \
-})
-#endif
-#define local_irq_disable() asm volatile ("oriw  #0x0700,%%sr": : : "memory")
-#define local_save_flags(x) asm volatile ("movew %%sr,%0":"=d" (x) : : "memory")
-#define local_irq_restore(x) asm volatile ("movew %0,%%sr": :"d" (x) : "memory")
-
-static inline int irqs_disabled(void)
-{
-       unsigned long flags;
-       local_save_flags(flags);
-       return flags & ~ALLOWINT;
-}
-
-/* For spinlocks etc */
-#define local_irq_save(x)      ({ local_save_flags(x); local_irq_disable(); })
-
 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
 
 struct __xchg_dummy { unsigned long a[100]; };
index 3c0718d74398b3b7ce0b29bfb66b3f1895474db8..20126c09794e5f59d7b58a94fcb07eb9a8e2d6f9 100644 (file)
@@ -2,6 +2,7 @@
 #define _M68KNOMMU_SYSTEM_H
 
 #include <linux/linkage.h>
+#include <linux/irqflags.h>
 #include <asm/segment.h>
 #include <asm/entry.h>
 
@@ -46,54 +47,6 @@ asmlinkage void resume(void);
   (last) = _last;                                              \
 }
 
-#ifdef CONFIG_COLDFIRE
-#define local_irq_enable() __asm__ __volatile__ (              \
-       "move %/sr,%%d0\n\t"                                    \
-       "andi.l #0xf8ff,%%d0\n\t"                               \
-       "move %%d0,%/sr\n"                                      \
-       : /* no outputs */                                      \
-       :                                                       \
-        : "cc", "%d0", "memory")
-#define local_irq_disable() __asm__ __volatile__ (             \
-       "move %/sr,%%d0\n\t"                                    \
-       "ori.l #0x0700,%%d0\n\t"                                \
-       "move %%d0,%/sr\n"                                      \
-       : /* no outputs */                                      \
-       :                                                       \
-       : "cc", "%d0", "memory")
-/* For spinlocks etc */
-#define local_irq_save(x) __asm__ __volatile__ (               \
-       "movew %%sr,%0\n\t"                                     \
-       "movew #0x0700,%%d0\n\t"                                \
-       "or.l  %0,%%d0\n\t"                                     \
-       "movew %%d0,%/sr"                                       \
-       : "=d" (x)                                              \
-       :                                                       \
-       : "cc", "%d0", "memory")
-#else
-
-/* portable version */ /* FIXME - see entry.h*/
-#define ALLOWINT 0xf8ff
-
-#define local_irq_enable() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory")
-#define local_irq_disable() asm volatile ("oriw  #0x0700,%%sr": : : "memory")
-#endif
-
-#define local_save_flags(x) asm volatile ("movew %%sr,%0":"=d" (x) : : "memory")
-#define local_irq_restore(x) asm volatile ("movew %0,%%sr": :"d" (x) : "memory")
-
-/* For spinlocks etc */
-#ifndef local_irq_save
-#define local_irq_save(x) do { local_save_flags(x); local_irq_disable(); } while (0)
-#endif
-
-#define        irqs_disabled()                 \
-({                                     \
-       unsigned long flags;            \
-       local_save_flags(flags);        \
-       ((flags & 0x0700) == 0x0700);   \
-})
-
 #define iret() __asm__ __volatile__ ("rte": : :"memory", "sp", "cc")
 
 /*
@@ -206,12 +159,4 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
 #define arch_align_stack(x) (x)
 
 
-static inline int irqs_disabled_flags(unsigned long flags)
-{
-       if (flags & 0x0700)
-               return 0;
-       else
-               return 1;
-}
-
 #endif /* _M68KNOMMU_SYSTEM_H */
index 9a8876f715d81d73214c97079d2a601460fe6234..24335022fa2c74893b695d041b330c4810680087 100644 (file)
@@ -74,8 +74,6 @@ int main(void)
 
        DEFINE(PT_PTRACED, PT_PTRACED);
 
-       DEFINE(THREAD_SIZE, THREAD_SIZE);
-
        /* Offsets in thread_info structure */
        DEFINE(TI_TASK, offsetof(struct thread_info, task));
        DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
index 4b91aa24eb00a6ec95510cfd88b210f99b8dcc05..0b2d7c7adf793324c0c0f193b6e3022bd2e6882c 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/coldfire.h>
 #include <asm/mcfcache.h>
 #include <asm/mcfsim.h>
+#include <asm/thread_info.h>
 
 /*****************************************************************************/
 
index 2c38c6d801769be469348fa80f4ef3283aab44e2..5fd31905775d691cb6d4e4fffbb0eeb91ad40013 100644 (file)
 #ifndef _ASM_MICROBLAZE_IRQFLAGS_H
 #define _ASM_MICROBLAZE_IRQFLAGS_H
 
-#include <linux/irqflags.h>
+#include <linux/types.h>
 #include <asm/registers.h>
 
-# if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-
-# define raw_local_irq_save(flags)                     \
-       do {                                            \
-               asm volatile (" msrclr %0, %1;          \
-                               nop;"                   \
-                               : "=r"(flags)           \
-                               : "i"(MSR_IE)           \
-                               : "memory");            \
-       } while (0)
-
-# define raw_local_irq_disable()                       \
-       do {                                            \
-               asm volatile (" msrclr r0, %0;          \
-                               nop;"                   \
-                               :                       \
-                               : "i"(MSR_IE)           \
-                               : "memory");            \
-       } while (0)
-
-# define raw_local_irq_enable()                                \
-       do {                                            \
-               asm volatile (" msrset  r0, %0;         \
-                               nop;"                   \
-                               :                       \
-                               : "i"(MSR_IE)           \
-                               : "memory");            \
-       } while (0)
-
-# else /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR == 0 */
-
-# define raw_local_irq_save(flags)                             \
-       do {                                                    \
-               register unsigned tmp;                          \
-               asm volatile (" mfs     %0, rmsr;               \
-                               nop;                            \
-                               andi    %1, %0, %2;             \
-                               mts     rmsr, %1;               \
-                               nop;"                           \
-                               : "=r"(flags), "=r" (tmp)       \
-                               : "i"(~MSR_IE)                  \
-                               : "memory");                    \
-       } while (0)
-
-# define raw_local_irq_disable()                               \
-       do {                                                    \
-               register unsigned tmp;                          \
-               asm volatile (" mfs     %0, rmsr;               \
-                               nop;                            \
-                               andi    %0, %0, %1;             \
-                               mts     rmsr, %0;               \
-                               nop;"                   \
-                               : "=r"(tmp)                     \
-                               : "i"(~MSR_IE)                  \
-                               : "memory");                    \
-       } while (0)
-
-# define raw_local_irq_enable()                                        \
-       do {                                                    \
-               register unsigned tmp;                          \
-               asm volatile (" mfs     %0, rmsr;               \
-                               nop;                            \
-                               ori     %0, %0, %1;             \
-                               mts     rmsr, %0;               \
-                               nop;"                           \
-                               : "=r"(tmp)                     \
-                               : "i"(MSR_IE)                   \
-                               : "memory");                    \
-       } while (0)
-
-# endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
-
-#define raw_local_irq_restore(flags)                           \
-       do {                                                    \
-               asm volatile (" mts     rmsr, %0;               \
-                               nop;"                           \
-                               :                               \
-                               : "r"(flags)                    \
-                               : "memory");                    \
-       } while (0)
-
-static inline unsigned long get_msr(void)
+#ifdef CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags;
+       asm volatile("  msrclr %0, %1   \n"
+                    "  nop             \n"
+                    : "=r"(flags)
+                    : "i"(MSR_IE)
+                    : "memory");
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       /* this uses r0 without declaring it - is that correct? */
+       asm volatile("  msrclr r0, %0   \n"
+                    "  nop             \n"
+                    :
+                    : "i"(MSR_IE)
+                    : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       /* this uses r0 without declaring it - is that correct? */
+       asm volatile("  msrset  r0, %0  \n"
+                    "  nop             \n"
+                    :
+                    : "i"(MSR_IE)
+                    : "memory");
+}
+
+#else /* !CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags, tmp;
+       asm volatile (" mfs     %0, rmsr        \n"
+                     " nop                     \n"
+                     " andi    %1, %0, %2      \n"
+                     " mts     rmsr, %1        \n"
+                     " nop                     \n"
+                     : "=r"(flags), "=r"(tmp)
+                     : "i"(~MSR_IE)
+                     : "memory");
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       unsigned long tmp;
+       asm volatile("  mfs     %0, rmsr        \n"
+                    "  nop                     \n"
+                    "  andi    %0, %0, %1      \n"
+                    "  mts     rmsr, %0        \n"
+                    "  nop                     \n"
+                    : "=r"(tmp)
+                    : "i"(~MSR_IE)
+                    : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       unsigned long tmp;
+       asm volatile("  mfs     %0, rmsr        \n"
+                    "  nop                     \n"
+                    "  ori     %0, %0, %1      \n"
+                    "  mts     rmsr, %0        \n"
+                    "  nop                     \n"
+                    : "=r"(tmp)
+                    : "i"(MSR_IE)
+                    : "memory");
+}
+
+#endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
+
+static inline unsigned long arch_local_save_flags(void)
 {
        unsigned long flags;
-       asm volatile (" mfs     %0, rmsr;       \
-                       nop;"                   \
-                       : "=r"(flags)           \
-                       :                       \
-                       : "memory");            \
+       asm volatile("  mfs     %0, rmsr        \n"
+                    "  nop                     \n"
+                    : "=r"(flags)
+                    :
+                    : "memory");
        return flags;
 }
 
-#define raw_local_save_flags(flags)    ((flags) = get_msr())
-#define raw_irqs_disabled()            ((get_msr() & MSR_IE) == 0)
-#define raw_irqs_disabled_flags(flags) ((flags & MSR_IE) == 0)
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile("  mts     rmsr, %0        \n"
+                    "  nop                     \n"
+                    :
+                    : "r"(flags)
+                    : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags & MSR_IE) == 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
 
 #endif /* _ASM_MICROBLAZE_IRQFLAGS_H */
index f9c2fa331d2ad92e675aad399befb989cc575fbc..20a8e257c77f3c2abadf04c8c87aad2347de4ee6 100644 (file)
@@ -9,9 +9,6 @@
 #ifndef _ASM_MICROBLAZE_MEMBLOCK_H
 #define _ASM_MICROBLAZE_MEMBLOCK_H
 
-/* MEMBLOCK limit is OFF */
-#define MEMBLOCK_REAL_LIMIT    0xFFFFFFFF
-
 #endif /* _ASM_MICROBLAZE_MEMBLOCK_H */
 
 
index 65eb00419d19dc8ac69e98cc2755b9cbc841d405..c8437866d3b75f3bde5d7c5fad00f9d624e9d58e 100644 (file)
@@ -70,16 +70,16 @@ static void __init paging_init(void)
 
 void __init setup_memory(void)
 {
-       int i;
        unsigned long map_size;
+       struct memblock_region *reg;
+
 #ifndef CONFIG_MMU
        u32 kernel_align_start, kernel_align_size;
 
        /* Find main memory where is the kernel */
-       for (i = 0; i < memblock.memory.cnt; i++) {
-               memory_start = (u32) memblock.memory.region[i].base;
-               memory_end = (u32) memblock.memory.region[i].base
-                               + (u32) memblock.memory.region[i].size;
+       for_each_memblock(memory, reg) {
+               memory_start = (u32)reg->base;
+               memory_end = (u32) reg->base + reg->size;
                if ((memory_start <= (u32)_text) &&
                                        ((u32)_text <= memory_end)) {
                        memory_size = memory_end - memory_start;
@@ -142,12 +142,10 @@ void __init setup_memory(void)
        free_bootmem(memory_start, memory_size);
 
        /* reserve allocate blocks */
-       for (i = 0; i < memblock.reserved.cnt; i++) {
-               pr_debug("reserved %d - 0x%08x-0x%08x\n", i,
-                       (u32) memblock.reserved.region[i].base,
-                       (u32) memblock_size_bytes(&memblock.reserved, i));
-               reserve_bootmem(memblock.reserved.region[i].base,
-                       memblock_size_bytes(&memblock.reserved, i) - 1, BOOTMEM_DEFAULT);
+       for_each_memblock(reserved, reg) {
+               pr_debug("reserved - 0x%08x-0x%08x\n",
+                        (u32) reg->base, (u32) reg->size);
+               reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
        }
 #ifdef CONFIG_MMU
        init_bootmem_done = 1;
@@ -230,7 +228,7 @@ static void mm_cmdline_setup(void)
                if (maxmem && memory_size > maxmem) {
                        memory_size = maxmem;
                        memory_end = memory_start + memory_size;
-                       memblock.memory.region[0].size = memory_size;
+                       memblock.memory.regions[0].size = memory_size;
                }
        }
 }
@@ -273,14 +271,14 @@ asmlinkage void __init mmu_init(void)
                machine_restart(NULL);
        }
 
-       if ((u32) memblock.memory.region[0].size < 0x1000000) {
+       if ((u32) memblock.memory.regions[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) memblock.memory.region[0].base;
-       memory_end = (u32) memblock.memory.region[0].base +
-                               (u32) memblock.memory.region[0].size;
+       memory_start = (u32) memblock.memory.regions[0].base;
+       memory_end = (u32) memblock.memory.regions[0].base +
+                               (u32) memblock.memory.regions[0].size;
        memory_size = memory_end - memory_start;
 
        mm_cmdline_setup(); /* FIXME parse args from command line - not used */
index e322d65f33a41e0085e5d352410ca0b5c3f37e26..7dd65cfae83759562e43ab20bb03be071ae56ce5 100644 (file)
@@ -7,6 +7,10 @@ subdir-ccflags-y := -Werror
 include arch/mips/Kbuild.platforms
 obj-y := $(platform-y)
 
+# make clean traverses $(obj-) without having included .config, so
+# everything ends up here
+obj- := $(platform-)
+
 # mips object files
 # The object files are linked as core-y files would be linked
 
index 3bc4fd2155d70303a439f2004a6407ec92888b6e..c52af8821da071f5fe49117ddb6f7f2652756c00 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/irq.h>
 #include <asm/addrspace.h>
 #include <asm/io.h>
 #include <asm/mach-db1x00/bcsr.h>
index c781556c44e46cea3c51a84d149e1b3d68f6c8b8..4ec2642c568fb18ce58c6eb277f58b7fb55772d9 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
index a0c5cd18c192a4aef91634b58ca851576cd2b4c6..3be87f2422f0357ddd16411c4fa0d406dc21cbe1 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/irq.h>
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
 #include <bcm63xx_cpu.h>
index 638adab028428002186bb83c589b553a0c40545b..12dbf533b77dc2da263c4e0bfe9e4c2fa86c51d8 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/serial_8250.h>
 #include <linux/serial_reg.h>
 #include <linux/tty.h>
+#include <linux/irq.h>
 
 #include <asm/time.h>
 
index 3adbcbd95db1efd4dbb18fba91bc978153079d7f..cf55a6f4e720c4e831733ceab40d820fa136a2c8 100644 (file)
@@ -1,7 +1,7 @@
 #
 # DECstation family
 #
-platform-$(CONFIG_MACH_DECSTATION)     = dec/
+platform-$(CONFIG_MACH_DECSTATION)     += dec/
 cflags-$(CONFIG_MACH_DECSTATION)       += \
                        -I$(srctree)/arch/mips/include/asm/mach-dec
 libs-$(CONFIG_MACH_DECSTATION)         += arch/mips/dec/prom/
index bd5431e1f4085fbfbcd2dfadc5097395828a4fae..fa45e924be05b9e40cf9d23b5a6a866034dfb8f3 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/pm.h>
+#include <linux/irq.h>
 
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
index 701ec0ba8fa9cdd596369b9de3825b284bae1ec9..9ef3b0d178962e92cf4ac27efc77f564b50667df 100644 (file)
@@ -17,7 +17,7 @@
 #include <asm/hazards.h>
 
 __asm__(
-       "       .macro  raw_local_irq_enable                            \n"
+       "       .macro  arch_local_irq_enable                           \n"
        "       .set    push                                            \n"
        "       .set    reorder                                         \n"
        "       .set    noat                                            \n"
@@ -40,7 +40,7 @@ __asm__(
 
 extern void smtc_ipi_replay(void);
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_enable(void)
 {
 #ifdef CONFIG_MIPS_MT_SMTC
        /*
@@ -50,7 +50,7 @@ static inline void raw_local_irq_enable(void)
        smtc_ipi_replay();
 #endif
        __asm__ __volatile__(
-               "raw_local_irq_enable"
+               "arch_local_irq_enable"
                : /* no outputs */
                : /* no inputs */
                : "memory");
@@ -76,7 +76,7 @@ static inline void raw_local_irq_enable(void)
  * Workaround: mask EXL bit of the result or place a nop before mfc0.
  */
 __asm__(
-       "       .macro  raw_local_irq_disable\n"
+       "       .macro  arch_local_irq_disable\n"
        "       .set    push                                            \n"
        "       .set    noat                                            \n"
 #ifdef CONFIG_MIPS_MT_SMTC
@@ -97,17 +97,17 @@ __asm__(
        "       .set    pop                                             \n"
        "       .endm                                                   \n");
 
-static inline void raw_local_irq_disable(void)
+static inline void arch_local_irq_disable(void)
 {
        __asm__ __volatile__(
-               "raw_local_irq_disable"
+               "arch_local_irq_disable"
                : /* no outputs */
                : /* no inputs */
                : "memory");
 }
 
 __asm__(
-       "       .macro  raw_local_save_flags flags                      \n"
+       "       .macro  arch_local_save_flags flags                     \n"
        "       .set    push                                            \n"
        "       .set    reorder                                         \n"
 #ifdef CONFIG_MIPS_MT_SMTC
@@ -118,13 +118,15 @@ __asm__(
        "       .set    pop                                             \n"
        "       .endm                                                   \n");
 
-#define raw_local_save_flags(x)                                                \
-__asm__ __volatile__(                                                  \
-       "raw_local_save_flags %0"                                       \
-       : "=r" (x))
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+       asm volatile("arch_local_save_flags %0" : "=r" (flags));
+       return flags;
+}
 
 __asm__(
-       "       .macro  raw_local_irq_save result                       \n"
+       "       .macro  arch_local_irq_save result                      \n"
        "       .set    push                                            \n"
        "       .set    reorder                                         \n"
        "       .set    noat                                            \n"
@@ -148,15 +150,18 @@ __asm__(
        "       .set    pop                                             \n"
        "       .endm                                                   \n");
 
-#define raw_local_irq_save(x)                                          \
-__asm__ __volatile__(                                                  \
-       "raw_local_irq_save\t%0"                                        \
-       : "=r" (x)                                                      \
-       : /* no inputs */                                               \
-       : "memory")
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags;
+       asm volatile("arch_local_irq_save\t%0"
+                    : "=r" (flags)
+                    : /* no inputs */
+                    : "memory");
+       return flags;
+}
 
 __asm__(
-       "       .macro  raw_local_irq_restore flags                     \n"
+       "       .macro  arch_local_irq_restore flags                    \n"
        "       .set    push                                            \n"
        "       .set    noreorder                                       \n"
        "       .set    noat                                            \n"
@@ -196,7 +201,7 @@ __asm__(
        "       .endm                                                   \n");
 
 
-static inline void raw_local_irq_restore(unsigned long flags)
+static inline void arch_local_irq_restore(unsigned long flags)
 {
        unsigned long __tmp1;
 
@@ -211,24 +216,24 @@ static inline void raw_local_irq_restore(unsigned long flags)
 #endif
 
        __asm__ __volatile__(
-               "raw_local_irq_restore\t%0"
+               "arch_local_irq_restore\t%0"
                : "=r" (__tmp1)
                : "0" (flags)
                : "memory");
 }
 
-static inline void __raw_local_irq_restore(unsigned long flags)
+static inline void __arch_local_irq_restore(unsigned long flags)
 {
        unsigned long __tmp1;
 
        __asm__ __volatile__(
-               "raw_local_irq_restore\t%0"
+               "arch_local_irq_restore\t%0"
                : "=r" (__tmp1)
                : "0" (flags)
                : "memory");
 }
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline int arch_irqs_disabled_flags(unsigned long flags)
 {
 #ifdef CONFIG_MIPS_MT_SMTC
        /*
index cb6985f24303668e661c0373b39e0f08a5d898f5..1e29b9dd1d7395752d401fca112b2f1f528357c8 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/io.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 
 /* loongson internal northbridge initialization */
 extern void bonito_irq_init(void);
index ee18028efe9222ba4c4c9fa54fa37296d3800055..35b3e2f0af04899ee159d59129203e445cfb6e49 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/spinlock.h>
+#include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/i8253.h>
index 6a97230e3d05ee4a53478c2a4625c51d92b26bd2..ba91be9c21ef405f65e0ae87fafe92a66ac8b06f 100644 (file)
@@ -1,3 +1,3 @@
-core-$(CONFIG_MACH_JZ4740)     += arch/mips/jz4740/
+platform-$(CONFIG_MACH_JZ4740) += jz4740/
 cflags-$(CONFIG_MACH_JZ4740)   += -I$(srctree)/arch/mips/include/asm/mach-jz4740
 load-$(CONFIG_MACH_JZ4740)     += 0xffffffff80010000
index bfea327c636c1e635089f19846f14303d7d5911b..36c3898b76dbb01182184744fec80056c1132cd8 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 
 #include <asm/addrspace.h>
 #include <asm/io.h>
index 00a4da277cbbef1b94b6d0f767973fb19d3c676c..939157e397b940fd811d348997840c9dc34a0a0b 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/mc146818rtc.h>
+#include <linux/irq.h>
 
 #include <asm/time.h>
 
index 392ef3756c56e0692d46e38cf5647b4f24bac951..339f3639b90e463d41931b7b127c3173e74297af 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/spinlock.h>
+#include <linux/irq.h>
 
 #include <asm/gt64120.h>
 #include <asm/time.h>
index 2a4d50ff5e2c17e8ad56e86593e48b70f29ee4df..2f4d7a99bcc2fcc91b3838599b0b0c3d4fb1c432 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 
 #include <asm/smtc_ipi.h>
 #include <asm/time.h>
index da78eeaea6e81a5d6fc7516ed4dcb04195d143a2..590c54f28a81772f961b2513fef1147d4d581f62 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include <linux/clockchips.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/percpu.h>
 #include <linux/smp.h>
 
index b102e4f1630eaa8e021b4c61b0b959f646f2bb81..2e72d30b2f05a9b2b0d1a40dd90699c658925d5b 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/interrupt.h>
 #include <linux/percpu.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 
 #include <asm/smtc_ipi.h>
 #include <asm/time.h>
index 218ee6bda9353822e010b5ba8d521b96a05991b9..0b7377361e22fa8b3d76afc335344c35613cac59 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/time.h>
 #include <asm/txx9tmr.h>
 
index 94794062a1777814c03428b27576796fe3f2a7a7..2392a7a296d41d4585fc406948ed58d4f83443f9 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/smp.h>
 #include <linux/spinlock.h>
+#include <linux/irq.h>
 
 #include <asm/delay.h>
 #include <asm/i8253.h>
index 27799113332cfa9c952d7402164201c3acf057c3..c58176cc796baa0c03d6d86597ab5252478f4e65 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/sysdev.h>
+#include <linux/irq.h>
 
 #include <asm/i8259.h>
 #include <asm/io.h>
index 82ba9f62f49e3b2faa98abc1f6da2fe1e062a4ed..1774271af848b7cca4dc2ab2da0578c7f38a6e13 100644 (file)
@@ -3,11 +3,11 @@
 #include <linux/bitmap.h>
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <linux/irq.h>
 
 #include <asm/io.h>
 #include <asm/gic.h>
 #include <asm/gcmpregs.h>
-#include <asm/irq.h>
 #include <linux/hardirq.h>
 #include <asm-generic/bitops/find.h>
 
index fb50cc78b28b45cf36ffddb8fa4add2a734d5fa1..9731e8b47862f221124b8ed84df2a66a8c704cd5 100644 (file)
@@ -11,6 +11,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 
 #include <asm/irq_cpu.h>
index b47e4615ec126980ca5cb457a67bd7244b2135f5..b7e4025b58a83d940080154b3edb76f3807c9e09 100644 (file)
@@ -11,6 +11,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 
index 55c8a3ca507b2800fab0406d81d0844c660a7c04..0262abe09121954b47e40a2b0b4c6f21ff1feb37 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
index 9b78029bea7026f237a337f981f0dd98c90661b5..95a96f69172d6d111a492e120c2af18adc364196 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/types.h>
+#include <linux/irq.h>
 #include <asm/txx9irq.h>
 
 struct txx9_irc_reg {
index 2340f11dc29cc8de689593c8b49315b613a6aae8..9a526ba6f25766f3ab6b58bc70b7f792c4011ff9 100644 (file)
@@ -103,7 +103,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
        if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
                goto out_unlock;
 
-       retval = security_task_setscheduler(p, 0, NULL);
+       retval = security_task_setscheduler(p)
        if (retval)
                goto out_unlock;
 
index 38b226938db3f5342dd99745ac7d599a57d4ec86..f08ece6d8acc7f3aa78ecbca23f801ae76727f6a 100644 (file)
@@ -322,10 +322,10 @@ EXPORT(sysn32_call_table)
        PTR     sys_cacheflush
        PTR     sys_cachectl
        PTR     sys_sysmips
-       PTR     sys_io_setup                    /* 6200 */
+       PTR     compat_sys_io_setup                     /* 6200 */
        PTR     sys_io_destroy
-       PTR     sys_io_getevents
-       PTR     sys_io_submit
+       PTR     compat_sys_io_getevents
+       PTR     compat_sys_io_submit
        PTR     sys_io_cancel
        PTR     sys_exit_group                  /* 6205 */
        PTR     sys_lookup_dcookie
index 42fe14b52a335ca55884dc9f5aa2bb15b32d20a8..78d768a3e19da78fc986e9170f73b240ee98c1c2 100644 (file)
@@ -445,10 +445,10 @@ sys_call_table:
        PTR     compat_sys_futex
        PTR     compat_sys_sched_setaffinity
        PTR     compat_sys_sched_getaffinity    /* 4240 */
-       PTR     sys_io_setup
+       PTR     compat_sys_io_setup
        PTR     sys_io_destroy
-       PTR     sys_io_getevents
-       PTR     sys_io_submit
+       PTR     compat_sys_io_getevents
+       PTR     compat_sys_io_submit
        PTR     sys_io_cancel                   /* 4245 */
        PTR     sys_exit_group
        PTR     sys32_lookup_dcookie
index cfeb2c1558967a540df6be261478df57c73a440f..39c08254b0f16f7d36e1b73344cb75c52ed9619f 100644 (file)
@@ -1038,7 +1038,7 @@ void deferred_smtc_ipi(void)
                 * but it's more efficient, given that we're already
                 * running down the IPI queue.
                 */
-               __raw_local_irq_restore(flags);
+               __arch_local_irq_restore(flags);
        }
 }
 
@@ -1190,7 +1190,7 @@ void smtc_ipi_replay(void)
                /*
                 ** But use a raw restore here to avoid recursion.
                 */
-               __raw_local_irq_restore(flags);
+               __arch_local_irq_restore(flags);
 
                if (pipi) {
                        self_ipi(pipi);
index 03ec0019032bc50ebbc9435cdec3c71eeaa9ac70..d053bf4759e417071760634656083151358ef23c 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/kprobes.h>
 #include <linux/notifier.h>
 #include <linux/kdb.h>
+#include <linux/irq.h>
 
 #include <asm/bootinfo.h>
 #include <asm/branch.h>
@@ -51,7 +52,6 @@
 #include <asm/mmu_context.h>
 #include <asm/types.h>
 #include <asm/stacktrace.h>
-#include <asm/irq.h>
 #include <asm/uasm.h>
 
 extern void check_wait(void);
index 72e32a7715beff770347237d6944472184853cf4..4c35301720e76c04aad4eade1d88310c107ba6fd 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/serial_8250.h>
 #include <linux/mc146818rtc.h>
 #include <linux/module.h>
+#include <linux/irq.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 #include <linux/platform_device.h>
index 31c15019659544a55f81f2675abf25f7a085640e..6a3bdb5ffa8074e5ba3e978d6989115857e17e5b 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <asm/addrspace.h>
 #include <asm/txx9irq.h>
index 5989e747527f2e4e67f591b93a1f4eb2f16652f3..a1e7e6d80c8c718e9b532e5ccb8ff0e7bac9e164 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/txx9/pci.h>
 #include <asm/txx9/tx4927pcic.h>
 
index 94c9c2c9fbc1d650897ac14eec91d68377c8ac5e..07e71ff2433f642428462d405c0f843d3928fd6b 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/bitops.h>
+#include <linux/irq.h>
 
 #include <asm/system.h>
 
index b54d24499b062d31fc5e04cd8f18f0a417532043..e5538243415576d121b1400aceadc726c6a7fec8 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
+#include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/mipsregs.h>
index 00ed19f0bdb56e4a9045ba7e2f7388562978d6a4..70482540b3dbc7edf469be8e14beb7e37a1f5f68 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/tty.h>
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
+#include <linux/irq.h>
 
 #include <asm/serial.h>
 #include <asm/mach-rc32434/rb.h>
index e6980892834aae7a00865172e2303c67732bc86b..bbe7187879fa9bb5c493f215ba1ef8f8f81cc695 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 
index 51e62bbaa23bb2440fa671fc22fe57930690aea6..8c92c73bc717db178bcdbce74788f30fe1b193b5 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/serial_8250.h>
 
index f4699d35858b70820f638d053dac36be73f4da5c..dc9874553becbf62abc5dce1135e9a7444f43d88 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/serial_8250.h>
 
index 90c558f7c0fa91b18df793a903cf8296fffc12fa..0e6f42c2bbc86c69117bd90bef5c22456f8c01ac 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/platform_device.h>
 #include <linux/serial_8250.h>
 #include <linux/io.h>
index f3b60e671207bea19676fd1c0cca9a4a38180ccb..c76151b56568ee241e345fe779d3454df0179add 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/smp.h>
 #include <linux/time.h>
 #include <linux/clockchips.h>
index ad2870def8f1f7e1697205cfe2094f6a988ab7e8..e1828e8bcaefedd4449cb0b96806c50708b343ed 100644 (file)
@@ -25,6 +25,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/irq_cpu.h>
 #include <asm/txx9/tx4927.h>
 
index 025ae11359a8183cadd81f1418127b45b215c395..a6e6e805097a80be53edf7501f2ead464ae8f023 100644 (file)
@@ -13,6 +13,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/irq_cpu.h>
 #include <asm/txx9/tx4938.h>
 
index 013213a8706b61d7c2f7d806b0b98ffb3637fdb3..3886ad77cbadd21a1ed1a97ffea7482ea083d88a 100644 (file)
@@ -19,6 +19,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/types.h>
 #include <asm/irq_cpu.h>
 #include <asm/txx9irq.h>
index 575d219b80014fea3e74cfef9865769251b79635..812816c456620f86fce6ba670d2f6352df7f9b6d 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/leds.h>
 #include <linux/sysdev.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
 #include <asm/bootinfo.h>
 #include <asm/time.h>
 #include <asm/reboot.h>
index 6ec626c9473fd4014a5c31919347d51aed407810..0a7f8e3b9fd796b7fe384d39772aef124231f40e 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <asm/io.h>
 #include <asm/mipsregs.h>
index 9c14ebb26cb4caf63f7448b02b83ad4e435f2332..c4b54d20efd3c67fc279ef8d6cfbe2099bc0b62a 100644 (file)
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/io.h>
 #include <asm/mipsregs.h>
 #include <asm/txx9/generic.h>
index 7d21befb8932c5ba36df028cb74b1c66e61c652d..67a73a8065ec800e00ebb753f612195434f5189b 100644 (file)
@@ -64,6 +64,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/mipsregs.h>
 #include <asm/txx9/generic.h>
 #include <asm/txx9/rbtx4938.h>
index 500cc0a908e6b8876e529c161d2cf1eee6f18f69..57fa740a72056b65ecd0f08e55fb23fe434083e7 100644 (file)
@@ -11,6 +11,7 @@
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/mipsregs.h>
 #include <asm/txx9/rbtx4939.h>
 
index bef06872f012d6ecb055aafeae92d9ed6f962135..0975eb72d385e189af3f26895eeb689ab3d950c3 100644 (file)
@@ -19,6 +19,7 @@
  */
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/irq.h>
 
 #include <asm/irq_cpu.h>
 #include <asm/system.h>
index 54eae56108fb94db06a5add150e8baad4ef5dbfe..bbd45d2559d63b4b1c23da18bdbc0ceb8dc655a9 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
+#include <linux/irq.h>
 
 #include <asm/cpu.h>
 #include <asm/vr41xx/siu.h>
diff --git a/arch/mn10300/include/asm/irqflags.h b/arch/mn10300/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..5e529a1
--- /dev/null
@@ -0,0 +1,123 @@
+/* MN10300 IRQ flag handling
+ *
+ * Copyright (C) 2010 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_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+#include <asm/cpu-regs.h>
+
+/*
+ * interrupt control
+ * - "disabled": run in IM1/2
+ *   - level 0 - GDB stub
+ *   - level 1 - virtual serial DMA (if present)
+ *   - level 5 - normal interrupt priority
+ *   - level 6 - timer interrupt
+ * - "enabled":  run in IM7
+ */
+#ifdef CONFIG_MN10300_TTYSM
+#define MN10300_CLI_LEVEL      EPSW_IM_2
+#else
+#define MN10300_CLI_LEVEL      EPSW_IM_1
+#endif
+
+#ifndef __ASSEMBLY__
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+
+       asm volatile("mov epsw,%0" : "=d"(flags));
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       asm volatile(
+               "       and %0,epsw     \n"
+               "       or %1,epsw      \n"
+               "       nop             \n"
+               "       nop             \n"
+               "       nop             \n"
+               :
+               : "i"(~EPSW_IM), "i"(EPSW_IE | MN10300_CLI_LEVEL)
+               : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags;
+
+       flags = arch_local_save_flags();
+       arch_local_irq_disable();
+       return flags;
+}
+
+/*
+ * we make sure arch_irq_enable() doesn't cause priority inversion
+ */
+extern unsigned long __mn10300_irq_enabled_epsw;
+
+static inline void arch_local_irq_enable(void)
+{
+       unsigned long tmp;
+
+       asm volatile(
+               "       mov     epsw,%0         \n"
+               "       and     %1,%0           \n"
+               "       or      %2,%0           \n"
+               "       mov     %0,epsw         \n"
+               : "=&d"(tmp)
+               : "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw)
+               : "memory");
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile(
+               "       mov %0,epsw     \n"
+               "       nop             \n"
+               "       nop             \n"
+               "       nop             \n"
+               :
+               : "d"(flags)
+               : "memory", "cc");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags & EPSW_IM) <= MN10300_CLI_LEVEL;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+/*
+ * Hook to save power by halting the CPU
+ * - called from the idle loop
+ * - must reenable interrupts (which takes three instruction cycles to complete)
+ */
+static inline void arch_safe_halt(void)
+{
+       asm volatile(
+               "       or      %0,epsw \n"
+               "       nop             \n"
+               "       nop             \n"
+               "       bset    %2,(%1) \n"
+               :
+               : "i"(EPSW_IE|EPSW_IM), "n"(&CPUM), "i"(CPUM_SLEEP)
+               : "cc");
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_IRQFLAGS_H */
index 3636c054dcd526202a3028c389c8515a450ffa98..9f7c7e17c01ee7d8560a568dd4f2d98636c7f130 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef __ASSEMBLY__
 
 #include <linux/kernel.h>
+#include <linux/irqflags.h>
 
 struct task_struct;
 struct thread_struct;
@@ -79,114 +80,6 @@ do {                                                                        \
 #define read_barrier_depends()         do {} while (0)
 #define smp_read_barrier_depends()     do {} while (0)
 
-/*****************************************************************************/
-/*
- * interrupt control
- * - "disabled": run in IM1/2
- *   - level 0 - GDB stub
- *   - level 1 - virtual serial DMA (if present)
- *   - level 5 - normal interrupt priority
- *   - level 6 - timer interrupt
- * - "enabled":  run in IM7
- */
-#ifdef CONFIG_MN10300_TTYSM
-#define MN10300_CLI_LEVEL      EPSW_IM_2
-#else
-#define MN10300_CLI_LEVEL      EPSW_IM_1
-#endif
-
-#define local_save_flags(x)                    \
-do {                                           \
-       typecheck(unsigned long, x);            \
-       asm volatile(                           \
-               "       mov epsw,%0     \n"     \
-               : "=d"(x)                       \
-               );                              \
-} while (0)
-
-#define local_irq_disable()                                            \
-do {                                                                   \
-       asm volatile(                                                   \
-               "       and %0,epsw     \n"                             \
-               "       or %1,epsw      \n"                             \
-               "       nop             \n"                             \
-               "       nop             \n"                             \
-               "       nop             \n"                             \
-               :                                                       \
-               : "i"(~EPSW_IM), "i"(EPSW_IE | MN10300_CLI_LEVEL)       \
-               );                                                      \
-} while (0)
-
-#define local_irq_save(x)                      \
-do {                                           \
-       local_save_flags(x);                    \
-       local_irq_disable();                    \
-} while (0)
-
-/*
- * we make sure local_irq_enable() doesn't cause priority inversion
- */
-#ifndef __ASSEMBLY__
-
-extern unsigned long __mn10300_irq_enabled_epsw;
-
-#endif
-
-#define local_irq_enable()                                             \
-do {                                                                   \
-       unsigned long tmp;                                              \
-                                                                       \
-       asm volatile(                                                   \
-               "       mov     epsw,%0         \n"                     \
-               "       and     %1,%0           \n"                     \
-               "       or      %2,%0           \n"                     \
-               "       mov     %0,epsw         \n"                     \
-               : "=&d"(tmp)                                            \
-               : "i"(~EPSW_IM), "r"(__mn10300_irq_enabled_epsw)        \
-               : "cc"                                                  \
-               );                                                      \
-} while (0)
-
-#define local_irq_restore(x)                   \
-do {                                           \
-       typecheck(unsigned long, x);            \
-       asm volatile(                           \
-               "       mov %0,epsw     \n"     \
-               "       nop             \n"     \
-               "       nop             \n"     \
-               "       nop             \n"     \
-               :                               \
-               : "d"(x)                        \
-               : "memory", "cc"                \
-               );                              \
-} while (0)
-
-#define irqs_disabled()                                \
-({                                             \
-       unsigned long flags;                    \
-       local_save_flags(flags);                \
-       (flags & EPSW_IM) <= MN10300_CLI_LEVEL; \
-})
-
-/* hook to save power by halting the CPU
- * - called from the idle loop
- * - must reenable interrupts (which takes three instruction cycles to complete)
- */
-#define safe_halt()                                                    \
-do {                                                                   \
-       asm volatile("  or      %0,epsw \n"                             \
-                    "  nop             \n"                             \
-                    "  nop             \n"                             \
-                    "  bset    %2,(%1) \n"                             \
-                    :                                                  \
-                    : "i"(EPSW_IE|EPSW_IM), "n"(&CPUM), "i"(CPUM_SLEEP)\
-                    : "cc"                                             \
-                    );                                                 \
-} while (0)
-
-#define STI    or EPSW_IE|EPSW_IM,epsw
-#define CLI    and ~EPSW_IM,epsw; or EPSW_IE|MN10300_CLI_LEVEL,epsw; nop; nop; nop
-
 /*****************************************************************************/
 /*
  * MN10300 doesn't actually have an exchange instruction
index d9ed5a15c547f8800f16080e6699c1ad131d5d2c..3d394b4eefba1e5a90f14c22997b1ccbbcb3fc5e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/linkage.h>
 #include <asm/smp.h>
 #include <asm/system.h>
+#include <asm/irqflags.h>
 #include <asm/thread_info.h>
 #include <asm/intctl-regs.h>
 #include <asm/busctl-regs.h>
index 907417d187e15039bb4bb6d96075cd950a045dbd..79a04a9394d5ad33b768d79ce1c2230b24e1c9bb 100644 (file)
@@ -16,6 +16,7 @@ config PARISC
        select RTC_DRV_GENERIC
        select INIT_ALL_POSSIBLE
        select BUG
+       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select GENERIC_ATOMIC64 if !64BIT
        help
diff --git a/arch/parisc/include/asm/irqflags.h b/arch/parisc/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..34f9cb9
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __PARISC_IRQFLAGS_H
+#define __PARISC_IRQFLAGS_H
+
+#include <linux/types.h>
+#include <asm/psw.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+       asm volatile("ssm 0, %0" : "=r" (flags) : : "memory");
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       asm volatile("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       asm volatile("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags;
+       asm volatile("rsm %1,%0" : "=r" (flags) : "i" (PSW_I) : "memory");
+       return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile("mtsm %0" : : "r" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags & PSW_I) == 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* __PARISC_IRQFLAGS_H */
index cc146427d8f9acf2219aa14813d76e52835bb83f..1e0fd8ba6c033e5f277afc02075fc7de57b1adc6 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __ASM_PARISC_PERF_EVENT_H
 #define __ASM_PARISC_PERF_EVENT_H
 
-/* parisc only supports software events through this interface. */
-static inline void set_perf_event_pending(void) { }
+/* Empty, just to avoid compiling error */
 
 #endif /* __ASM_PARISC_PERF_EVENT_H */
index 2ab4af58ecb9ca20cf13751868c917fe09b36a7b..b19e63a8e8484413b5df79d82e3f3a7905e41a0f 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __PARISC_SYSTEM_H
 #define __PARISC_SYSTEM_H
 
-#include <asm/psw.h>
+#include <linux/irqflags.h>
 
 /* The program status word as bitfields.  */
 struct pa_psw {
@@ -48,23 +48,6 @@ extern struct task_struct *_switch_to(struct task_struct *, struct task_struct *
        (last) = _switch_to(prev, next);                        \
 } while(0)
 
-/* interrupt control */
-#define local_save_flags(x)    __asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory")
-#define local_irq_disable()    __asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
-#define local_irq_enable()     __asm__ __volatile__("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory" )
-
-#define local_irq_save(x) \
-       __asm__ __volatile__("rsm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" )
-#define local_irq_restore(x) \
-       __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory" )
-
-#define irqs_disabled()                        \
-({                                     \
-       unsigned long flags;            \
-       local_save_flags(flags);        \
-       (flags & PSW_I) == 0;           \
-})
-
 #define mfctl(reg)     ({              \
        unsigned long cr;               \
        __asm__ __volatile__(           \
index 631e5a0fb6abcf2e124f0dfc6d1ed95d9b9f4566..4b1e521d966f0facaf7d1b70be55ebaf83df3954 100644 (file)
@@ -138,6 +138,7 @@ config PPC
        select HAVE_OPROFILE
        select HAVE_SYSCALL_WRAPPERS if PPC64
        select GENERIC_ATOMIC64 if PPC32
+       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
index b1e5611b2ab1d639edd67346ca50f88d625b9629..349b5530d2c4c31394cdb03080f4491fcbe047ed 100644 (file)
@@ -20,7 +20,7 @@
 #include <string.h>
 
 /* CHRP note section */
-char arch[] = "PowerPC";
+static const char arch[] = "PowerPC";
 
 #define N_DESCR        6
 unsigned int descr[N_DESCR] = {
@@ -33,7 +33,7 @@ unsigned int descr[N_DESCR] = {
 };
 
 /* RPA note section */
-char rpaname[] = "IBM,RPA-Client-Config";
+static const char rpaname[] = "IBM,RPA-Client-Config";
 
 /*
  * Note: setting ignore_my_client_config *should* mean that OF ignores
diff --git a/arch/powerpc/boot/dts/bluestone.dts b/arch/powerpc/boot/dts/bluestone.dts
new file mode 100644 (file)
index 0000000..9bb3d72
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Device Tree for Bluestone (APM821xx) board.
+ *
+ * Copyright (c) 2010, Applied Micro Circuits Corporation
+ * Author: Tirumala R Marri <tmarri@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/dts-v1/;
+
+/ {
+       #address-cells = <2>;
+       #size-cells = <1>;
+       model = "apm,bluestone";
+       compatible = "apm,bluestone";
+       dcr-parent = <&{/cpus/cpu@0}>;
+
+       aliases {
+               ethernet0 = &EMAC0;
+               serial0 = &UART0;
+               serial1 = &UART1;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu@0 {
+                       device_type = "cpu";
+                       model = "PowerPC,apm821xx";
+                       reg = <0x00000000>;
+                       clock-frequency = <0>; /* Filled in by U-Boot */
+                       timebase-frequency = <0>; /* Filled in by U-Boot */
+                       i-cache-line-size = <32>;
+                       d-cache-line-size = <32>;
+                       i-cache-size = <32768>;
+                       d-cache-size = <32768>;
+                       dcr-controller;
+                       dcr-access-method = "native";
+                       next-level-cache = <&L2C0>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by U-Boot */
+       };
+
+       UIC0: interrupt-controller0 {
+               compatible = "ibm,uic";
+               interrupt-controller;
+               cell-index = <0>;
+               dcr-reg = <0x0c0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+       };
+
+       UIC1: interrupt-controller1 {
+               compatible = "ibm,uic";
+               interrupt-controller;
+               cell-index = <1>;
+               dcr-reg = <0x0d0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
+               interrupt-parent = <&UIC0>;
+       };
+
+       UIC2: interrupt-controller2 {
+               compatible = "ibm,uic";
+               interrupt-controller;
+               cell-index = <2>;
+               dcr-reg = <0x0e0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
+               interrupt-parent = <&UIC0>;
+       };
+
+       UIC3: interrupt-controller3 {
+               compatible = "ibm,uic";
+               interrupt-controller;
+               cell-index = <3>;
+               dcr-reg = <0x0f0 0x009>;
+               #address-cells = <0>;
+               #size-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
+               interrupt-parent = <&UIC0>;
+       };
+
+       SDR0: sdr {
+               compatible = "ibm,sdr-apm821xx";
+               dcr-reg = <0x00e 0x002>;
+       };
+
+       CPR0: cpr {
+               compatible = "ibm,cpr-apm821xx";
+               dcr-reg = <0x00c 0x002>;
+       };
+
+       plb {
+               compatible = "ibm,plb4";
+               #address-cells = <2>;
+               #size-cells = <1>;
+               ranges;
+               clock-frequency = <0>; /* Filled in by U-Boot */
+
+               SDRAM0: sdram {
+                       compatible = "ibm,sdram-apm821xx";
+                       dcr-reg = <0x010 0x002>;
+               };
+
+               MAL0: mcmal {
+                       compatible = "ibm,mcmal2";
+                       descriptor-memory = "ocm";
+                       dcr-reg = <0x180 0x062>;
+                       num-tx-chans = <1>;
+                       num-rx-chans = <1>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       interrupt-parent = <&UIC2>;
+                       interrupts = <  /*TXEOB*/ 0x6 0x4
+                                       /*RXEOB*/ 0x7 0x4
+                                       /*SERR*/  0x3 0x4
+                                       /*TXDE*/  0x4 0x4
+                                       /*RXDE*/  0x5 0x4
+               };
+
+               POB0: opb {
+                       compatible = "ibm,opb";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0xb0000000 0x00000004 0xb0000000 0x50000000>;
+                       clock-frequency = <0>; /* Filled in by U-Boot */
+
+                       EBC0: ebc {
+                               compatible = "ibm,ebc";
+                               dcr-reg = <0x012 0x002>;
+                               #address-cells = <2>;
+                               #size-cells = <1>;
+                               clock-frequency = <0>; /* Filled in by U-Boot */
+                               /* ranges property is supplied by U-Boot */
+                               ranges = < 0x00000003 0x00000000 0xe0000000 0x8000000>;
+                               interrupts = <0x6 0x4>;
+                               interrupt-parent = <&UIC1>;
+
+                               nor_flash@0,0 {
+                                       compatible = "amd,s29gl512n", "cfi-flash";
+                                       bank-width = <2>;
+                                       reg = <0x00000000 0x00000000 0x00400000>;
+                                       #address-cells = <1>;
+                                       #size-cells = <1>;
+                                       partition@0 {
+                                               label = "kernel";
+                                               reg = <0x00000000 0x00180000>;
+                                       };
+                                       partition@180000 {
+                                               label = "env";
+                                               reg = <0x00180000 0x00020000>;
+                                       };
+                                       partition@1a0000 {
+                                               label = "u-boot";
+                                               reg = <0x001a0000 0x00060000>;
+                                       };
+                               };
+                       }
+
+                       UART0: serial@ef600300 {
+                               device_type = "serial";
+                               compatible = "ns16550";
+                               reg = <0xef600300 0x00000008>;
+                               virtual-reg = <0xef600300>;
+                               clock-frequency = <0>; /* Filled in by U-Boot */
+                               current-speed = <0>; /* Filled in by U-Boot */
+                               interrupt-parent = <&UIC1>;
+                               interrupts = <0x1 0x4>;
+                       };
+
+                       IIC0: i2c@ef600700 {
+                               compatible = "ibm,iic";
+                               reg = <0xef600700 0x00000014>;
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x2 0x4>;
+                       };
+
+                       IIC1: i2c@ef600800 {
+                               compatible = "ibm,iic";
+                               reg = <0xef600800 0x00000014>;
+                               interrupt-parent = <&UIC0>;
+                               interrupts = <0x3 0x4>;
+                       };
+
+                       RGMII0: emac-rgmii@ef601500 {
+                               compatible = "ibm,rgmii";
+                               reg = <0xef601500 0x00000008>;
+                               has-mdio;
+                       };
+
+                       TAH0: emac-tah@ef601350 {
+                               compatible = "ibm,tah";
+                               reg = <0xef601350 0x00000030>;
+                       };
+
+                       EMAC0: ethernet@ef600c00 {
+                               device_type = "network";
+                               compatible = "ibm,emac4sync";
+                               interrupt-parent = <&EMAC0>;
+                               interrupts = <0x0 0x1>;
+                               #interrupt-cells = <1>;
+                               #address-cells = <0>;
+                               #size-cells = <0>;
+                               interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
+                                                /*Wake*/   0x1 &UIC2 0x14 0x4>;
+                               reg = <0xef600c00 0x000000c4>;
+                               local-mac-address = [000000000000]; /* Filled in by U-Boot */
+                               mal-device = <&MAL0>;
+                               mal-tx-channel = <0>;
+                               mal-rx-channel = <0>;
+                               cell-index = <0>;
+                               max-frame-size = <9000>;
+                               rx-fifo-size = <16384>;
+                               tx-fifo-size = <2048>;
+                               phy-mode = "rgmii";
+                               phy-map = <0x00000000>;
+                               rgmii-device = <&RGMII0>;
+                               rgmii-channel = <0>;
+                               tah-device = <&TAH0>;
+                               tah-channel = <0>;
+                               has-inverted-stacr-oc;
+                               has-new-stacr-staopc;
+                       };
+               };
+
+       };
+};
diff --git a/arch/powerpc/boot/dts/mpc8308_p1m.dts b/arch/powerpc/boot/dts/mpc8308_p1m.dts
new file mode 100644 (file)
index 0000000..05a76cc
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * mpc8308_p1m Device Tree Source
+ *
+ * Copyright 2010 Ilya Yanok, Emcraft Systems, yanok@emcraft.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.
+ */
+
+/dts-v1/;
+
+/ {
+       compatible = "denx,mpc8308_p1m";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       aliases {
+               ethernet0 = &enet0;
+               ethernet1 = &enet1;
+               serial0 = &serial0;
+               serial1 = &serial1;
+               pci0 = &pci0;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,8308@0 {
+                       device_type = "cpu";
+                       reg = <0x0>;
+                       d-cache-line-size = <32>;
+                       i-cache-line-size = <32>;
+                       d-cache-size = <16384>;
+                       i-cache-size = <16384>;
+                       timebase-frequency = <0>;       // from bootloader
+                       bus-frequency = <0>;            // from bootloader
+                       clock-frequency = <0>;          // from bootloader
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x00000000 0x08000000>;  // 128MB at 0
+       };
+
+       localbus@e0005000 {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "fsl,mpc8315-elbc", "fsl,elbc", "simple-bus";
+               reg = <0xe0005000 0x1000>;
+               interrupts = <77 0x8>;
+               interrupt-parent = <&ipic>;
+
+               ranges = <0x0 0x0 0xfc000000 0x04000000
+                         0x1 0x0 0xfbff0000 0x00008000
+                         0x2 0x0 0xfbff8000 0x00008000>;
+
+               flash@0,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "cfi-flash";
+                       reg = <0x0 0x0 0x4000000>;
+                       bank-width = <2>;
+                       device-width = <1>;
+
+                       u-boot@0 {
+                               reg = <0x0 0x60000>;
+                               read-only;
+                       };
+                       env@60000 {
+                               reg = <0x60000 0x20000>;
+                       };
+                       env1@80000 {
+                               reg = <0x80000 0x20000>;
+                       };
+                       kernel@a0000 {
+                               reg = <0xa0000 0x200000>;
+                       };
+                       dtb@2a0000 {
+                               reg = <0x2a0000 0x20000>;
+                       };
+                       ramdisk@2c0000 {
+                               reg = <0x2c0000 0x640000>;
+                       };
+                       user@700000 {
+                               reg = <0x700000 0x3900000>;
+                       };
+               };
+
+               can@1,0 {
+                       compatible = "nxp,sja1000";
+                       reg = <0x1 0x0 0x80>;
+                       interrupts = <18 0x8>;
+                       interrups-parent = <&ipic>;
+               };
+
+               cpld@2,0 {
+                       compatible = "denx,mpc8308_p1m-cpld";
+                       reg = <0x2 0x0 0x8>;
+                       interrupts = <48 0x8>;
+                       interrups-parent = <&ipic>;
+               };
+       };
+
+       immr@e0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               device_type = "soc";
+               compatible = "fsl,mpc8308-immr", "simple-bus";
+               ranges = <0 0xe0000000 0x00100000>;
+               reg = <0xe0000000 0x00000200>;
+               bus-frequency = <0>;
+
+               i2c@3000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3000 0x100>;
+                       interrupts = <14 0x8>;
+                       interrupt-parent = <&ipic>;
+                       dfsrr;
+                       fram@50 {
+                               compatible = "ramtron,24c64";
+                               reg = <0x50>;
+                       };
+               };
+
+               i2c@3100 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl-i2c";
+                       reg = <0x3100 0x100>;
+                       interrupts = <15 0x8>;
+                       interrupt-parent = <&ipic>;
+                       dfsrr;
+                       pwm@28 {
+                               compatible = "maxim,ds1050";
+                               reg = <0x28>;
+                       };
+                       sensor@48 {
+                               compatible = "maxim,max6625";
+                               reg = <0x48>;
+                       };
+                       sensor@49 {
+                               compatible = "maxim,max6625";
+                               reg = <0x49>;
+                       };
+                       sensor@4b {
+                               compatible = "maxim,max6625";
+                               reg = <0x4b>;
+                       };
+               };
+
+               usb@23000 {
+                       compatible = "fsl-usb2-dr";
+                       reg = <0x23000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       interrupt-parent = <&ipic>;
+                       interrupts = <38 0x8>;
+                       dr_mode = "peripheral";
+                       phy_type = "ulpi";
+               };
+
+               enet0: ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges = <0x0 0x24000 0x1000>;
+
+                       cell-index = <0>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x24000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <32 0x8 33 0x8 34 0x8>;
+                       interrupt-parent = <&ipic>;
+                       phy-handle = < &phy1 >;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-mdio";
+                               reg = <0x520 0x20>;
+                               phy1: ethernet-phy@1 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <17 0x8>;
+                                       reg = <0x1>;
+                                       device_type = "ethernet-phy";
+                               };
+                               phy2: ethernet-phy@2 {
+                                       interrupt-parent = <&ipic>;
+                                       interrupts = <19 0x8>;
+                                       reg = <0x2>;
+                                       device_type = "ethernet-phy";
+                               };
+                               tbi0: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
+               };
+
+               enet1: ethernet@25000 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       cell-index = <1>;
+                       device_type = "network";
+                       model = "eTSEC";
+                       compatible = "gianfar";
+                       reg = <0x25000 0x1000>;
+                       ranges = <0x0 0x25000 0x1000>;
+                       local-mac-address = [ 00 00 00 00 00 00 ];
+                       interrupts = <35 0x8 36 0x8 37 0x8>;
+                       interrupt-parent = <&ipic>;
+                       phy-handle = < &phy2 >;
+
+                       mdio@520 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               compatible = "fsl,gianfar-tbi";
+                               reg = <0x520 0x20>;
+                               tbi1: tbi-phy@11 {
+                                       reg = <0x11>;
+                                       device_type = "tbi-phy";
+                               };
+                       };
+               };
+
+               serial0: serial@4500 {
+                       cell-index = <0>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4500 0x100>;
+                       clock-frequency = <133333333>;
+                       interrupts = <9 0x8>;
+                       interrupt-parent = <&ipic>;
+               };
+
+               serial1: serial@4600 {
+                       cell-index = <1>;
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x4600 0x100>;
+                       clock-frequency = <133333333>;
+                       interrupts = <10 0x8>;
+                       interrupt-parent = <&ipic>;
+               };
+
+               gpio@c00 {
+                       #gpio-cells = <2>;
+                       compatible = "fsl,mpc8308-gpio", "fsl,mpc8349-gpio";
+                       reg = <0xc00 0x18>;
+                       interrupts = <74 0x8>;
+                       interrupt-parent = <&ipic>;
+                       gpio-controller;
+               };
+
+               timer@500 {
+                       compatible = "fsl,mpc8308-gtm", "fsl,gtm";
+                       reg = <0x500 0x100>;
+                       interrupts = <90 8 78 8 84 8 72 8>;
+                       interrupt-parent = <&ipic>;
+                       clock-frequency = <133333333>;
+               };
+
+               /* IPIC
+                * interrupts cell = <intr #, sense>
+                * sense values match linux IORESOURCE_IRQ_* defines:
+                * sense == 8: Level, low assertion
+                * sense == 2: Edge, high-to-low change
+                */
+               ipic: interrupt-controller@700 {
+                       compatible = "fsl,ipic";
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       reg = <0x700 0x100>;
+                       device_type = "ipic";
+               };
+
+               ipic-msi@7c0 {
+                       compatible = "fsl,ipic-msi";
+                       reg = <0x7c0 0x40>;
+                       msi-available-ranges = <0x0 0x100>;
+                       interrupts = < 0x43 0x8
+                                       0x4  0x8
+                                       0x51 0x8
+                                       0x52 0x8
+                                       0x56 0x8
+                                       0x57 0x8
+                                       0x58 0x8
+                                       0x59 0x8 >;
+                       interrupt-parent = < &ipic >;
+               };
+
+       };
+
+       pci0: pcie@e0009000 {
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               compatible = "fsl,mpc8308-pcie", "fsl,mpc8314-pcie";
+               reg = <0xe0009000 0x00001000
+                       0xb0000000 0x01000000>;
+               ranges = <0x02000000 0 0xa0000000 0xa0000000 0 0x10000000
+                         0x01000000 0 0x00000000 0xb1000000 0 0x00800000>;
+               bus-range = <0 0>;
+               interrupt-map-mask = <0 0 0 0>;
+               interrupt-map = <0 0 0 0 &ipic 1 8>;
+               interrupts = <0x1 0x8>;
+               interrupt-parent = <&ipic>;
+               clock-frequency = <0>;
+
+               pcie@0 {
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       device_type = "pci";
+                       reg = <0 0 0 0 0>;
+                       ranges = <0x02000000 0 0xa0000000
+                                 0x02000000 0 0xa0000000
+                                 0 0x10000000
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00800000>;
+               };
+       };
+};
index 815cebb2e3e593641feae4101fde07d419641110..a75c10eed2690ba1d9c7084683517c9cd2a418d3 100644 (file)
                        };
                };
 
+               spi@7000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "fsl,mpc8536-espi";
+                       reg = <0x7000 0x1000>;
+                       interrupts = <59 0x2>;
+                       interrupt-parent = <&mpic>;
+                       fsl,espi-num-chipselects = <4>;
+
+                       flash@0 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "spansion,s25sl12801";
+                               reg = <0>;
+                               spi-max-frequency = <40000000>;
+                               partition@u-boot {
+                                       label = "u-boot";
+                                       reg = <0x00000000 0x00100000>;
+                                       read-only;
+                               };
+                               partition@kernel {
+                                       label = "kernel";
+                                       reg = <0x00100000 0x00500000>;
+                                       read-only;
+                               };
+                               partition@dtb {
+                                       label = "dtb";
+                                       reg = <0x00600000 0x00100000>;
+                                       read-only;
+                               };
+                               partition@fs {
+                                       label = "file system";
+                                       reg = <0x00700000 0x00900000>;
+                               };
+                       };
+                       flash@1 {
+                               compatible = "spansion,s25sl12801";
+                               reg = <1>;
+                               spi-max-frequency = <40000000>;
+                       };
+                       flash@2 {
+                               compatible = "spansion,s25sl12801";
+                               reg = <2>;
+                               spi-max-frequency = <40000000>;
+                       };
+                       flash@3 {
+                               compatible = "spansion,s25sl12801";
+                               reg = <3>;
+                               spi-max-frequency = <40000000>;
+                       };
+               };
+
                dma@21300 {
                        #address-cells = <1>;
                        #size-cells = <1>;
index 8bcb10b9267744593b0a95b824f7b205f70030eb..2bbecbb4cbf9a3388749128d751503ce41595aa7 100644 (file)
                                label = "reserved-nand";
                        };
                };
+
+               board-control@3,0 {
+                       compatible = "fsl,p1022ds-pixis";
+                       reg = <3 0 0x30>;
+                       interrupt-parent = <&mpic>;
+                       /*
+                        * IRQ8 is generated if the "EVENT" switch is pressed
+                        * and PX_CTL[EVESEL] is set to 00.
+                        */
+                       interrupts = <8 8>;
+               };
        };
 
        soc@fffe00000 {
index 2f0de24e3822577631169c765f8ac17510144b70..5b7fc29dd6cf6a0aeb81501fc658b7d4e7cd1d04 100644 (file)
                };
 
                spi@110000 {
-                       cell-index = <0>;
                        #address-cells = <1>;
                        #size-cells = <0>;
-                       compatible = "fsl,espi";
+                       compatible = "fsl,p4080-espi", "fsl,mpc8536-espi";
                        reg = <0x110000 0x1000>;
                        interrupts = <53 0x2>;
                        interrupt-parent = <&mpic>;
-                       espi,num-ss-bits = <4>;
-                       mode = "cpu";
+                       fsl,espi-num-chipselects = <4>;
 
-                       fsl_m25p80@0 {
+                       flash@0 {
                                #address-cells = <1>;
                                #size-cells = <1>;
-                               compatible = "fsl,espi-flash";
+                               compatible = "spansion,s25sl12801";
                                reg = <0>;
-                               linux,modalias = "fsl_m25p80";
                                spi-max-frequency = <40000000>; /* input clock */
                                partition@u-boot {
                                        label = "u-boot";
diff --git a/arch/powerpc/configs/44x/bluestone_defconfig b/arch/powerpc/configs/44x/bluestone_defconfig
new file mode 100644 (file)
index 0000000..ac65b48
--- /dev/null
@@ -0,0 +1,68 @@
+CONFIG_44x=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_PCI_QUIRKS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_BLUESTONE=y
+# CONFIG_EBONY is not set
+# CONFIG_KVM_GUEST is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_CONNECTOR=y
+CONFIG_MTD=y
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=35000
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=256
+CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_IBM_IIC=y
+CONFIG_SENSORS_AD7414=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_M41T80=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_CRAMFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NLS=y
diff --git a/arch/powerpc/configs/e55xx_smp_defconfig b/arch/powerpc/configs/e55xx_smp_defconfig
new file mode 100644 (file)
index 0000000..94d120e
--- /dev/null
@@ -0,0 +1,84 @@
+CONFIG_PPC64=y
+CONFIG_PPC_BOOK3E_64=y
+# CONFIG_VIRT_CPU_ACCOUNTING is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_P5020_DS=y
+# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BINFMT_MISC=m
+CONFIG_SPARSE_IRQ=y
+# CONFIG_PCI is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_EEPROM_LEGACY=y
+CONFIG_INPUT_FF_MEMLESS=m
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_I2C=y
+# CONFIG_HWMON is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_DMADEVICES=y
+CONFIG_FSL_DMA=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_MAC_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_UTF8=m
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_LIBCRC32C=m
+CONFIG_FRAME_WARN=1024
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_VIRQ_DEBUG=y
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_TALITOS=y
index cd446fba3faedc2c044575948dd21ea61161ae8c..2fa05f7be4cb9977f273eee5979a24c366353eae 100644 (file)
@@ -12,6 +12,7 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_BLK_DEV_BSG is not set
 CONFIG_BAMBOO=y
+CONFIG_BLUESTONE=y
 CONFIG_SAM440EP=y
 CONFIG_SEQUOIA=y
 CONFIG_TAISHAN=y
@@ -97,14 +98,17 @@ CONFIG_USB_STORAGE=m
 CONFIG_EXT2_FS=y
 CONFIG_EXT3_FS=m
 # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_INOTIFY=y
 CONFIG_VFAT_FS=m
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_JFFS2_FS=y
 CONFIG_UBIFS_FS=m
 CONFIG_UBIFS_FS_XATTR=y
+CONFIG_LOGFS=m
 CONFIG_CRAMFS=y
+CONFIG_SQUASHFS=m
+CONFIG_SQUASHFS_XATTR=y
+CONFIG_SQUASHFS_LZO=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_ROOT_NFS=y
@@ -116,11 +120,8 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_HUNG_TASK=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_CRYPTO_CBC=y
 CONFIG_CRYPTO_ECB=y
 CONFIG_CRYPTO_PCBC=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_DES=y
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 # CONFIG_CRYPTO_HW is not set
 CONFIG_VIRTUALIZATION=y
index 04ae0740b6d0fde0147861746e262825e5903d4f..7bd1763877babeb272b7e3b6a962330de7f6d91e 100644 (file)
@@ -18,6 +18,7 @@ CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_P5020_DS=y
 CONFIG_CPU_FREQ=y
 CONFIG_CPU_FREQ_GOV_POWERSAVE=y
 CONFIG_CPU_FREQ_GOV_USERSPACE=y
@@ -256,7 +257,6 @@ CONFIG_HID_ZEROPLUS=y
 CONFIG_USB=y
 CONFIG_USB_DEVICEFS=y
 CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_TT_NEWSCHED=y
 # CONFIG_USB_EHCI_HCD_PPC_OF is not set
 CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_STORAGE=m
@@ -290,7 +290,6 @@ CONFIG_JFS_POSIX_ACL=y
 CONFIG_JFS_SECURITY=y
 CONFIG_XFS_FS=m
 CONFIG_XFS_POSIX_ACL=y
-CONFIG_INOTIFY=y
 CONFIG_AUTOFS4_FS=m
 CONFIG_ISO9660_FS=y
 CONFIG_UDF_FS=m
@@ -384,7 +383,6 @@ CONFIG_CRYPTO_TGR192=m
 CONFIG_CRYPTO_WP512=m
 CONFIG_CRYPTO_AES=m
 CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_ARC4=m
 CONFIG_CRYPTO_BLOWFISH=m
 CONFIG_CRYPTO_CAST6=m
 CONFIG_CRYPTO_KHAZAD=m
index 7cdf358337cf246c21634650af8495086750361a..ce0c28495f9a0416450a33a4ceee4b3a33be45c2 100644 (file)
@@ -52,12 +52,22 @@ extern __wsum csum_partial(const void *buff, int len, __wsum sum);
 extern __wsum csum_partial_copy_generic(const void *src, void *dst,
                                              int len, __wsum sum,
                                              int *src_err, int *dst_err);
+
+#ifdef __powerpc64__
+#define _HAVE_ARCH_COPY_AND_CSUM_FROM_USER
+extern __wsum csum_and_copy_from_user(const void __user *src, void *dst,
+                                     int len, __wsum sum, int *err_ptr);
+#define HAVE_CSUM_COPY_USER
+extern __wsum csum_and_copy_to_user(const void *src, void __user *dst,
+                                   int len, __wsum sum, int *err_ptr);
+#else
 /*
  * the same as csum_partial, but copies from src to dst while it
  * checksums.
  */
 #define csum_partial_copy_from_user(src, dst, len, sum, errp)   \
         csum_partial_copy_generic((__force const void *)(src), (dst), (len), (sum), (errp), NULL)
+#endif
 
 #define csum_partial_copy_nocheck(src, dst, len, sum)   \
         csum_partial_copy_generic((src), (dst), (len), (sum), NULL, NULL)
index a11d4eac4f97f369f48866a7475696879b8be5d3..2296112e247befe8050526420f6fa8db2a42d693 100644 (file)
@@ -143,7 +143,7 @@ static inline void __user *arch_compat_alloc_user_space(long len)
         * We cant access below the stack pointer in the 32bit ABI and
         * can access 288 bytes in the 64bit ABI
         */
-       if (!(test_thread_flag(TIF_32BIT)))
+       if (!is_32bit_task())
                usp -= 288;
 
        return (void __user *) (usp - len);
@@ -213,7 +213,7 @@ struct compat_shmid64_ds {
 
 static inline int is_compat_task(void)
 {
-       return test_thread_flag(TIF_32BIT);
+       return is_32bit_task();
 }
 
 #endif /* __KERNEL__ */
index 3a40a992e5941ea73628aca26f12a30cd0d387d0..f3a1fdd9cf08b67ede4102dab01b8a353c3c826f 100644 (file)
@@ -198,6 +198,7 @@ extern const char *powerpc_base_platform;
 #define CPU_FTR_CP_USE_DCBTZ           LONG_ASM_CONST(0x0040000000000000)
 #define CPU_FTR_UNALIGNED_LD_STD       LONG_ASM_CONST(0x0080000000000000)
 #define CPU_FTR_ASYM_SMT               LONG_ASM_CONST(0x0100000000000000)
+#define CPU_FTR_STCX_CHECKS_ADDRESS    LONG_ASM_CONST(0x0200000000000000)
 
 #ifndef __ASSEMBLY__
 
@@ -392,28 +393,31 @@ extern const char *powerpc_base_platform;
            CPU_FTR_MMCRA | CPU_FTR_CTRL)
 #define CPU_FTRS_POWER4        (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
-           CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ)
+           CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ | \
+           CPU_FTR_STCX_CHECKS_ADDRESS)
 #define CPU_FTRS_PPC970        (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA | \
-           CPU_FTR_CP_USE_DCBTZ)
+           CPU_FTR_CP_USE_DCBTZ | CPU_FTR_STCX_CHECKS_ADDRESS)
 #define CPU_FTRS_POWER5        (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_MMCRA | CPU_FTR_SMT | \
            CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
-           CPU_FTR_PURR)
+           CPU_FTR_PURR | CPU_FTR_STCX_CHECKS_ADDRESS)
 #define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_MMCRA | CPU_FTR_SMT | \
            CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
            CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
-           CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD)
+           CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD | \
+           CPU_FTR_STCX_CHECKS_ADDRESS)
 #define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_MMCRA | CPU_FTR_SMT | \
            CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
            CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
-           CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT)
+           CPU_FTR_DSCR | CPU_FTR_SAO  | CPU_FTR_ASYM_SMT | \
+           CPU_FTR_STCX_CHECKS_ADDRESS)
 #define CPU_FTRS_CELL  (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
            CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
            CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
index 8c9c6ad2004ea1f47ce3e5009da4bf9245131327..6d2416a857096be9548964987af7f701a5fe15c2 100644 (file)
@@ -127,19 +127,7 @@ static inline int dma_supported(struct device *dev, u64 mask)
        return dma_ops->dma_supported(dev, mask);
 }
 
-static inline int dma_set_mask(struct device *dev, u64 dma_mask)
-{
-       struct dma_map_ops *dma_ops = get_dma_ops(dev);
-
-       if (unlikely(dma_ops == NULL))
-               return -EIO;
-       if (dma_ops->set_dma_mask != NULL)
-               return dma_ops->set_dma_mask(dev, dma_mask);
-       if (!dev->dma_mask || !dma_supported(dev, dma_mask))
-               return -EIO;
-       *dev->dma_mask = dma_mask;
-       return 0;
-}
+extern int dma_set_mask(struct device *dev, u64 dma_mask);
 
 static inline void *dma_alloc_coherent(struct device *dev, size_t size,
                                       dma_addr_t *dma_handle, gfp_t flag)
index c376eda153139673bc879e8b5489470db7a00e99..2b917c69ed15683bc4d761a5c5b6a5d7304718af 100644 (file)
@@ -250,7 +250,7 @@ do {                                                                \
  * the 64bit ABI has never had these issues dont enable the workaround
  * even if we have an executable stack.
  */
-# define elf_read_implies_exec(ex, exec_stk) (test_thread_flag(TIF_32BIT) ? \
+# define elf_read_implies_exec(ex, exec_stk) (is_32bit_task() ? \
                (exec_stk == EXSTACK_DEFAULT) : 0)
 #else 
 # define SET_PERSONALITY(ex) \
index 57c4000719959cd4409d109f13d5cb723e70e95c..7778d6f0c878a614a4bda84c52f2a77d02012a07 100644 (file)
        li      r10,0;                                                     \
        ld      r11,exception_marker@toc(r2);                              \
        std     r10,RESULT(r1);         /* clear regs->result           */ \
-       std     r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame      */
+       std     r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame      */ \
+       ACCOUNT_STOLEN_TIME
 
 /*
  * Exception vectors.
diff --git a/arch/powerpc/include/asm/fsl_85xx_cache_sram.h b/arch/powerpc/include/asm/fsl_85xx_cache_sram.h
new file mode 100644 (file)
index 0000000..2af2bdc
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 Freescale Semiconductor, Inc.
+ *
+ * Cache SRAM handling for QorIQ platform
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+
+ * This file is derived from the original work done
+ * by Sylvain Munaut for the Bestcomm SRAM allocator.
+ *
+ * This program is free software; you can redistribute  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 __ASM_POWERPC_FSL_85XX_CACHE_SRAM_H__
+#define __ASM_POWERPC_FSL_85XX_CACHE_SRAM_H__
+
+#include <asm/rheap.h>
+#include <linux/spinlock.h>
+
+/*
+ * Cache-SRAM
+ */
+
+struct mpc85xx_cache_sram {
+       phys_addr_t base_phys;
+       void *base_virt;
+       unsigned int size;
+       rh_info_t *rh;
+       spinlock_t lock;
+};
+
+extern void mpc85xx_cache_sram_free(void *ptr);
+extern void *mpc85xx_cache_sram_alloc(unsigned int size,
+                                 phys_addr_t *phys, unsigned int align);
+
+#endif /* __AMS_POWERPC_FSL_85XX_CACHE_SRAM_H__ */
index bd100fcf40d0c1263e81e5d737e2ec6cfc32b025..ff08b70b36d4befb36139fadbe0cec54829096e8 100644 (file)
@@ -16,42 +16,57 @@ extern void timer_interrupt(struct pt_regs *);
 #ifdef CONFIG_PPC64
 #include <asm/paca.h>
 
-static inline unsigned long local_get_flags(void)
+static inline unsigned long arch_local_save_flags(void)
 {
        unsigned long flags;
 
-       __asm__ __volatile__("lbz %0,%1(13)"
-       : "=r" (flags)
-       : "i" (offsetof(struct paca_struct, soft_enabled)));
+       asm volatile(
+               "lbz %0,%1(13)"
+               : "=r" (flags)
+               : "i" (offsetof(struct paca_struct, soft_enabled)));
 
        return flags;
 }
 
-static inline unsigned long raw_local_irq_disable(void)
+static inline unsigned long arch_local_irq_disable(void)
 {
        unsigned long flags, zero;
 
-       __asm__ __volatile__("li %1,0; lbz %0,%2(13); stb %1,%2(13)"
-       : "=r" (flags), "=&r" (zero)
-       : "i" (offsetof(struct paca_struct, soft_enabled))
-       : "memory");
+       asm volatile(
+               "li %1,0; lbz %0,%2(13); stb %1,%2(13)"
+               : "=r" (flags), "=&r" (zero)
+               : "i" (offsetof(struct paca_struct, soft_enabled))
+               : "memory");
 
        return flags;
 }
 
-extern void raw_local_irq_restore(unsigned long);
+extern void arch_local_irq_restore(unsigned long);
 extern void iseries_handle_interrupts(void);
 
-#define raw_local_irq_enable()         raw_local_irq_restore(1)
-#define raw_local_save_flags(flags)    ((flags) = local_get_flags())
-#define raw_local_irq_save(flags)      ((flags) = raw_local_irq_disable())
+static inline void arch_local_irq_enable(void)
+{
+       arch_local_irq_restore(1);
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       return arch_local_irq_disable();
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return flags == 0;
+}
 
-#define raw_irqs_disabled()            (local_get_flags() == 0)
-#define raw_irqs_disabled_flags(flags) ((flags) == 0)
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
 
 #ifdef CONFIG_PPC_BOOK3E
-#define __hard_irq_enable()    __asm__ __volatile__("wrteei 1": : :"memory");
-#define __hard_irq_disable()   __asm__ __volatile__("wrteei 0": : :"memory");
+#define __hard_irq_enable()    asm volatile("wrteei 1" : : : "memory");
+#define __hard_irq_disable()   asm volatile("wrteei 0" : : : "memory");
 #else
 #define __hard_irq_enable()    __mtmsrd(mfmsr() | MSR_EE, 1)
 #define __hard_irq_disable()   __mtmsrd(mfmsr() & ~MSR_EE, 1)
@@ -64,64 +79,66 @@ extern void iseries_handle_interrupts(void);
                get_paca()->hard_enabled = 0;   \
        } while(0)
 
-#else
+#else /* CONFIG_PPC64 */
 
-#if defined(CONFIG_BOOKE)
 #define SET_MSR_EE(x)  mtmsr(x)
-#define raw_local_irq_restore(flags)   __asm__ __volatile__("wrtee %0" : : "r" (flags) : "memory")
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       return mfmsr();
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+#if defined(CONFIG_BOOKE)
+       asm volatile("wrtee %0" : : "r" (flags) : "memory");
 #else
-#define SET_MSR_EE(x)  mtmsr(x)
-#define raw_local_irq_restore(flags)   mtmsr(flags)
+       mtmsr(flags);
 #endif
+}
 
-static inline void raw_local_irq_disable(void)
+static inline unsigned long arch_local_irq_save(void)
 {
+       unsigned long flags = arch_local_save_flags();
 #ifdef CONFIG_BOOKE
-       __asm__ __volatile__("wrteei 0": : :"memory");
+       asm volatile("wrteei 0" : : : "memory");
 #else
-       unsigned long msr;
-
-       msr = mfmsr();
-       SET_MSR_EE(msr & ~MSR_EE);
+       SET_MSR_EE(flags & ~MSR_EE);
 #endif
+       return flags;
 }
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_disable(void)
 {
 #ifdef CONFIG_BOOKE
-       __asm__ __volatile__("wrteei 1": : :"memory");
+       asm volatile("wrteei 0" : : : "memory");
 #else
-       unsigned long msr;
-
-       msr = mfmsr();
-       SET_MSR_EE(msr | MSR_EE);
+       arch_local_irq_save();
 #endif
 }
 
-static inline void raw_local_irq_save_ptr(unsigned long *flags)
+static inline void arch_local_irq_enable(void)
 {
-       unsigned long msr;
-       msr = mfmsr();
-       *flags = msr;
 #ifdef CONFIG_BOOKE
-       __asm__ __volatile__("wrteei 0": : :"memory");
+       asm volatile("wrteei 1" : : : "memory");
 #else
-       SET_MSR_EE(msr & ~MSR_EE);
+       unsigned long msr = mfmsr();
+       SET_MSR_EE(msr | MSR_EE);
 #endif
 }
 
-#define raw_local_save_flags(flags)    ((flags) = mfmsr())
-#define raw_local_irq_save(flags)      raw_local_irq_save_ptr(&flags)
-#define raw_irqs_disabled()            ((mfmsr() & MSR_EE) == 0)
-#define raw_irqs_disabled_flags(flags) (((flags) & MSR_EE) == 0)
-
-#define hard_irq_disable()             raw_local_irq_disable()
-
-static inline int irqs_disabled_flags(unsigned long flags)
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
        return (flags & MSR_EE) == 0;
 }
 
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#define hard_irq_disable()             arch_local_irq_disable()
+
 #endif /* CONFIG_PPC64 */
 
 /*
index 5f68ecfdf516bf85d2094396363849647dae9ebd..b85d8ddbb6668b77aed280e750e971c9619f5df0 100644 (file)
@@ -6,7 +6,7 @@
 
 #ifndef __ASSEMBLY__
 /*
- * Get definitions for raw_local_save_flags(x), etc.
+ * Get definitions for arch_local_save_flags(x), etc.
  */
 #include <asm/hw_irq.h>
 
index 076327f2eff777b2cdbd4e15de8336ce7b03faa6..f54408d995b5b9df718f818f4fdf16d37c796517 100644 (file)
@@ -91,6 +91,7 @@ extern void machine_kexec_simple(struct kimage *image);
 extern void crash_kexec_secondary(struct pt_regs *regs);
 extern int overlaps_crashkernel(unsigned long start, unsigned long size);
 extern void reserve_crashkernel(void);
+extern void machine_kexec_mask_interrupts(void);
 
 #else /* !CONFIG_KEXEC */
 static inline int kexec_sr_activated(int cpu) { return 0; }
index c3d4f0518a67c2f89b4c42e3d1b81e20dea0c059..92daae13249245e31783b31756b3b88608f9cf68 100644 (file)
@@ -82,7 +82,7 @@ FPD_THREE_IN(fmadd)
 FPD_THREE_IN(fnmsub)
 FPD_THREE_IN(fnmadd)
 
-extern void kvm_cvt_fd(u32 *from, u64 *to, u64 *fpscr);
-extern void kvm_cvt_df(u64 *from, u32 *to, u64 *fpscr);
+extern void kvm_cvt_fd(u32 *from, u64 *to);
+extern void kvm_cvt_df(u64 *from, u32 *to);
 
 #endif
index 14b592dfb4e824f691a71c248e2f60c6827dcf0e..7f5e0fefebb0f14d5a8456ef8098a16107f70208 100644 (file)
@@ -153,6 +153,8 @@ struct lppaca {
 
 extern struct lppaca lppaca[];
 
+#define lppaca_of(cpu) (*paca[cpu].lppaca_ptr)
+
 /*
  * SLB shadow buffer structure as defined in the PAPR.  The save_area
  * contains adjacent ESID and VSID pairs for each shadowed SLB.  The
@@ -170,6 +172,33 @@ struct slb_shadow {
 
 extern struct slb_shadow slb_shadow[];
 
+/*
+ * Layout of entries in the hypervisor's dispatch trace log buffer.
+ */
+struct dtl_entry {
+       u8      dispatch_reason;
+       u8      preempt_reason;
+       u16     processor_id;
+       u32     enqueue_to_dispatch_time;
+       u32     ready_to_enqueue_time;
+       u32     waiting_to_ready_time;
+       u64     timebase;
+       u64     fault_addr;
+       u64     srr0;
+       u64     srr1;
+};
+
+#define DISPATCH_LOG_BYTES     4096    /* bytes per cpu */
+#define N_DISPATCH_LOG         (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry))
+
+/*
+ * When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls
+ * reading from the dispatch trace log.  If other code wants to consume
+ * DTL entries, it can set this pointer to a function that will get
+ * called once for each DTL entry that gets processed.
+ */
+extern void (*dtl_consumer)(struct dtl_entry *entry, u64 index);
+
 #endif /* CONFIG_PPC_BOOK3S */
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_LPPACA_H */
index adc8e6cdf33914bef9fd07fc69f60ab9730959ea..d045b0145537d47c5201c891f47079b93d4d8681 100644 (file)
@@ -102,6 +102,9 @@ struct machdep_calls {
        void            (*pci_dma_dev_setup)(struct pci_dev *dev);
        void            (*pci_dma_bus_setup)(struct pci_bus *bus);
 
+       /* Platform set_dma_mask override */
+       int             (*dma_set_mask)(struct device *dev, u64 dma_mask);
+
        int             (*probe)(void);
        void            (*setup_arch)(void); /* Optional, may be NULL */
        void            (*init_early)(void);
index 3c29728b56b1df4ef2fc6b2c5396717af6daa2a8..43efc345065e968246fc07638503e7fb5ba8911f 100644 (file)
@@ -5,11 +5,4 @@
 
 #define MEMBLOCK_DBG(fmt...) udbg_printf(fmt)
 
-#ifdef CONFIG_PPC32
-extern phys_addr_t lowmem_end_addr;
-#define MEMBLOCK_REAL_LIMIT    lowmem_end_addr
-#else
-#define MEMBLOCK_REAL_LIMIT    0
-#endif
-
 #endif /* _ASM_POWERPC_MEMBLOCK_H */
index 87a1d787c5b626cf3747eb915be383f605b11179..8eaed81ea642663d7aae026ae899a667022302b1 100644 (file)
 
 #define MAS7_RPN               0xFFFFFFFF
 
+/* Bit definitions for MMUCFG */
+#define MMUCFG_MAVN    0x00000003      /* MMU Architecture Version Number */
+#define MMUCFG_MAVN_V1 0x00000000      /* v1.0 */
+#define MMUCFG_MAVN_V2 0x00000001      /* v2.0 */
+#define MMUCFG_NTLBS   0x0000000c      /* Number of TLBs */
+#define MMUCFG_PIDSIZE 0x000007c0      /* PID Reg Size */
+#define MMUCFG_TWC     0x00008000      /* TLB Write Conditional (v2.0) */
+#define MMUCFG_LRAT    0x00010000      /* LRAT Supported (v2.0) */
+#define MMUCFG_RASIZE  0x00fe0000      /* Real Addr Size */
+#define MMUCFG_LPIDSIZE        0x0f000000      /* LPID Reg Size */
+
 /* Bit definitions for MMUCSR0 */
 #define MMUCSR0_TLB1FI 0x00000002      /* TLB1 Flash invalidate */
 #define MMUCSR0_TLB0FI 0x00000004      /* TLB0 Flash invalidate */
 #define TLBnCFG_GTWE           0x00010000      /* Guest can write */
 #define TLBnCFG_IND            0x00020000      /* IND entries supported */
 #define TLBnCFG_PT             0x00040000      /* Can load from page table */
+#define TLBnCFG_MINSIZE                0x00f00000      /* Minimum Page Size (v1.0) */
+#define TLBnCFG_MINSIZE_SHIFT  20
+#define TLBnCFG_MAXSIZE                0x000f0000      /* Maximum Page Size (v1.0) */
+#define TLBnCFG_MAXSIZE_SHIFT  16
 #define TLBnCFG_ASSOC          0xff000000      /* Associativity */
 
 /* TLBnPS encoding */
index 7ebf42ed84a2aef049946757b2a4c6afe81501c7..bb40a06d3b7701d418b750a24b16a22385570bba 100644 (file)
@@ -2,6 +2,8 @@
 #define _ASM_POWERPC_MMU_H_
 #ifdef __KERNEL__
 
+#include <linux/types.h>
+
 #include <asm/asm-compat.h>
 #include <asm/feature-fixups.h>
 
@@ -82,6 +84,16 @@ extern unsigned int __start___mmu_ftr_fixup, __stop___mmu_ftr_fixup;
 extern void early_init_mmu(void);
 extern void early_init_mmu_secondary(void);
 
+extern void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+                                      phys_addr_t first_memblock_size);
+
+#ifdef CONFIG_PPC64
+/* This is our real memory area size on ppc64 server, on embedded, we
+ * make it match the size our of bolted TLB area
+ */
+extern u64 ppc64_rma_size;
+#endif /* CONFIG_PPC64 */
+
 #endif /* !__ASSEMBLY__ */
 
 /* The kernel use the constants below to index in the page sizes array.
index 1ff6662f7faf28ffce6577ac40f0a237f2b866e8..ec57540cd7af639b6d111f01bc2ae1f8d98c1a46 100644 (file)
@@ -85,6 +85,8 @@ struct paca_struct {
        u8 kexec_state;         /* set when kexec down has irqs off */
 #ifdef CONFIG_PPC_STD_MMU_64
        struct slb_shadow *slb_shadow_ptr;
+       struct dtl_entry *dispatch_log;
+       struct dtl_entry *dispatch_log_end;
 
        /*
         * Now, starting in cacheline 2, the exception save areas
@@ -129,13 +131,19 @@ struct paca_struct {
        u8 soft_enabled;                /* irq soft-enable flag */
        u8 hard_enabled;                /* set if irqs are enabled in MSR */
        u8 io_sync;                     /* writel() needs spin_unlock sync */
-       u8 perf_event_pending;          /* PM interrupt while soft-disabled */
+       u8 irq_work_pending;            /* IRQ_WORK interrupt while soft-disable */
 
        /* Stuff for accurate time accounting */
        u64 user_time;                  /* accumulated usermode TB ticks */
        u64 system_time;                /* accumulated system TB ticks */
-       u64 startpurr;                  /* PURR/TB value snapshot */
+       u64 user_time_scaled;           /* accumulated usermode SPURR ticks */
+       u64 starttime;                  /* TB value snapshot */
+       u64 starttime_user;             /* TB value on exit to usermode */
        u64 startspurr;                 /* SPURR value snapshot */
+       u64 utime_sspurr;               /* ->user_time when ->startspurr set */
+       u64 stolen_time;                /* TB ticks taken by hypervisor */
+       u64 dtl_ridx;                   /* read index in dispatch log */
+       struct dtl_entry *dtl_curr;     /* pointer corresponding to dtl_ridx */
 
 #ifdef CONFIG_KVM_BOOK3S_HANDLER
        /* We use this to store guest state in */
index 358ff14ea25ed2d917f442576dba3ac841a1f9b5..932f88dcf6fa175616ca5dae4f3315e684120dbe 100644 (file)
@@ -163,7 +163,7 @@ do {                                                \
 #endif /* !CONFIG_HUGETLB_PAGE */
 
 #define VM_DATA_DEFAULT_FLAGS \
-       (test_thread_flag(TIF_32BIT) ? \
+       (is_32bit_task() ? \
         VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64)
 
 /*
@@ -179,7 +179,7 @@ do {                                                \
                                         VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
 #define VM_STACK_DEFAULT_FLAGS \
-       (test_thread_flag(TIF_32BIT) ? \
+       (is_32bit_task() ? \
         VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64)
 
 #include <asm-generic/getorder.h>
index 42fdff0e4b329a266b6398893fda81bd80de0b8d..43268f15004e8082148cc1a57de8766fdad75c7d 100644 (file)
@@ -28,8 +28,8 @@ extern void find_and_init_phbs(void);
 extern struct pci_dev *isa_bridge_pcidev;      /* may be NULL if no ISA bus */
 
 /** Bus Unit ID macros; get low and hi 32-bits of the 64-bit BUID */
-#define BUID_HI(buid) ((buid) >> 32)
-#define BUID_LO(buid) ((buid) & 0xffffffff)
+#define BUID_HI(buid) upper_32_bits(buid)
+#define BUID_LO(buid) lower_32_bits(buid)
 
 /* PCI device_node operations */
 struct device_node;
index 498fe09263d3e7df23ca37b848996339ff50b23c..98210067c1ccbac17f449946a4a5b42023cea1f2 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/asm-compat.h>
 #include <asm/processor.h>
 #include <asm/ppc-opcode.h>
+#include <asm/firmware.h>
 
 #ifndef __ASSEMBLY__
 #error __FILE__ should only be used in assembler files
 #ifndef CONFIG_VIRT_CPU_ACCOUNTING
 #define ACCOUNT_CPU_USER_ENTRY(ra, rb)
 #define ACCOUNT_CPU_USER_EXIT(ra, rb)
+#define ACCOUNT_STOLEN_TIME
 #else
 #define ACCOUNT_CPU_USER_ENTRY(ra, rb)                                 \
        beq     2f;                     /* if from kernel mode */       \
-BEGIN_FTR_SECTION;                                                     \
-       mfspr   ra,SPRN_PURR;           /* get processor util. reg */   \
-END_FTR_SECTION_IFSET(CPU_FTR_PURR);                                   \
-BEGIN_FTR_SECTION;                                                     \
-       MFTB(ra);                       /* or get TB if no PURR */      \
-END_FTR_SECTION_IFCLR(CPU_FTR_PURR);                                   \
-       ld      rb,PACA_STARTPURR(r13);                                 \
-       std     ra,PACA_STARTPURR(r13);                                 \
+       MFTB(ra);                       /* get timebase */              \
+       ld      rb,PACA_STARTTIME_USER(r13);                            \
+       std     ra,PACA_STARTTIME(r13);                                 \
        subf    rb,rb,ra;               /* subtract start value */      \
        ld      ra,PACA_USER_TIME(r13);                                 \
        add     ra,ra,rb;               /* add on to user time */       \
@@ -44,19 +41,34 @@ END_FTR_SECTION_IFCLR(CPU_FTR_PURR);                                        \
 2:
 
 #define ACCOUNT_CPU_USER_EXIT(ra, rb)                                  \
-BEGIN_FTR_SECTION;                                                     \
-       mfspr   ra,SPRN_PURR;           /* get processor util. reg */   \
-END_FTR_SECTION_IFSET(CPU_FTR_PURR);                                   \
-BEGIN_FTR_SECTION;                                                     \
-       MFTB(ra);                       /* or get TB if no PURR */      \
-END_FTR_SECTION_IFCLR(CPU_FTR_PURR);                                   \
-       ld      rb,PACA_STARTPURR(r13);                                 \
-       std     ra,PACA_STARTPURR(r13);                                 \
+       MFTB(ra);                       /* get timebase */              \
+       ld      rb,PACA_STARTTIME(r13);                                 \
+       std     ra,PACA_STARTTIME_USER(r13);                            \
        subf    rb,rb,ra;               /* subtract start value */      \
        ld      ra,PACA_SYSTEM_TIME(r13);                               \
-       add     ra,ra,rb;               /* add on to user time */       \
-       std     ra,PACA_SYSTEM_TIME(r13);
-#endif
+       add     ra,ra,rb;               /* add on to system time */     \
+       std     ra,PACA_SYSTEM_TIME(r13)
+
+#ifdef CONFIG_PPC_SPLPAR
+#define ACCOUNT_STOLEN_TIME                                            \
+BEGIN_FW_FTR_SECTION;                                                  \
+       beq     33f;                                                    \
+       /* from user - see if there are any DTL entries to process */   \
+       ld      r10,PACALPPACAPTR(r13); /* get ptr to VPA */            \
+       ld      r11,PACA_DTL_RIDX(r13); /* get log read index */        \
+       ld      r10,LPPACA_DTLIDX(r10); /* get log write index */       \
+       cmpd    cr1,r11,r10;                                            \
+       beq+    cr1,33f;                                                \
+       bl      .accumulate_stolen_time;                                \
+33:                                                                    \
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
+
+#else  /* CONFIG_PPC_SPLPAR */
+#define ACCOUNT_STOLEN_TIME
+
+#endif /* CONFIG_PPC_SPLPAR */
+
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
 
 /*
  * Macros for storing registers into and loading registers from
index 19c05b0f74bedb30ea4beddaba9ff005b3d6f2e1..4c14187ba02d24ab65c361023bedf93fff24a30f 100644 (file)
@@ -118,7 +118,7 @@ extern struct task_struct *last_task_used_spe;
 #define TASK_UNMAPPED_BASE_USER32 (PAGE_ALIGN(TASK_SIZE_USER32 / 4))
 #define TASK_UNMAPPED_BASE_USER64 (PAGE_ALIGN(TASK_SIZE_USER64 / 4))
 
-#define TASK_UNMAPPED_BASE ((test_thread_flag(TIF_32BIT)) ? \
+#define TASK_UNMAPPED_BASE ((is_32bit_task()) ? \
                TASK_UNMAPPED_BASE_USER32 : TASK_UNMAPPED_BASE_USER64 )
 #endif
 
@@ -128,7 +128,7 @@ extern struct task_struct *last_task_used_spe;
 #define STACK_TOP_USER64 TASK_SIZE_USER64
 #define STACK_TOP_USER32 TASK_SIZE_USER32
 
-#define STACK_TOP (test_thread_flag(TIF_32BIT) ? \
+#define STACK_TOP (is_32bit_task() ? \
                   STACK_TOP_USER32 : STACK_TOP_USER64)
 
 #define STACK_TOP_MAX STACK_TOP_USER64
index f2b370180a09772546e2f9fccef588d53660ff88..76bb195e4f24d0e89db09665297dd68ec83ccb37 100644 (file)
@@ -171,6 +171,13 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
 /* Make modules code happy. We don't set RO yet */
 #define PAGE_KERNEL_EXEC       PAGE_KERNEL_X
 
+/*
+ * Don't just check for any non zero bits in __PAGE_USER, since for book3e
+ * and PTE_64BIT, PAGE_KERNEL_X contains _PAGE_BAP_SR which is also in
+ * _PAGE_USER.  Need to explictly match _PAGE_BAP_UR bit in that case too.
+ */
+#define pte_user(val)          ((val & _PAGE_USER) == _PAGE_USER)
+
 /* Advertise special mapping type for AGP */
 #define PAGE_AGP               (PAGE_KERNEL_NC)
 #define HAVE_PAGE_AGP
index 3d35f8ae377e1b446cc8db98c0ee971f218f24cc..9a1193e30f26ce0e6545cf67c440336723ac7185 100644 (file)
@@ -187,6 +187,7 @@ extern void rtas_progress(char *s, unsigned short hex);
 extern void rtas_initialize(void);
 extern int rtas_suspend_cpu(struct rtas_suspend_me_data *data);
 extern int rtas_suspend_last_cpu(struct rtas_suspend_me_data *data);
+extern int rtas_ibm_suspend_me(struct rtas_args *);
 
 struct rtc_time;
 extern unsigned long rtas_get_boot_time(void);
index 3d212669a130a5621d1006694c75785f08c87d9d..aa0f1ebb4aaf0e85a22124b42987ec335cc57d1c 100644 (file)
@@ -329,3 +329,22 @@ COMPAT_SYS(rt_tgsigqueueinfo)
 SYSCALL(fanotify_init)
 COMPAT_SYS(fanotify_mark)
 SYSCALL_SPU(prlimit64)
+SYSCALL_SPU(socket)
+SYSCALL_SPU(bind)
+SYSCALL_SPU(connect)
+SYSCALL_SPU(listen)
+SYSCALL_SPU(accept)
+SYSCALL_SPU(getsockname)
+SYSCALL_SPU(getpeername)
+SYSCALL_SPU(socketpair)
+SYSCALL_SPU(send)
+SYSCALL_SPU(sendto)
+COMPAT_SYS_SPU(recv)
+COMPAT_SYS_SPU(recvfrom)
+SYSCALL_SPU(shutdown)
+COMPAT_SYS_SPU(setsockopt)
+COMPAT_SYS_SPU(getsockopt)
+COMPAT_SYS_SPU(sendmsg)
+COMPAT_SYS_SPU(recvmsg)
+COMPAT_SYS_SPU(recvmmsg)
+SYSCALL_SPU(accept4)
index 6c294acac848145d868d9f936c5df5ca879b1920..5e474ddd227382350fc82ae0e2ca80352d1fd070 100644 (file)
@@ -154,8 +154,8 @@ extern void enable_kernel_spe(void);
 extern void giveup_spe(struct task_struct *);
 extern void load_up_spe(struct task_struct *);
 extern int fix_alignment(struct pt_regs *);
-extern void cvt_fd(float *from, double *to, struct thread_struct *thread);
-extern void cvt_df(double *from, float *to, struct thread_struct *thread);
+extern void cvt_fd(float *from, double *to);
+extern void cvt_df(double *from, float *to);
 
 #ifndef CONFIG_SMP
 extern void discard_lazy_cpu_state(void);
@@ -542,10 +542,6 @@ extern void reloc_got2(unsigned long);
 
 #define PTRRELOC(x)    ((typeof(x)) add_reloc_offset((unsigned long)(x)))
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
-extern void account_system_vtime(struct task_struct *);
-#endif
-
 extern struct dentry *powerpc_debugfs_root;
 
 #endif /* __KERNEL__ */
index dc779dfcf25813a4502bf767e6bd6cd2f6c3a5bb..fe6f7c2c9c6889600bd0ec00fab55ed6b7daf1f6 100644 (file)
@@ -34,7 +34,6 @@ extern void to_tm(int tim, struct rtc_time * tm);
 extern void GregorianDay(struct rtc_time *tm);
 
 extern void generic_calibrate_decr(void);
-extern void snapshot_timebase(void);
 
 extern void set_dec_cpu6(unsigned int val);
 
@@ -212,12 +211,8 @@ struct cpu_usage {
 DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);
 
 #if defined(CONFIG_VIRT_CPU_ACCOUNTING)
-extern void calculate_steal_time(void);
-extern void snapshot_timebases(void);
 #define account_process_vtime(tsk)             account_process_tick(tsk, 0)
 #else
-#define calculate_steal_time()                 do { } while (0)
-#define snapshot_timebases()                   do { } while (0)
 #define account_process_vtime(tsk)             do { } while (0)
 #endif
 
index 597e6f9d094a95dd51ff80873e8425d75ed94759..6151937657f69c0a3ee9f201befc74f297c57bce 100644 (file)
 #define __NR_fanotify_init     323
 #define __NR_fanotify_mark     324
 #define __NR_prlimit64         325
+#define __NR_socket            326
+#define __NR_bind              327
+#define __NR_connect           328
+#define __NR_listen            329
+#define __NR_accept            330
+#define __NR_getsockname       331
+#define __NR_getpeername       332
+#define __NR_socketpair                333
+#define __NR_send              334
+#define __NR_sendto            335
+#define __NR_recv              336
+#define __NR_recvfrom          337
+#define __NR_shutdown          338
+#define __NR_setsockopt                339
+#define __NR_getsockopt                340
+#define __NR_sendmsg           341
+#define __NR_recvmsg           342
+#define __NR_recvmmsg          343
+#define __NR_accept4           344
 
 #ifdef __KERNEL__
 
-#define __NR_syscalls          326
+#define __NR_syscalls          345
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index 1dda70129141d04656c65c3af27389491c5c9261..4ed076a4db2453001468eeb9bc662aa9cf7def73 100644 (file)
@@ -55,7 +55,9 @@ obj-$(CONFIG_IBMVIO)          += vio.o
 obj-$(CONFIG_IBMEBUS)           += ibmebus.o
 obj-$(CONFIG_GENERIC_TBSYNC)   += smp-tbsync.o
 obj-$(CONFIG_CRASH_DUMP)       += crash_dump.o
+ifeq ($(CONFIG_PPC32),y)
 obj-$(CONFIG_E500)             += idle_e500.o
+endif
 obj-$(CONFIG_6xx)              += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
 obj-$(CONFIG_TAU)              += tau_6xx.o
 obj-$(CONFIG_HIBERNATION)      += swsusp.o suspend.o
@@ -67,7 +69,7 @@ endif
 obj64-$(CONFIG_HIBERNATION)    += swsusp_asm64.o
 obj-$(CONFIG_MODULES)          += module.o module_$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_44x)              += cpu_setup_44x.o
-obj-$(CONFIG_FSL_BOOKE)                += cpu_setup_fsl_booke.o dbell.o
+obj-$(CONFIG_PPC_FSL_BOOK3E)   += cpu_setup_fsl_booke.o dbell.o
 obj-$(CONFIG_PPC_BOOK3E_64)    += dbell.o
 
 extra-y                                := head_$(CONFIG_WORD_SIZE).o
index b876e989220b02fbb3314e5ac56043717a42ffcb..8184ee97e484e9b86dcb8c0d0f226e88066796d4 100644 (file)
@@ -889,7 +889,7 @@ int fix_alignment(struct pt_regs *regs)
 #ifdef CONFIG_PPC_FPU
                        preempt_disable();
                        enable_kernel_fp();
-                       cvt_df(&data.dd, (float *)&data.v[4], &current->thread);
+                       cvt_df(&data.dd, (float *)&data.v[4]);
                        preempt_enable();
 #else
                        return 0;
@@ -933,7 +933,7 @@ int fix_alignment(struct pt_regs *regs)
 #ifdef CONFIG_PPC_FPU
                preempt_disable();
                enable_kernel_fp();
-               cvt_fd((float *)&data.v[4], &data.dd, &current->thread);
+               cvt_fd((float *)&data.v[4], &data.dd);
                preempt_enable();
 #else
                return 0;
index 1c0607ddccc09e7b3c34dc19695ebdfbbff6295b..c3e01945ad4f6f8493c37cc13b7d5298176f4a98 100644 (file)
@@ -61,7 +61,7 @@
 #endif
 #endif
 
-#if defined(CONFIG_FSL_BOOKE)
+#if defined(CONFIG_PPC_FSL_BOOK3E)
 #include "../mm/mmu_decl.h"
 #endif
 
@@ -181,17 +181,19 @@ int main(void)
               offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid));
        DEFINE(SLBSHADOW_STACKESID,
               offsetof(struct slb_shadow, save_area[SLB_NUM_BOLTED - 1].esid));
+       DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
        DEFINE(LPPACASRR0, offsetof(struct lppaca, saved_srr0));
        DEFINE(LPPACASRR1, offsetof(struct lppaca, saved_srr1));
        DEFINE(LPPACAANYINT, offsetof(struct lppaca, int_dword.any_int));
        DEFINE(LPPACADECRINT, offsetof(struct lppaca, int_dword.fields.decr_int));
-       DEFINE(SLBSHADOW_SAVEAREA, offsetof(struct slb_shadow, save_area));
+       DEFINE(LPPACA_DTLIDX, offsetof(struct lppaca, dtl_idx));
+       DEFINE(PACA_DTL_RIDX, offsetof(struct paca_struct, dtl_ridx));
 #endif /* CONFIG_PPC_STD_MMU_64 */
        DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
        DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
        DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
-       DEFINE(PACA_STARTPURR, offsetof(struct paca_struct, startpurr));
-       DEFINE(PACA_STARTSPURR, offsetof(struct paca_struct, startspurr));
+       DEFINE(PACA_STARTTIME, offsetof(struct paca_struct, starttime));
+       DEFINE(PACA_STARTTIME_USER, offsetof(struct paca_struct, starttime_user));
        DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
        DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time));
        DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save));
@@ -468,7 +470,7 @@ int main(void)
        DEFINE(PGD_T_LOG2, PGD_T_LOG2);
        DEFINE(PTE_T_LOG2, PTE_T_LOG2);
 #endif
-#ifdef CONFIG_FSL_BOOKE
+#ifdef CONFIG_PPC_FSL_BOOK3E
        DEFINE(TLBCAM_SIZE, sizeof(struct tlbcam));
        DEFINE(TLBCAM_MAS0, offsetof(struct tlbcam, MAS0));
        DEFINE(TLBCAM_MAS1, offsetof(struct tlbcam, MAS1));
index 7d606f89a8396311c5019fc65ba7fa66f6d720b3..e32b4a9a2c2282c2554e854965f7f8b784ffe3eb 100644 (file)
@@ -35,6 +35,7 @@ _GLOBAL(__setup_cpu_440grx)
 _GLOBAL(__setup_cpu_460ex)
 _GLOBAL(__setup_cpu_460gt)
 _GLOBAL(__setup_cpu_460sx)
+_GLOBAL(__setup_cpu_apm821xx)
        mflr    r4
        bl      __init_fpu_44x
        bl      __fixup_440A_mcheck
index 0adb50ad8031220afc2aa3d9ec66b88da5be801e..894e64fa481e94ca51b8c02419310a017ac2adf0 100644 (file)
@@ -51,6 +51,7 @@ _GLOBAL(__e500_dcache_setup)
        isync
        blr
 
+#ifdef CONFIG_PPC32
 _GLOBAL(__setup_cpu_e200)
        /* enable dedicated debug exception handling resources (Debug APU) */
        mfspr   r3,SPRN_HID0
@@ -72,3 +73,17 @@ _GLOBAL(__setup_cpu_e500mc)
        bl      __setup_e500mc_ivors
        mtlr    r4
        blr
+#endif
+/* Right now, restore and setup are the same thing */
+_GLOBAL(__restore_cpu_e5500)
+_GLOBAL(__setup_cpu_e5500)
+       mflr    r4
+       bl      __e500_icache_setup
+       bl      __e500_dcache_setup
+#ifdef CONFIG_PPC_BOOK3E_64
+       bl      .__setup_base_ivors
+#else
+       bl      __setup_e500mc_ivors
+#endif
+       mtlr    r4
+       blr
index 1f9123f412ec3c5a7a817f58e6316298d6ce7e05..96a908f1cd876ac1d4456e884da8c3cdd5c4e7c8 100644 (file)
@@ -48,6 +48,7 @@ extern void __setup_cpu_440x5(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_460sx(unsigned long offset, struct cpu_spec *spec);
+extern void __setup_cpu_apm821xx(unsigned long offset, struct cpu_spec *spec);
 extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec);
 extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec);
@@ -66,6 +67,10 @@ extern void __restore_cpu_ppc970(void);
 extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec);
 extern void __restore_cpu_power7(void);
 #endif /* CONFIG_PPC64 */
+#if defined(CONFIG_E500)
+extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
+extern void __restore_cpu_e5500(void);
+#endif /* CONFIG_E500 */
 
 /* This table only contains "desktop" CPUs, it need to be filled with embedded
  * ones as well...
@@ -1805,6 +1810,20 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check          = machine_check_440A,
                .platform               = "ppc440",
        },
+       { /* 464 in APM821xx */
+               .pvr_mask               = 0xffffff00,
+               .pvr_value              = 0x12C41C80,
+               .cpu_name               = "APM821XX",
+               .cpu_features           = CPU_FTRS_44X,
+               .cpu_user_features      = COMMON_USER_BOOKE |
+                       PPC_FEATURE_HAS_FPU,
+               .mmu_features           = MMU_FTR_TYPE_44x,
+               .icache_bsize           = 32,
+               .dcache_bsize           = 32,
+               .cpu_setup              = __setup_cpu_apm821xx,
+               .machine_check          = machine_check_440A,
+               .platform               = "ppc440",
+       },
        { /* 476 core */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x11a50000,
@@ -1891,7 +1910,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .platform               = "ppc5554",
        }
 #endif /* CONFIG_E200 */
+#endif /* CONFIG_PPC32 */
 #ifdef CONFIG_E500
+#ifdef CONFIG_PPC32
        {       /* e500 */
                .pvr_mask               = 0xffff0000,
                .pvr_value              = 0x80200000,
@@ -1946,6 +1967,26 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check          = machine_check_e500mc,
                .platform               = "ppce500mc",
        },
+#endif /* CONFIG_PPC32 */
+       {       /* e5500 */
+               .pvr_mask               = 0xffff0000,
+               .pvr_value              = 0x80240000,
+               .cpu_name               = "e5500",
+               .cpu_features           = CPU_FTRS_E500MC,
+               .cpu_user_features      = COMMON_USER_BOOKE,
+               .mmu_features           = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS |
+                       MMU_FTR_USE_TLBILX,
+               .icache_bsize           = 64,
+               .dcache_bsize           = 64,
+               .num_pmcs               = 4,
+               .oprofile_cpu_type      = "ppc/e500mc",
+               .oprofile_type          = PPC_OPROFILE_FSL_EMB,
+               .cpu_setup              = __setup_cpu_e5500,
+               .cpu_restore            = __restore_cpu_e5500,
+               .machine_check          = machine_check_e500mc,
+               .platform               = "ppce5500",
+       },
+#ifdef CONFIG_PPC32
        {       /* default match */
                .pvr_mask               = 0x00000000,
                .pvr_value              = 0x00000000,
@@ -1960,8 +2001,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .machine_check          = machine_check_e500,
                .platform               = "powerpc",
        }
-#endif /* CONFIG_E500 */
 #endif /* CONFIG_PPC32 */
+#endif /* CONFIG_E500 */
 
 #ifdef CONFIG_PPC_BOOK3E_64
        {       /* This is a default entry to get going, to be replaced by
index 4457382f8667a7e770f51c9cb82ee09f9531fb1b..832c8c4db2541225ad007f5592b60ec8fe14776d 100644 (file)
@@ -414,18 +414,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
        crash_kexec_wait_realmode(crashing_cpu);
 #endif
 
-       for_each_irq(i) {
-               struct irq_desc *desc = irq_to_desc(i);
-
-               if (!desc || !desc->chip || !desc->chip->eoi)
-                       continue;
-
-               if (desc->status & IRQ_INPROGRESS)
-                       desc->chip->eoi(i);
-
-               if (!(desc->status & IRQ_DISABLED))
-                       desc->chip->shutdown(i);
-       }
+       machine_kexec_mask_interrupts();
 
        /*
         * Call registered shutdown routines savely.  Swap out
index 37771a51811915665e7279f0ec0089e20cfcf51b..6e54a0fd31aa2485591b565bb9e0a8e121835fb7 100644 (file)
@@ -74,16 +74,17 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask)
 {
        struct iommu_table *tbl = get_iommu_table_base(dev);
 
-       if (!tbl || tbl->it_offset > mask) {
-               printk(KERN_INFO
-                      "Warning: IOMMU offset too big for device mask\n");
-               if (tbl)
-                       printk(KERN_INFO
-                              "mask: 0x%08llx, table offset: 0x%08lx\n",
-                               mask, tbl->it_offset);
-               else
-                       printk(KERN_INFO "mask: 0x%08llx, table unavailable\n",
-                               mask);
+       if (!tbl) {
+               dev_info(dev, "Warning: IOMMU dma not supported: mask 0x%08llx"
+                       ", table unavailable\n", mask);
+               return 0;
+       }
+
+       if ((tbl->it_offset + tbl->it_size) > (mask >> IOMMU_PAGE_SHIFT)) {
+               dev_info(dev, "Warning: IOMMU window too big for device mask\n");
+               dev_info(dev, "mask: 0x%08llx, table end: 0x%08lx\n",
+                               mask, (tbl->it_offset + tbl->it_size) <<
+                               IOMMU_PAGE_SHIFT);
                return 0;
        } else
                return 1;
index 84d6367ec0030c6611782902321d39871b9fe278..cf02cad62d9a78ecaae14161d7deb6cd78bdf768 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/memblock.h>
 #include <asm/bug.h>
 #include <asm/abs_addr.h>
+#include <asm/machdep.h>
 
 /*
  * Generic direct DMA implementation
@@ -89,7 +90,7 @@ static int dma_direct_dma_supported(struct device *dev, u64 mask)
        /* Could be improved so platforms can set the limit in case
         * they have limited DMA windows
         */
-       return mask >= (memblock_end_of_DRAM() - 1);
+       return mask >= get_dma_offset(dev) + (memblock_end_of_DRAM() - 1);
 #else
        return 1;
 #endif
@@ -154,6 +155,23 @@ EXPORT_SYMBOL(dma_direct_ops);
 
 #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16)
 
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+       struct dma_map_ops *dma_ops = get_dma_ops(dev);
+
+       if (ppc_md.dma_set_mask)
+               return ppc_md.dma_set_mask(dev, dma_mask);
+       if (unlikely(dma_ops == NULL))
+               return -EIO;
+       if (dma_ops->set_dma_mask != NULL)
+               return dma_ops->set_dma_mask(dev, dma_mask);
+       if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+               return -EIO;
+       *dev->dma_mask = dma_mask;
+       return 0;
+}
+EXPORT_SYMBOL(dma_set_mask);
+
 static int __init dma_init(void)
 {
        dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
index 42e9d908914a0e47117cfe7f3dcc5fe50d215d98..d82878c4daa677c416cf116924b4d34e58d501d3 100644 (file)
@@ -97,6 +97,24 @@ system_call_common:
        addi    r9,r1,STACK_FRAME_OVERHEAD
        ld      r11,exception_marker@toc(r2)
        std     r11,-16(r9)             /* "regshere" marker */
+#if defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR)
+BEGIN_FW_FTR_SECTION
+       beq     33f
+       /* if from user, see if there are any DTL entries to process */
+       ld      r10,PACALPPACAPTR(r13)  /* get ptr to VPA */
+       ld      r11,PACA_DTL_RIDX(r13)  /* get log read index */
+       ld      r10,LPPACA_DTLIDX(r10)  /* get log write index */
+       cmpd    cr1,r11,r10
+       beq+    cr1,33f
+       bl      .accumulate_stolen_time
+       REST_GPR(0,r1)
+       REST_4GPRS(3,r1)
+       REST_2GPRS(7,r1)
+       addi    r9,r1,STACK_FRAME_OVERHEAD
+33:
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */
+
 #ifdef CONFIG_TRACE_IRQFLAGS
        bl      .trace_hardirqs_on
        REST_GPR(0,r1)
@@ -202,7 +220,9 @@ syscall_exit:
        bge-    syscall_error
 syscall_error_cont:
        ld      r7,_NIP(r1)
+BEGIN_FTR_SECTION
        stdcx.  r0,0,r1                 /* to clear the reservation */
+END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
        andi.   r6,r8,MSR_PR
        ld      r4,_LINK(r1)
        /*
@@ -419,6 +439,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
        sync
 #endif /* CONFIG_SMP */
 
+       /*
+        * If we optimise away the clear of the reservation in system
+        * calls because we know the CPU tracks the address of the
+        * reservation, then we need to clear it here to cover the
+        * case that the kernel context switch path has no larx
+        * instructions.
+        */
+BEGIN_FTR_SECTION
+       ldarx   r6,0,r1
+END_FTR_SECTION_IFSET(CPU_FTR_STCX_CHECKS_ADDRESS)
+
        addi    r6,r4,-THREAD   /* Convert THREAD to 'current' */
        std     r6,PACACURRENT(r13)     /* Set new 'current' */
 
@@ -576,7 +607,16 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
        andi.   r0,r3,MSR_RI
        beq-    unrecov_restore
 
+       /*
+        * Clear the reservation. If we know the CPU tracks the address of
+        * the reservation then we can potentially save some cycles and use
+        * a larx. On POWER6 and POWER7 this is significantly faster.
+        */
+BEGIN_FTR_SECTION
        stdcx.  r0,0,r1         /* to clear the reservation */
+FTR_SECTION_ELSE
+       ldarx   r4,0,r1
+ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
 
        /*
         * Clear RI before restoring r13.  If we are returning to
index f53029a01554ca3ce86a9e1983b048335f7383f0..39b0c48872d23b337f07c00bb0299e284a8f9ab5 100644 (file)
@@ -818,12 +818,12 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
 
        /*
         * hash_page couldn't handle it, set soft interrupt enable back
-        * to what it was before the trap.  Note that .raw_local_irq_restore
+        * to what it was before the trap.  Note that .arch_local_irq_restore
         * handles any interrupts pending at this point.
         */
        ld      r3,SOFTE(r1)
        TRACE_AND_RESTORE_IRQ_PARTIAL(r3, 11f)
-       bl      .raw_local_irq_restore
+       bl      .arch_local_irq_restore
        b       11f
 
 /* We have a data breakpoint exception - handle it */
index fc8f5b14019c515ba870868b7789799ca9efd1a0..e86c040ae5857056a2538fe535864e96d2ce3579 100644 (file)
@@ -163,24 +163,14 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
 /*
  * These are used in the alignment trap handler when emulating
  * single-precision loads and stores.
- * We restore and save the fpscr so the task gets the same result
- * and exceptions as if the cpu had performed the load or store.
  */
 
 _GLOBAL(cvt_fd)
-       lfd     0,THREAD_FPSCR(r5)      /* load up fpscr value */
-       MTFSF_L(0)
        lfs     0,0(r3)
        stfd    0,0(r4)
-       mffs    0
-       stfd    0,THREAD_FPSCR(r5)      /* save new fpscr value */
        blr
 
 _GLOBAL(cvt_df)
-       lfd     0,THREAD_FPSCR(r5)      /* load up fpscr value */
-       MTFSF_L(0)
        lfd     0,0(r3)
        stfs    0,0(r4)
-       mffs    0
-       stfd    0,THREAD_FPSCR(r5)      /* save new fpscr value */
        blr
index a90625f9b48517bdca205774dc71a962ec698d91..8278e8bad5a01ebad1de83e5623047cd3899364e 100644 (file)
@@ -923,11 +923,7 @@ initial_mmu:
        mtspr   SPRN_PID,r0
        sync
 
-       /* Configure and load two entries into TLB slots 62 and 63.
-        * 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.
-        */
+       /* Configure and load one entry into TLB slots 63 */
        clrrwi  r4,r4,10                /* Mask off the real page number */
        ori     r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
 
index 4faeba247854c038078ef4362836d50b37f4f44a..529b817f473b13de52bea2ac0ae33e859e9e27c4 100644 (file)
@@ -152,8 +152,11 @@ _ENTRY(__early_start)
        /* Check to see if we're the second processor, and jump
         * to the secondary_start code if so
         */
-       mfspr   r24,SPRN_PIR
-       cmpwi   r24,0
+       lis     r24, boot_cpuid@h
+       ori     r24, r24, boot_cpuid@l
+       lwz     r24, 0(r24)
+       cmpwi   r24, -1
+       mfspr   r24,SPRN_PIR
        bne     __secondary_start
 #endif
 
@@ -175,6 +178,9 @@ _ENTRY(__early_start)
        li      r0,0
        stwu    r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
 
+       rlwinm  r22,r1,0,0,31-THREAD_SHIFT      /* current thread_info */
+       stw     r24, TI_CPU(r22)
+
        bl      early_init
 
 #ifdef CONFIG_RELOCATABLE
index 4a65386995d7fa697f86e32b77503558f1198961..ce557f6f00fcf2817c38ad8821a2e7fc8c8394a4 100644 (file)
@@ -116,7 +116,7 @@ static inline notrace void set_soft_enabled(unsigned long enable)
        : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
 }
 
-notrace void raw_local_irq_restore(unsigned long en)
+notrace void arch_local_irq_restore(unsigned long en)
 {
        /*
         * get_paca()->soft_enabled = en;
@@ -192,7 +192,7 @@ notrace void raw_local_irq_restore(unsigned long en)
 
        __hard_irq_enable();
 }
-EXPORT_SYMBOL(raw_local_irq_restore);
+EXPORT_SYMBOL(arch_local_irq_restore);
 #endif /* CONFIG_PPC64 */
 
 static int show_other_interrupts(struct seq_file *p, int prec)
@@ -587,8 +587,10 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
                         * this will be fixed once slab is made available early
                         * instead of the current cruft
                         */
-                       if (mem_init_done)
+                       if (mem_init_done) {
+                               of_node_put(host->of_node);
                                kfree(host);
+                       }
                        return NULL;
                }
                irq_map[0].host = host;
@@ -1143,7 +1145,7 @@ static int virq_debug_show(struct seq_file *m, void *private)
        unsigned long flags;
        struct irq_desc *desc;
        const char *p;
-       char none[] = "none";
+       static const char none[] = "none";
        int i;
 
        seq_printf(m, "%-5s  %-7s  %-15s  %s\n", "virq", "hwirq",
index 50362b6ef6e93d8752ffda779ffaee429e2a054a..8d9e3b9cda645e0cf072cc12a7bd557da633aa67 100644 (file)
@@ -56,7 +56,7 @@ static unsigned long get_purr(void)
 
        for_each_possible_cpu(cpu) {
                if (firmware_has_feature(FW_FEATURE_ISERIES))
-                       sum_purr += lppaca[cpu].emulated_time_base;
+                       sum_purr += lppaca_of(cpu).emulated_time_base;
                else {
                        struct cpu_usage *cu;
 
@@ -263,7 +263,7 @@ static void parse_ppp_data(struct seq_file *m)
                   ppp_data.active_system_procs);
 
        /* pool related entries are apropriate for shared configs */
-       if (lppaca[0].shared_proc) {
+       if (lppaca_of(0).shared_proc) {
                unsigned long pool_idle_time, pool_procs;
 
                seq_printf(m, "pool=%d\n", ppp_data.pool_num);
@@ -460,8 +460,8 @@ static void pseries_cmo_data(struct seq_file *m)
                return;
 
        for_each_possible_cpu(cpu) {
-               cmo_faults += lppaca[cpu].cmo_faults;
-               cmo_fault_time += lppaca[cpu].cmo_fault_time;
+               cmo_faults += lppaca_of(cpu).cmo_faults;
+               cmo_fault_time += lppaca_of(cpu).cmo_fault_time;
        }
 
        seq_printf(m, "cmo_faults=%lu\n", cmo_faults);
@@ -479,8 +479,8 @@ static void splpar_dispatch_data(struct seq_file *m)
        unsigned long dispatch_dispersions = 0;
 
        for_each_possible_cpu(cpu) {
-               dispatches += lppaca[cpu].yield_count;
-               dispatch_dispersions += lppaca[cpu].dispersion_count;
+               dispatches += lppaca_of(cpu).yield_count;
+               dispatch_dispersions += lppaca_of(cpu).dispersion_count;
        }
 
        seq_printf(m, "dispatches=%lu\n", dispatches);
@@ -545,7 +545,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
        seq_printf(m, "partition_potential_processors=%d\n",
                   partition_potential_processors);
 
-       seq_printf(m, "shared_processor_mode=%d\n", lppaca[0].shared_proc);
+       seq_printf(m, "shared_processor_mode=%d\n", lppaca_of(0).shared_proc);
 
        seq_printf(m, "slb_size=%d\n", mmu_slb_size);
 
index dd6c141f166261b7970c42023f8b96a0ccf3085f..df7e20c191cda3190c1396bc60921bd8c8df003f 100644 (file)
 #include <linux/threads.h>
 #include <linux/memblock.h>
 #include <linux/of.h>
+#include <linux/irq.h>
+
 #include <asm/machdep.h>
 #include <asm/prom.h>
 #include <asm/sections.h>
 
+void machine_kexec_mask_interrupts(void) {
+       unsigned int i;
+
+       for_each_irq(i) {
+               struct irq_desc *desc = irq_to_desc(i);
+
+               if (!desc || !desc->chip)
+                       continue;
+
+               if (desc->chip->eoi &&
+                   desc->status & IRQ_INPROGRESS)
+                       desc->chip->eoi(i);
+
+               if (desc->chip->mask)
+                       desc->chip->mask(i);
+
+               if (desc->chip->disable &&
+                   !(desc->status & IRQ_DISABLED))
+                       desc->chip->disable(i);
+       }
+}
+
 void machine_crash_shutdown(struct pt_regs *regs)
 {
        if (ppc_md.machine_crash_shutdown)
index ae63a964b858049f63a47e446e96bb54295a6c0c..e63f2e7d2efb029fca417c344ecee0d9e96daf88 100644 (file)
@@ -39,6 +39,10 @@ void default_machine_kexec(struct kimage *image)
        /* Interrupts aren't acceptable while we reboot */
        local_irq_disable();
 
+       /* mask each interrupt so we are in a more sane state for the
+        * kexec kernel */
+       machine_kexec_mask_interrupts();
+
        page_list = image->head;
 
        /* we need both effective and real address here */
index d0a26f1770fe0492320e3fe4187cb20b741fd56e..ebf9846f3c3b30b7cf2d61d48a8a96c37b702c1c 100644 (file)
@@ -26,6 +26,20 @@ extern unsigned long __toc_start;
 
 #ifdef CONFIG_PPC_BOOK3S
 
+/*
+ * We only have to have statically allocated lppaca structs on
+ * legacy iSeries, which supports at most 64 cpus.
+ */
+#ifdef CONFIG_PPC_ISERIES
+#if NR_CPUS < 64
+#define NR_LPPACAS     NR_CPUS
+#else
+#define NR_LPPACAS     64
+#endif
+#else /* not iSeries */
+#define NR_LPPACAS     1
+#endif
+
 /*
  * The structure which the hypervisor knows about - this structure
  * should not cross a page boundary.  The vpa_init/register_vpa call
@@ -36,7 +50,7 @@ extern unsigned long __toc_start;
  * will suffice to ensure that it doesn't cross a page boundary.
  */
 struct lppaca lppaca[] = {
-       [0 ... (NR_CPUS-1)] = {
+       [0 ... (NR_LPPACAS-1)] = {
                .desc = 0xd397d781,     /* "LpPa" */
                .size = sizeof(struct lppaca),
                .dyn_proc_status = 2,
@@ -49,6 +63,54 @@ struct lppaca lppaca[] = {
        },
 };
 
+static struct lppaca *extra_lppacas;
+static long __initdata lppaca_size;
+
+static void allocate_lppacas(int nr_cpus, unsigned long limit)
+{
+       if (nr_cpus <= NR_LPPACAS)
+               return;
+
+       lppaca_size = PAGE_ALIGN(sizeof(struct lppaca) *
+                                (nr_cpus - NR_LPPACAS));
+       extra_lppacas = __va(memblock_alloc_base(lppaca_size,
+                                                PAGE_SIZE, limit));
+}
+
+static struct lppaca *new_lppaca(int cpu)
+{
+       struct lppaca *lp;
+
+       if (cpu < NR_LPPACAS)
+               return &lppaca[cpu];
+
+       lp = extra_lppacas + (cpu - NR_LPPACAS);
+       *lp = lppaca[0];
+
+       return lp;
+}
+
+static void free_lppacas(void)
+{
+       long new_size = 0, nr;
+
+       if (!lppaca_size)
+               return;
+       nr = num_possible_cpus() - NR_LPPACAS;
+       if (nr > 0)
+               new_size = PAGE_ALIGN(nr * sizeof(struct lppaca));
+       if (new_size >= lppaca_size)
+               return;
+
+       memblock_free(__pa(extra_lppacas) + new_size, lppaca_size - new_size);
+       lppaca_size = new_size;
+}
+
+#else
+
+static inline void allocate_lppacas(int nr_cpus, unsigned long limit) { }
+static inline void free_lppacas(void) { }
+
 #endif /* CONFIG_PPC_BOOK3S */
 
 #ifdef CONFIG_PPC_STD_MMU_64
@@ -88,7 +150,7 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
        unsigned long kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL;
 
 #ifdef CONFIG_PPC_BOOK3S
-       new_paca->lppaca_ptr = &lppaca[cpu];
+       new_paca->lppaca_ptr = new_lppaca(cpu);
 #else
        new_paca->kernel_pgd = swapper_pg_dir;
 #endif
@@ -127,7 +189,7 @@ void __init allocate_pacas(void)
         * the first segment. On iSeries they must be within the area mapped
         * by the HV, which is HvPagesToMap * HVPAGESIZE bytes.
         */
-       limit = min(0x10000000ULL, memblock.rmo_size);
+       limit = min(0x10000000ULL, ppc64_rma_size);
        if (firmware_has_feature(FW_FEATURE_ISERIES))
                limit = min(limit, HvPagesToMap * HVPAGESIZE);
 
@@ -144,6 +206,8 @@ void __init allocate_pacas(void)
        printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n",
                paca_size, nr_cpus, paca);
 
+       allocate_lppacas(nr_cpus, limit);
+
        /* Can't use for_each_*_cpu, as they aren't functional yet */
        for (cpu = 0; cpu < nr_cpus; cpu++)
                initialise_paca(&paca[cpu], cpu);
@@ -164,4 +228,6 @@ void __init free_unused_pacas(void)
                paca_size - new_size);
 
        paca_size = new_size;
+
+       free_lppacas();
 }
index 9021c4ad4bbd3ebdcda00af9de8bf59e6bfacc83..10a44e68ef11eca50957467569b052fd796d6936 100644 (file)
@@ -1090,8 +1090,6 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
                 bus->number, bus->self ? pci_name(bus->self) : "PHB");
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
-               struct dev_archdata *sd = &dev->dev.archdata;
-
                /* Cardbus can call us to add new devices to a bus, so ignore
                 * those who are already fully discovered
                 */
@@ -1107,7 +1105,7 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
                set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
 
                /* Hook up default DMA ops */
-               sd->dma_ops = pci_dma_ops;
+               set_dma_ops(&dev->dev, pci_dma_ops);
                set_dma_offset(&dev->dev, PCI_DRAM_OFFSET);
 
                /* Additional platform DMA/iommu setup */
index 95ad9dad298e9d4773117b0406bc4a3378d77e5e..d05ae4204bbf3d3ddcc84266476b736a6790715c 100644 (file)
 #include "ppc32.h"
 #endif
 
-/*
- * Store another value in a callchain_entry.
- */
-static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip)
-{
-       unsigned int nr = entry->nr;
-
-       if (nr < PERF_MAX_STACK_DEPTH) {
-               entry->ip[nr] = ip;
-               entry->nr = nr + 1;
-       }
-}
 
 /*
  * Is sp valid as the address of the next kernel stack frame after prev_sp?
@@ -58,8 +46,8 @@ static int valid_next_sp(unsigned long sp, unsigned long prev_sp)
        return 0;
 }
 
-static void perf_callchain_kernel(struct pt_regs *regs,
-                                 struct perf_callchain_entry *entry)
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
        unsigned long sp, next_sp;
        unsigned long next_ip;
@@ -69,8 +57,7 @@ static void perf_callchain_kernel(struct pt_regs *regs,
 
        lr = regs->link;
        sp = regs->gpr[1];
-       callchain_store(entry, PERF_CONTEXT_KERNEL);
-       callchain_store(entry, regs->nip);
+       perf_callchain_store(entry, regs->nip);
 
        if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
                return;
@@ -89,7 +76,7 @@ static void perf_callchain_kernel(struct pt_regs *regs,
                        next_ip = regs->nip;
                        lr = regs->link;
                        level = 0;
-                       callchain_store(entry, PERF_CONTEXT_KERNEL);
+                       perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
 
                } else {
                        if (level == 0)
@@ -111,7 +98,7 @@ static void perf_callchain_kernel(struct pt_regs *regs,
                        ++level;
                }
 
-               callchain_store(entry, next_ip);
+               perf_callchain_store(entry, next_ip);
                if (!valid_next_sp(next_sp, sp))
                        return;
                sp = next_sp;
@@ -233,8 +220,8 @@ static int sane_signal_64_frame(unsigned long sp)
                puc == (unsigned long) &sf->uc;
 }
 
-static void perf_callchain_user_64(struct pt_regs *regs,
-                                  struct perf_callchain_entry *entry)
+static void perf_callchain_user_64(struct perf_callchain_entry *entry,
+                                  struct pt_regs *regs)
 {
        unsigned long sp, next_sp;
        unsigned long next_ip;
@@ -246,8 +233,7 @@ static void perf_callchain_user_64(struct pt_regs *regs,
        next_ip = regs->nip;
        lr = regs->link;
        sp = regs->gpr[1];
-       callchain_store(entry, PERF_CONTEXT_USER);
-       callchain_store(entry, next_ip);
+       perf_callchain_store(entry, next_ip);
 
        for (;;) {
                fp = (unsigned long __user *) sp;
@@ -276,14 +262,14 @@ static void perf_callchain_user_64(struct pt_regs *regs,
                            read_user_stack_64(&uregs[PT_R1], &sp))
                                return;
                        level = 0;
-                       callchain_store(entry, PERF_CONTEXT_USER);
-                       callchain_store(entry, next_ip);
+                       perf_callchain_store(entry, PERF_CONTEXT_USER);
+                       perf_callchain_store(entry, next_ip);
                        continue;
                }
 
                if (level == 0)
                        next_ip = lr;
-               callchain_store(entry, next_ip);
+               perf_callchain_store(entry, next_ip);
                ++level;
                sp = next_sp;
        }
@@ -315,8 +301,8 @@ static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
        return __get_user_inatomic(*ret, ptr);
 }
 
-static inline void perf_callchain_user_64(struct pt_regs *regs,
-                                         struct perf_callchain_entry *entry)
+static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
+                                         struct pt_regs *regs)
 {
 }
 
@@ -435,8 +421,8 @@ static unsigned int __user *signal_frame_32_regs(unsigned int sp,
        return mctx->mc_gregs;
 }
 
-static void perf_callchain_user_32(struct pt_regs *regs,
-                                  struct perf_callchain_entry *entry)
+static void perf_callchain_user_32(struct perf_callchain_entry *entry,
+                                  struct pt_regs *regs)
 {
        unsigned int sp, next_sp;
        unsigned int next_ip;
@@ -447,8 +433,7 @@ static void perf_callchain_user_32(struct pt_regs *regs,
        next_ip = regs->nip;
        lr = regs->link;
        sp = regs->gpr[1];
-       callchain_store(entry, PERF_CONTEXT_USER);
-       callchain_store(entry, next_ip);
+       perf_callchain_store(entry, next_ip);
 
        while (entry->nr < PERF_MAX_STACK_DEPTH) {
                fp = (unsigned int __user *) (unsigned long) sp;
@@ -470,45 +455,24 @@ static void perf_callchain_user_32(struct pt_regs *regs,
                            read_user_stack_32(&uregs[PT_R1], &sp))
                                return;
                        level = 0;
-                       callchain_store(entry, PERF_CONTEXT_USER);
-                       callchain_store(entry, next_ip);
+                       perf_callchain_store(entry, PERF_CONTEXT_USER);
+                       perf_callchain_store(entry, next_ip);
                        continue;
                }
 
                if (level == 0)
                        next_ip = lr;
-               callchain_store(entry, next_ip);
+               perf_callchain_store(entry, next_ip);
                ++level;
                sp = next_sp;
        }
 }
 
-/*
- * Since we can't get PMU interrupts inside a PMU interrupt handler,
- * we don't need separate irq and nmi entries here.
- */
-static DEFINE_PER_CPU(struct perf_callchain_entry, cpu_perf_callchain);
-
-struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
-       struct perf_callchain_entry *entry = &__get_cpu_var(cpu_perf_callchain);
-
-       entry->nr = 0;
-
-       if (!user_mode(regs)) {
-               perf_callchain_kernel(regs, entry);
-               if (current->mm)
-                       regs = task_pt_regs(current);
-               else
-                       regs = NULL;
-       }
-
-       if (regs) {
-               if (current_is_64bit())
-                       perf_callchain_user_64(regs, entry);
-               else
-                       perf_callchain_user_32(regs, entry);
-       }
-
-       return entry;
+       if (current_is_64bit())
+               perf_callchain_user_64(entry, regs);
+       else
+               perf_callchain_user_32(entry, regs);
 }
index d301a30445e09a49cec4a3d4dcf2ea01529934b3..3129c855933c2a3857b0c4b3321b259b851279b8 100644 (file)
@@ -402,6 +402,9 @@ static void power_pmu_read(struct perf_event *event)
 {
        s64 val, delta, prev;
 
+       if (event->hw.state & PERF_HES_STOPPED)
+               return;
+
        if (!event->hw.idx)
                return;
        /*
@@ -517,7 +520,7 @@ static void write_mmcr0(struct cpu_hw_events *cpuhw, unsigned long mmcr0)
  * Disable all events to prevent PMU interrupts and to allow
  * events to be added or removed.
  */
-void hw_perf_disable(void)
+static void power_pmu_disable(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw;
        unsigned long flags;
@@ -565,7 +568,7 @@ void hw_perf_disable(void)
  * If we were previously disabled and events were added, then
  * put the new config on the PMU.
  */
-void hw_perf_enable(void)
+static void power_pmu_enable(struct pmu *pmu)
 {
        struct perf_event *event;
        struct cpu_hw_events *cpuhw;
@@ -672,6 +675,8 @@ void hw_perf_enable(void)
                }
                local64_set(&event->hw.prev_count, val);
                event->hw.idx = idx;
+               if (event->hw.state & PERF_HES_STOPPED)
+                       val = 0;
                write_pmc(idx, val);
                perf_event_update_userpage(event);
        }
@@ -727,7 +732,7 @@ static int collect_events(struct perf_event *group, int max_count,
  * re-enable the PMU in order to get hw_perf_enable to do the
  * actual work of reconfiguring the PMU.
  */
-static int power_pmu_enable(struct perf_event *event)
+static int power_pmu_add(struct perf_event *event, int ef_flags)
 {
        struct cpu_hw_events *cpuhw;
        unsigned long flags;
@@ -735,7 +740,7 @@ static int power_pmu_enable(struct perf_event *event)
        int ret = -EAGAIN;
 
        local_irq_save(flags);
-       perf_disable();
+       perf_pmu_disable(event->pmu);
 
        /*
         * Add the event to the list (if there is room)
@@ -749,6 +754,9 @@ static int power_pmu_enable(struct perf_event *event)
        cpuhw->events[n0] = event->hw.config;
        cpuhw->flags[n0] = event->hw.event_base;
 
+       if (!(ef_flags & PERF_EF_START))
+               event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+
        /*
         * If group events scheduling transaction was started,
         * skip the schedulability test here, it will be peformed
@@ -769,7 +777,7 @@ nocheck:
 
        ret = 0;
  out:
-       perf_enable();
+       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
        return ret;
 }
@@ -777,14 +785,14 @@ nocheck:
 /*
  * Remove a event from the PMU.
  */
-static void power_pmu_disable(struct perf_event *event)
+static void power_pmu_del(struct perf_event *event, int ef_flags)
 {
        struct cpu_hw_events *cpuhw;
        long i;
        unsigned long flags;
 
        local_irq_save(flags);
-       perf_disable();
+       perf_pmu_disable(event->pmu);
 
        power_pmu_read(event);
 
@@ -821,34 +829,60 @@ static void power_pmu_disable(struct perf_event *event)
                cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
        }
 
-       perf_enable();
+       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
 }
 
 /*
- * Re-enable interrupts on a event after they were throttled
- * because they were coming too fast.
+ * POWER-PMU does not support disabling individual counters, hence
+ * program their cycle counter to their max value and ignore the interrupts.
  */
-static void power_pmu_unthrottle(struct perf_event *event)
+
+static void power_pmu_start(struct perf_event *event, int ef_flags)
+{
+       unsigned long flags;
+       s64 left;
+
+       if (!event->hw.idx || !event->hw.sample_period)
+               return;
+
+       if (!(event->hw.state & PERF_HES_STOPPED))
+               return;
+
+       if (ef_flags & PERF_EF_RELOAD)
+               WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+       local_irq_save(flags);
+       perf_pmu_disable(event->pmu);
+
+       event->hw.state = 0;
+       left = local64_read(&event->hw.period_left);
+       write_pmc(event->hw.idx, left);
+
+       perf_event_update_userpage(event);
+       perf_pmu_enable(event->pmu);
+       local_irq_restore(flags);
+}
+
+static void power_pmu_stop(struct perf_event *event, int ef_flags)
 {
-       s64 val, left;
        unsigned long flags;
 
        if (!event->hw.idx || !event->hw.sample_period)
                return;
+
+       if (event->hw.state & PERF_HES_STOPPED)
+               return;
+
        local_irq_save(flags);
-       perf_disable();
+       perf_pmu_disable(event->pmu);
+
        power_pmu_read(event);
-       left = event->hw.sample_period;
-       event->hw.last_period = left;
-       val = 0;
-       if (left < 0x80000000L)
-               val = 0x80000000L - left;
-       write_pmc(event->hw.idx, val);
-       local64_set(&event->hw.prev_count, val);
-       local64_set(&event->hw.period_left, left);
+       event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+       write_pmc(event->hw.idx, 0);
+
        perf_event_update_userpage(event);
-       perf_enable();
+       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
 }
 
@@ -857,10 +891,11 @@ static void power_pmu_unthrottle(struct perf_event *event)
  * Set the flag to make pmu::enable() not perform the
  * schedulability test, it will be performed at commit time
  */
-void power_pmu_start_txn(const struct pmu *pmu)
+void power_pmu_start_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 
+       perf_pmu_disable(pmu);
        cpuhw->group_flag |= PERF_EVENT_TXN;
        cpuhw->n_txn_start = cpuhw->n_events;
 }
@@ -870,11 +905,12 @@ void power_pmu_start_txn(const struct pmu *pmu)
  * Clear the flag and pmu::enable() will perform the
  * schedulability test.
  */
-void power_pmu_cancel_txn(const struct pmu *pmu)
+void power_pmu_cancel_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 
        cpuhw->group_flag &= ~PERF_EVENT_TXN;
+       perf_pmu_enable(pmu);
 }
 
 /*
@@ -882,7 +918,7 @@ void power_pmu_cancel_txn(const struct pmu *pmu)
  * Perform the group schedulability test as a whole
  * Return 0 if success
  */
-int power_pmu_commit_txn(const struct pmu *pmu)
+int power_pmu_commit_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw;
        long i, n;
@@ -901,19 +937,10 @@ int power_pmu_commit_txn(const struct pmu *pmu)
                cpuhw->event[i]->hw.config = cpuhw->events[i];
 
        cpuhw->group_flag &= ~PERF_EVENT_TXN;
+       perf_pmu_enable(pmu);
        return 0;
 }
 
-struct pmu power_pmu = {
-       .enable         = power_pmu_enable,
-       .disable        = power_pmu_disable,
-       .read           = power_pmu_read,
-       .unthrottle     = power_pmu_unthrottle,
-       .start_txn      = power_pmu_start_txn,
-       .cancel_txn     = power_pmu_cancel_txn,
-       .commit_txn     = power_pmu_commit_txn,
-};
-
 /*
  * Return 1 if we might be able to put event on a limited PMC,
  * or 0 if not.
@@ -1014,7 +1041,7 @@ static int hw_perf_cache_event(u64 config, u64 *eventp)
        return 0;
 }
 
-const struct pmu *hw_perf_event_init(struct perf_event *event)
+static int power_pmu_event_init(struct perf_event *event)
 {
        u64 ev;
        unsigned long flags;
@@ -1026,25 +1053,27 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
        struct cpu_hw_events *cpuhw;
 
        if (!ppmu)
-               return ERR_PTR(-ENXIO);
+               return -ENOENT;
+
        switch (event->attr.type) {
        case PERF_TYPE_HARDWARE:
                ev = event->attr.config;
                if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
-                       return ERR_PTR(-EOPNOTSUPP);
+                       return -EOPNOTSUPP;
                ev = ppmu->generic_events[ev];
                break;
        case PERF_TYPE_HW_CACHE:
                err = hw_perf_cache_event(event->attr.config, &ev);
                if (err)
-                       return ERR_PTR(err);
+                       return err;
                break;
        case PERF_TYPE_RAW:
                ev = event->attr.config;
                break;
        default:
-               return ERR_PTR(-EINVAL);
+               return -ENOENT;
        }
+
        event->hw.config_base = ev;
        event->hw.idx = 0;
 
@@ -1063,7 +1092,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
         * XXX we should check if the task is an idle task.
         */
        flags = 0;
-       if (event->ctx->task)
+       if (event->attach_state & PERF_ATTACH_TASK)
                flags |= PPMU_ONLY_COUNT_RUN;
 
        /*
@@ -1081,7 +1110,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
                         */
                        ev = normal_pmc_alternative(ev, flags);
                        if (!ev)
-                               return ERR_PTR(-EINVAL);
+                               return -EINVAL;
                }
        }
 
@@ -1095,19 +1124,19 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
                n = collect_events(event->group_leader, ppmu->n_counter - 1,
                                   ctrs, events, cflags);
                if (n < 0)
-                       return ERR_PTR(-EINVAL);
+                       return -EINVAL;
        }
        events[n] = ev;
        ctrs[n] = event;
        cflags[n] = flags;
        if (check_excludes(ctrs, cflags, n, 1))
-               return ERR_PTR(-EINVAL);
+               return -EINVAL;
 
        cpuhw = &get_cpu_var(cpu_hw_events);
        err = power_check_constraints(cpuhw, events, cflags, n + 1);
        put_cpu_var(cpu_hw_events);
        if (err)
-               return ERR_PTR(-EINVAL);
+               return -EINVAL;
 
        event->hw.config = events[n];
        event->hw.event_base = cflags[n];
@@ -1132,11 +1161,23 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
        }
        event->destroy = hw_perf_event_destroy;
 
-       if (err)
-               return ERR_PTR(err);
-       return &power_pmu;
+       return err;
 }
 
+struct pmu power_pmu = {
+       .pmu_enable     = power_pmu_enable,
+       .pmu_disable    = power_pmu_disable,
+       .event_init     = power_pmu_event_init,
+       .add            = power_pmu_add,
+       .del            = power_pmu_del,
+       .start          = power_pmu_start,
+       .stop           = power_pmu_stop,
+       .read           = power_pmu_read,
+       .start_txn      = power_pmu_start_txn,
+       .cancel_txn     = power_pmu_cancel_txn,
+       .commit_txn     = power_pmu_commit_txn,
+};
+
 /*
  * A counter has overflowed; update its count and record
  * things if requested.  Note that interrupts are hard-disabled
@@ -1149,6 +1190,11 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
        s64 prev, delta, left;
        int record = 0;
 
+       if (event->hw.state & PERF_HES_STOPPED) {
+               write_pmc(event->hw.idx, 0);
+               return;
+       }
+
        /* we don't have to worry about interrupts here */
        prev = local64_read(&event->hw.prev_count);
        delta = (val - prev) & 0xfffffffful;
@@ -1171,6 +1217,11 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
                        val = 0x80000000LL - left;
        }
 
+       write_pmc(event->hw.idx, val);
+       local64_set(&event->hw.prev_count, val);
+       local64_set(&event->hw.period_left, left);
+       perf_event_update_userpage(event);
+
        /*
         * Finally record data if requested.
         */
@@ -1183,23 +1234,9 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
                if (event->attr.sample_type & PERF_SAMPLE_ADDR)
                        perf_get_data_addr(regs, &data.addr);
 
-               if (perf_event_overflow(event, nmi, &data, regs)) {
-                       /*
-                        * Interrupts are coming too fast - throttle them
-                        * by setting the event to 0, so it will be
-                        * at least 2^30 cycles until the next interrupt
-                        * (assuming each event counts at most 2 counts
-                        * per cycle).
-                        */
-                       val = 0;
-                       left = ~0ULL >> 1;
-               }
+               if (perf_event_overflow(event, nmi, &data, regs))
+                       power_pmu_stop(event, 0);
        }
-
-       write_pmc(event->hw.idx, val);
-       local64_set(&event->hw.prev_count, val);
-       local64_set(&event->hw.period_left, left);
-       perf_event_update_userpage(event);
 }
 
 /*
@@ -1342,6 +1379,7 @@ int register_power_pmu(struct power_pmu *pmu)
                freeze_events_kernel = MMCR0_FCHV;
 #endif /* CONFIG_PPC64 */
 
+       perf_pmu_register(&power_pmu);
        perf_cpu_notifier(power_pmu_notifier);
 
        return 0;
index 1ba45471ae436617e1ecbf3654a5064ef15d1af7..7ecca59ddf77fe20bd46b470d9392cdd16fd5ba9 100644 (file)
@@ -156,6 +156,9 @@ static void fsl_emb_pmu_read(struct perf_event *event)
 {
        s64 val, delta, prev;
 
+       if (event->hw.state & PERF_HES_STOPPED)
+               return;
+
        /*
         * Performance monitor interrupts come even when interrupts
         * are soft-disabled, as long as interrupts are hard-enabled.
@@ -177,7 +180,7 @@ static void fsl_emb_pmu_read(struct perf_event *event)
  * Disable all events to prevent PMU interrupts and to allow
  * events to be added or removed.
  */
-void hw_perf_disable(void)
+static void fsl_emb_pmu_disable(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw;
        unsigned long flags;
@@ -216,7 +219,7 @@ void hw_perf_disable(void)
  * If we were previously disabled and events were added, then
  * put the new config on the PMU.
  */
-void hw_perf_enable(void)
+static void fsl_emb_pmu_enable(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw;
        unsigned long flags;
@@ -262,8 +265,8 @@ static int collect_events(struct perf_event *group, int max_count,
        return n;
 }
 
-/* perf must be disabled, context locked on entry */
-static int fsl_emb_pmu_enable(struct perf_event *event)
+/* context locked on entry */
+static int fsl_emb_pmu_add(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuhw;
        int ret = -EAGAIN;
@@ -271,6 +274,7 @@ static int fsl_emb_pmu_enable(struct perf_event *event)
        u64 val;
        int i;
 
+       perf_pmu_disable(event->pmu);
        cpuhw = &get_cpu_var(cpu_hw_events);
 
        if (event->hw.config & FSL_EMB_EVENT_RESTRICTED)
@@ -301,6 +305,12 @@ static int fsl_emb_pmu_enable(struct perf_event *event)
                        val = 0x80000000L - left;
        }
        local64_set(&event->hw.prev_count, val);
+
+       if (!(flags & PERF_EF_START)) {
+               event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+               val = 0;
+       }
+
        write_pmc(i, val);
        perf_event_update_userpage(event);
 
@@ -310,15 +320,17 @@ static int fsl_emb_pmu_enable(struct perf_event *event)
        ret = 0;
  out:
        put_cpu_var(cpu_hw_events);
+       perf_pmu_enable(event->pmu);
        return ret;
 }
 
-/* perf must be disabled, context locked on entry */
-static void fsl_emb_pmu_disable(struct perf_event *event)
+/* context locked on entry */
+static void fsl_emb_pmu_del(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuhw;
        int i = event->hw.idx;
 
+       perf_pmu_disable(event->pmu);
        if (i < 0)
                goto out;
 
@@ -346,44 +358,57 @@ static void fsl_emb_pmu_disable(struct perf_event *event)
        cpuhw->n_events--;
 
  out:
+       perf_pmu_enable(event->pmu);
        put_cpu_var(cpu_hw_events);
 }
 
-/*
- * Re-enable interrupts on a event after they were throttled
- * because they were coming too fast.
- *
- * Context is locked on entry, but perf is not disabled.
- */
-static void fsl_emb_pmu_unthrottle(struct perf_event *event)
+static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags)
 {
-       s64 val, left;
        unsigned long flags;
+       s64 left;
 
        if (event->hw.idx < 0 || !event->hw.sample_period)
                return;
+
+       if (!(event->hw.state & PERF_HES_STOPPED))
+               return;
+
+       if (ef_flags & PERF_EF_RELOAD)
+               WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
        local_irq_save(flags);
-       perf_disable();
-       fsl_emb_pmu_read(event);
-       left = event->hw.sample_period;
-       event->hw.last_period = left;
-       val = 0;
-       if (left < 0x80000000L)
-               val = 0x80000000L - left;
-       write_pmc(event->hw.idx, val);
-       local64_set(&event->hw.prev_count, val);
-       local64_set(&event->hw.period_left, left);
+       perf_pmu_disable(event->pmu);
+
+       event->hw.state = 0;
+       left = local64_read(&event->hw.period_left);
+       write_pmc(event->hw.idx, left);
+
        perf_event_update_userpage(event);
-       perf_enable();
+       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
 }
 
-static struct pmu fsl_emb_pmu = {
-       .enable         = fsl_emb_pmu_enable,
-       .disable        = fsl_emb_pmu_disable,
-       .read           = fsl_emb_pmu_read,
-       .unthrottle     = fsl_emb_pmu_unthrottle,
-};
+static void fsl_emb_pmu_stop(struct perf_event *event, int ef_flags)
+{
+       unsigned long flags;
+
+       if (event->hw.idx < 0 || !event->hw.sample_period)
+               return;
+
+       if (event->hw.state & PERF_HES_STOPPED)
+               return;
+
+       local_irq_save(flags);
+       perf_pmu_disable(event->pmu);
+
+       fsl_emb_pmu_read(event);
+       event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
+       write_pmc(event->hw.idx, 0);
+
+       perf_event_update_userpage(event);
+       perf_pmu_enable(event->pmu);
+       local_irq_restore(flags);
+}
 
 /*
  * Release the PMU if this is the last perf_event.
@@ -428,7 +453,7 @@ static int hw_perf_cache_event(u64 config, u64 *eventp)
        return 0;
 }
 
-const struct pmu *hw_perf_event_init(struct perf_event *event)
+static int fsl_emb_pmu_event_init(struct perf_event *event)
 {
        u64 ev;
        struct perf_event *events[MAX_HWEVENTS];
@@ -441,14 +466,14 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
        case PERF_TYPE_HARDWARE:
                ev = event->attr.config;
                if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
-                       return ERR_PTR(-EOPNOTSUPP);
+                       return -EOPNOTSUPP;
                ev = ppmu->generic_events[ev];
                break;
 
        case PERF_TYPE_HW_CACHE:
                err = hw_perf_cache_event(event->attr.config, &ev);
                if (err)
-                       return ERR_PTR(err);
+                       return err;
                break;
 
        case PERF_TYPE_RAW:
@@ -456,12 +481,12 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
                break;
 
        default:
-               return ERR_PTR(-EINVAL);
+               return -ENOENT;
        }
 
        event->hw.config = ppmu->xlate_event(ev);
        if (!(event->hw.config & FSL_EMB_EVENT_VALID))
-               return ERR_PTR(-EINVAL);
+               return -EINVAL;
 
        /*
         * If this is in a group, check if it can go on with all the
@@ -473,7 +498,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
                n = collect_events(event->group_leader,
                                   ppmu->n_counter - 1, events);
                if (n < 0)
-                       return ERR_PTR(-EINVAL);
+                       return -EINVAL;
        }
 
        if (event->hw.config & FSL_EMB_EVENT_RESTRICTED) {
@@ -484,7 +509,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
                }
 
                if (num_restricted >= ppmu->n_restricted)
-                       return ERR_PTR(-EINVAL);
+                       return -EINVAL;
        }
 
        event->hw.idx = -1;
@@ -497,7 +522,7 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
        if (event->attr.exclude_kernel)
                event->hw.config_base |= PMLCA_FCS;
        if (event->attr.exclude_idle)
-               return ERR_PTR(-ENOTSUPP);
+               return -ENOTSUPP;
 
        event->hw.last_period = event->hw.sample_period;
        local64_set(&event->hw.period_left, event->hw.last_period);
@@ -523,11 +548,20 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
        }
        event->destroy = hw_perf_event_destroy;
 
-       if (err)
-               return ERR_PTR(err);
-       return &fsl_emb_pmu;
+       return err;
 }
 
+static struct pmu fsl_emb_pmu = {
+       .pmu_enable     = fsl_emb_pmu_enable,
+       .pmu_disable    = fsl_emb_pmu_disable,
+       .event_init     = fsl_emb_pmu_event_init,
+       .add            = fsl_emb_pmu_add,
+       .del            = fsl_emb_pmu_del,
+       .start          = fsl_emb_pmu_start,
+       .stop           = fsl_emb_pmu_stop,
+       .read           = fsl_emb_pmu_read,
+};
+
 /*
  * A counter has overflowed; update its count and record
  * things if requested.  Note that interrupts are hard-disabled
@@ -540,6 +574,11 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
        s64 prev, delta, left;
        int record = 0;
 
+       if (event->hw.state & PERF_HES_STOPPED) {
+               write_pmc(event->hw.idx, 0);
+               return;
+       }
+
        /* we don't have to worry about interrupts here */
        prev = local64_read(&event->hw.prev_count);
        delta = (val - prev) & 0xfffffffful;
@@ -562,6 +601,11 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
                        val = 0x80000000LL - left;
        }
 
+       write_pmc(event->hw.idx, val);
+       local64_set(&event->hw.prev_count, val);
+       local64_set(&event->hw.period_left, left);
+       perf_event_update_userpage(event);
+
        /*
         * Finally record data if requested.
         */
@@ -571,23 +615,9 @@ static void record_and_restart(struct perf_event *event, unsigned long val,
                perf_sample_data_init(&data, 0);
                data.period = event->hw.last_period;
 
-               if (perf_event_overflow(event, nmi, &data, regs)) {
-                       /*
-                        * Interrupts are coming too fast - throttle them
-                        * by setting the event to 0, so it will be
-                        * at least 2^30 cycles until the next interrupt
-                        * (assuming each event counts at most 2 counts
-                        * per cycle).
-                        */
-                       val = 0;
-                       left = ~0ULL >> 1;
-               }
+               if (perf_event_overflow(event, nmi, &data, regs))
+                       fsl_emb_pmu_stop(event, 0);
        }
-
-       write_pmc(event->hw.idx, val);
-       local64_set(&event->hw.prev_count, val);
-       local64_set(&event->hw.period_left, left);
-       perf_event_update_userpage(event);
 }
 
 static void perf_event_interrupt(struct pt_regs *regs)
@@ -651,5 +681,7 @@ int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu)
        pr_info("%s performance monitor hardware support registered\n",
                pmu->name);
 
+       perf_pmu_register(&fsl_emb_pmu);
+
        return 0;
 }
index 8eff48e20dba8ae056f9f4469642a5cdc453aefc..3fee685de4df49e01a3a85ff069f3d409354c924 100644 (file)
@@ -169,9 +169,11 @@ static int p970_marked_instr_event(u64 event)
        switch (unit) {
        case PM_VPU:
                mask = 0x4c;            /* byte 0 bits 2,3,6 */
+               break;
        case PM_LSU0:
                /* byte 2 bits 0,2,3,4,6; all of byte 1 */
                mask = 0x085dff00;
+               break;
        case PM_LSU1L:
                mask = 0x50 << 24;      /* byte 3 bits 4,6 */
                break;
index b1c648a36b03cbc2d08104b30ccd21e14bf70644..84906d3fc8607befb6e2abca027480f12120d17d 100644 (file)
@@ -517,7 +517,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
 
        account_system_vtime(current);
        account_process_vtime(current);
-       calculate_steal_time();
 
        /*
         * We can't take a PMU exception inside _switch() since there is a
@@ -1298,14 +1297,3 @@ unsigned long randomize_et_dyn(unsigned long base)
 
        return ret;
 }
-
-#ifdef CONFIG_SMP
-int arch_sd_sibling_asym_packing(void)
-{
-       if (cpu_has_feature(CPU_FTR_ASYM_SMT)) {
-               printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
-               return SD_ASYM_PACKING;
-       }
-       return 0;
-}
-#endif
index fed9bf6187d1a514e88677b144c5ad1273be8505..c3c6a88575441a5d68c75705a1ac68e0d130a5f7 100644 (file)
@@ -66,6 +66,7 @@
 int __initdata iommu_is_off;
 int __initdata iommu_force_on;
 unsigned long tce_alloc_start, tce_alloc_end;
+u64 ppc64_rma_size;
 #endif
 
 static int __init early_parse_mem(char *p)
@@ -98,7 +99,7 @@ static void __init move_device_tree(void)
 
        if ((memory_limit && (start + size) > memory_limit) ||
                        overlaps_crashkernel(start, size)) {
-               p = __va(memblock_alloc_base(size, PAGE_SIZE, memblock.rmo_size));
+               p = __va(memblock_alloc(size, PAGE_SIZE));
                memcpy(p, initial_boot_params, size);
                initial_boot_params = (struct boot_param_header *)p;
                DBG("Moved device tree to 0x%p\n", p);
@@ -492,7 +493,7 @@ static int __init early_init_dt_scan_memory_ppc(unsigned long node,
 
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
-#if defined(CONFIG_PPC64)
+#ifdef CONFIG_PPC64
        if (iommu_is_off) {
                if (base >= 0x80000000ul)
                        return;
@@ -501,9 +502,13 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
        }
 #endif
 
-       memblock_add(base, size);
-
+       /* First MEMBLOCK added, do some special initializations */
+       if (memstart_addr == ~(phys_addr_t)0)
+               setup_initial_memory_limit(base, size);
        memstart_addr = min((u64)memstart_addr, base);
+
+       /* Add the chunk to the MEMBLOCK list */
+       memblock_add(base, size);
 }
 
 u64 __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
@@ -655,7 +660,6 @@ static void __init phyp_dump_reserve_mem(void)
 static inline void __init phyp_dump_reserve_mem(void) {}
 #endif /* CONFIG_PHYP_DUMP  && CONFIG_PPC_RTAS */
 
-
 void __init early_init_devtree(void *params)
 {
        phys_addr_t limit;
@@ -683,6 +687,7 @@ void __init early_init_devtree(void *params)
 
        /* Scan memory nodes and rebuild MEMBLOCKs */
        memblock_init();
+
        of_scan_flat_dt(early_init_dt_scan_root, NULL);
        of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL);
 
index 11f3cd9c832f6c25fc97b4666fda60eeaaf8e1bd..286d9783d93f3ed2806036e14b5b6690d159865a 100644 (file)
@@ -1681,7 +1681,7 @@ long do_syscall_trace_enter(struct pt_regs *regs)
 
        if (unlikely(current->audit_context)) {
 #ifdef CONFIG_PPC64
-               if (!test_thread_flag(TIF_32BIT))
+               if (!is_32bit_task())
                        audit_syscall_entry(AUDIT_ARCH_PPC64,
                                            regs->gpr[0],
                                            regs->gpr[3], regs->gpr[4],
index 41048de3c6c396d84826e68a12edc639f86b0587..8fe8bc61c10a5543a2cd1553fbe613a096054586 100644 (file)
@@ -805,7 +805,7 @@ static void rtas_percpu_suspend_me(void *info)
        __rtas_suspend_cpu((struct rtas_suspend_me_data *)info, 1);
 }
 
-static int rtas_ibm_suspend_me(struct rtas_args *args)
+int rtas_ibm_suspend_me(struct rtas_args *args)
 {
        long state;
        long rc;
@@ -855,7 +855,7 @@ static int rtas_ibm_suspend_me(struct rtas_args *args)
        return atomic_read(&data.error);
 }
 #else /* CONFIG_PPC_PSERIES */
-static int rtas_ibm_suspend_me(struct rtas_args *args)
+int rtas_ibm_suspend_me(struct rtas_args *args)
 {
        return -ENOSYS;
 }
@@ -969,7 +969,7 @@ void __init rtas_initialize(void)
         */
 #ifdef CONFIG_PPC64
        if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR)) {
-               rtas_region = min(memblock.rmo_size, RTAS_INSTANTIATE_MAX);
+               rtas_region = min(ppc64_rma_size, RTAS_INSTANTIATE_MAX);
                ibm_suspend_me_token = rtas_token("ibm,suspend-me");
        }
 #endif
index 93666f9cabf17fd6c0271332e9f4cb84ded8cd85..1d2fbc905303401c50bbd410da0118338cb05eb7 100644 (file)
@@ -46,7 +46,7 @@
 
 extern void bootx_init(unsigned long r4, unsigned long phys);
 
-int boot_cpuid;
+int boot_cpuid = -1;
 EXPORT_SYMBOL_GPL(boot_cpuid);
 int boot_cpuid_phys;
 
@@ -246,7 +246,7 @@ static void __init irqstack_early_init(void)
        unsigned int i;
 
        /* interrupt stacks must be in lowmem, we get that for free on ppc32
-        * as the memblock is limited to lowmem by MEMBLOCK_REAL_LIMIT */
+        * as the memblock is limited to lowmem by default */
        for_each_possible_cpu(i) {
                softirq_ctx[i] = (struct thread_info *)
                        __va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
index e72690ec9b87489af9e8d30a8e81ac84e03db229..2a178b0ebcdf8ea33ed67c8a4516b7ec0f1d9f26 100644 (file)
@@ -486,7 +486,7 @@ static void __init emergency_stack_init(void)
         * bringup, we need to get at them in real mode. This means they
         * must also be within the RMO region.
         */
-       limit = min(slb0_limit(), memblock.rmo_size);
+       limit = min(slb0_limit(), ppc64_rma_size);
 
        for_each_possible_cpu(i) {
                unsigned long sp;
index 0008bc58e826c53b29f9e689336388f16377eb77..68034bbf2e4f0affdeaa991a56b75482b6c3d615 100644 (file)
@@ -508,9 +508,6 @@ int __devinit start_secondary(void *unused)
        if (smp_ops->take_timebase)
                smp_ops->take_timebase();
 
-       if (system_state > SYSTEM_BOOTING)
-               snapshot_timebase();
-
        secondary_cpu_time_init();
 
        ipi_call_lock();
@@ -575,11 +572,18 @@ void __init smp_cpus_done(unsigned int max_cpus)
 
        free_cpumask_var(old_mask);
 
-       snapshot_timebases();
-
        dump_numa_cpu_topology();
 }
 
+int arch_sd_sibling_asym_packing(void)
+{
+       if (cpu_has_feature(CPU_FTR_ASYM_SMT)) {
+               printk_once(KERN_INFO "Enabling Asymmetric SMT scheduling\n");
+               return SD_ASYM_PACKING;
+       }
+       return 0;
+}
+
 #ifdef CONFIG_HOTPLUG_CPU
 int __cpu_disable(void)
 {
index 8533b3b83f5d0e35b50fb39eefb663e6d81975b0..010406958d974a4d0275be31bbba90af2de5035a 100644 (file)
@@ -53,7 +53,7 @@
 #include <linux/posix-timers.h>
 #include <linux/irq.h>
 #include <linux/delay.h>
-#include <linux/perf_event.h>
+#include <linux/irq_work.h>
 #include <asm/trace.h>
 
 #include <asm/io.h>
@@ -161,10 +161,9 @@ extern struct timezone sys_tz;
 static long timezone_offset;
 
 unsigned long ppc_proc_freq;
-EXPORT_SYMBOL(ppc_proc_freq);
+EXPORT_SYMBOL_GPL(ppc_proc_freq);
 unsigned long ppc_tb_freq;
-
-static DEFINE_PER_CPU(u64, last_jiffy);
+EXPORT_SYMBOL_GPL(ppc_tb_freq);
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 /*
@@ -185,6 +184,8 @@ DEFINE_PER_CPU(unsigned long, cputime_scaled_last_delta);
 
 cputime_t cputime_one_jiffy;
 
+void (*dtl_consumer)(struct dtl_entry *, u64);
+
 static void calc_cputime_factors(void)
 {
        struct div_result res;
@@ -200,62 +201,153 @@ static void calc_cputime_factors(void)
 }
 
 /*
- * Read the PURR on systems that have it, otherwise the timebase.
+ * Read the SPURR on systems that have it, otherwise the PURR,
+ * or if that doesn't exist return the timebase value passed in.
  */
-static u64 read_purr(void)
+static u64 read_spurr(u64 tb)
 {
+       if (cpu_has_feature(CPU_FTR_SPURR))
+               return mfspr(SPRN_SPURR);
        if (cpu_has_feature(CPU_FTR_PURR))
                return mfspr(SPRN_PURR);
-       return mftb();
+       return tb;
 }
 
+#ifdef CONFIG_PPC_SPLPAR
+
 /*
- * Read the SPURR on systems that have it, otherwise the purr
+ * Scan the dispatch trace log and count up the stolen time.
+ * Should be called with interrupts disabled.
  */
-static u64 read_spurr(u64 purr)
+static u64 scan_dispatch_log(u64 stop_tb)
 {
-       /*
-        * cpus without PURR won't have a SPURR
-        * We already know the former when we use this, so tell gcc
-        */
-       if (cpu_has_feature(CPU_FTR_PURR) && cpu_has_feature(CPU_FTR_SPURR))
-               return mfspr(SPRN_SPURR);
-       return purr;
+       u64 i = local_paca->dtl_ridx;
+       struct dtl_entry *dtl = local_paca->dtl_curr;
+       struct dtl_entry *dtl_end = local_paca->dispatch_log_end;
+       struct lppaca *vpa = local_paca->lppaca_ptr;
+       u64 tb_delta;
+       u64 stolen = 0;
+       u64 dtb;
+
+       if (i == vpa->dtl_idx)
+               return 0;
+       while (i < vpa->dtl_idx) {
+               if (dtl_consumer)
+                       dtl_consumer(dtl, i);
+               dtb = dtl->timebase;
+               tb_delta = dtl->enqueue_to_dispatch_time +
+                       dtl->ready_to_enqueue_time;
+               barrier();
+               if (i + N_DISPATCH_LOG < vpa->dtl_idx) {
+                       /* buffer has overflowed */
+                       i = vpa->dtl_idx - N_DISPATCH_LOG;
+                       dtl = local_paca->dispatch_log + (i % N_DISPATCH_LOG);
+                       continue;
+               }
+               if (dtb > stop_tb)
+                       break;
+               stolen += tb_delta;
+               ++i;
+               ++dtl;
+               if (dtl == dtl_end)
+                       dtl = local_paca->dispatch_log;
+       }
+       local_paca->dtl_ridx = i;
+       local_paca->dtl_curr = dtl;
+       return stolen;
 }
 
+/*
+ * Accumulate stolen time by scanning the dispatch trace log.
+ * Called on entry from user mode.
+ */
+void accumulate_stolen_time(void)
+{
+       u64 sst, ust;
+
+       sst = scan_dispatch_log(get_paca()->starttime_user);
+       ust = scan_dispatch_log(get_paca()->starttime);
+       get_paca()->system_time -= sst;
+       get_paca()->user_time -= ust;
+       get_paca()->stolen_time += ust + sst;
+}
+
+static inline u64 calculate_stolen_time(u64 stop_tb)
+{
+       u64 stolen = 0;
+
+       if (get_paca()->dtl_ridx != get_paca()->lppaca_ptr->dtl_idx) {
+               stolen = scan_dispatch_log(stop_tb);
+               get_paca()->system_time -= stolen;
+       }
+
+       stolen += get_paca()->stolen_time;
+       get_paca()->stolen_time = 0;
+       return stolen;
+}
+
+#else /* CONFIG_PPC_SPLPAR */
+static inline u64 calculate_stolen_time(u64 stop_tb)
+{
+       return 0;
+}
+
+#endif /* CONFIG_PPC_SPLPAR */
+
 /*
  * Account time for a transition between system, hard irq
  * or soft irq state.
  */
 void account_system_vtime(struct task_struct *tsk)
 {
-       u64 now, nowscaled, delta, deltascaled, sys_time;
+       u64 now, nowscaled, delta, deltascaled;
        unsigned long flags;
+       u64 stolen, udelta, sys_scaled, user_scaled;
 
        local_irq_save(flags);
-       now = read_purr();
+       now = mftb();
        nowscaled = read_spurr(now);
-       delta = now - get_paca()->startpurr;
+       get_paca()->system_time += now - get_paca()->starttime;
+       get_paca()->starttime = now;
        deltascaled = nowscaled - get_paca()->startspurr;
-       get_paca()->startpurr = now;
        get_paca()->startspurr = nowscaled;
-       if (!in_interrupt()) {
-               /* deltascaled includes both user and system time.
-                * Hence scale it based on the purr ratio to estimate
-                * the system time */
-               sys_time = get_paca()->system_time;
-               if (get_paca()->user_time)
-                       deltascaled = deltascaled * sys_time /
-                            (sys_time + get_paca()->user_time);
-               delta += sys_time;
-               get_paca()->system_time = 0;
+
+       stolen = calculate_stolen_time(now);
+
+       delta = get_paca()->system_time;
+       get_paca()->system_time = 0;
+       udelta = get_paca()->user_time - get_paca()->utime_sspurr;
+       get_paca()->utime_sspurr = get_paca()->user_time;
+
+       /*
+        * Because we don't read the SPURR on every kernel entry/exit,
+        * deltascaled includes both user and system SPURR ticks.
+        * Apportion these ticks to system SPURR ticks and user
+        * SPURR ticks in the same ratio as the system time (delta)
+        * and user time (udelta) values obtained from the timebase
+        * over the same interval.  The system ticks get accounted here;
+        * the user ticks get saved up in paca->user_time_scaled to be
+        * used by account_process_tick.
+        */
+       sys_scaled = delta;
+       user_scaled = udelta;
+       if (deltascaled != delta + udelta) {
+               if (udelta) {
+                       sys_scaled = deltascaled * delta / (delta + udelta);
+                       user_scaled = deltascaled - sys_scaled;
+               } else {
+                       sys_scaled = deltascaled;
+               }
+       }
+       get_paca()->user_time_scaled += user_scaled;
+
+       if (in_irq() || idle_task(smp_processor_id()) != tsk) {
+               account_system_time(tsk, 0, delta, sys_scaled);
+               if (stolen)
+                       account_steal_time(stolen);
+       } else {
+               account_idle_time(delta + stolen);
        }
-       if (in_irq() || idle_task(smp_processor_id()) != tsk)
-               account_system_time(tsk, 0, delta, deltascaled);
-       else
-               account_idle_time(delta);
-       __get_cpu_var(cputime_last_delta) = delta;
-       __get_cpu_var(cputime_scaled_last_delta) = deltascaled;
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(account_system_vtime);
@@ -265,125 +357,26 @@ EXPORT_SYMBOL_GPL(account_system_vtime);
  * by the exception entry and exit code to the generic process
  * user and system time records.
  * Must be called with interrupts disabled.
+ * Assumes that account_system_vtime() has been called recently
+ * (i.e. since the last entry from usermode) so that
+ * get_paca()->user_time_scaled is up to date.
  */
 void account_process_tick(struct task_struct *tsk, int user_tick)
 {
        cputime_t utime, utimescaled;
 
        utime = get_paca()->user_time;
+       utimescaled = get_paca()->user_time_scaled;
        get_paca()->user_time = 0;
-       utimescaled = cputime_to_scaled(utime);
+       get_paca()->user_time_scaled = 0;
+       get_paca()->utime_sspurr = 0;
        account_user_time(tsk, utime, utimescaled);
 }
 
-/*
- * Stuff for accounting stolen time.
- */
-struct cpu_purr_data {
-       int     initialized;                    /* thread is running */
-       u64     tb;                     /* last TB value read */
-       u64     purr;                   /* last PURR value read */
-       u64     spurr;                  /* last SPURR value read */
-};
-
-/*
- * Each entry in the cpu_purr_data array is manipulated only by its
- * "owner" cpu -- usually in the timer interrupt but also occasionally
- * in process context for cpu online.  As long as cpus do not touch
- * each others' cpu_purr_data, disabling local interrupts is
- * sufficient to serialize accesses.
- */
-static DEFINE_PER_CPU(struct cpu_purr_data, cpu_purr_data);
-
-static void snapshot_tb_and_purr(void *data)
-{
-       unsigned long flags;
-       struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data);
-
-       local_irq_save(flags);
-       p->tb = get_tb_or_rtc();
-       p->purr = mfspr(SPRN_PURR);
-       wmb();
-       p->initialized = 1;
-       local_irq_restore(flags);
-}
-
-/*
- * Called during boot when all cpus have come up.
- */
-void snapshot_timebases(void)
-{
-       if (!cpu_has_feature(CPU_FTR_PURR))
-               return;
-       on_each_cpu(snapshot_tb_and_purr, NULL, 1);
-}
-
-/*
- * Must be called with interrupts disabled.
- */
-void calculate_steal_time(void)
-{
-       u64 tb, purr;
-       s64 stolen;
-       struct cpu_purr_data *pme;
-
-       pme = &__get_cpu_var(cpu_purr_data);
-       if (!pme->initialized)
-               return;         /* !CPU_FTR_PURR or early in early boot */
-       tb = mftb();
-       purr = mfspr(SPRN_PURR);
-       stolen = (tb - pme->tb) - (purr - pme->purr);
-       if (stolen > 0) {
-               if (idle_task(smp_processor_id()) != current)
-                       account_steal_time(stolen);
-               else
-                       account_idle_time(stolen);
-       }
-       pme->tb = tb;
-       pme->purr = purr;
-}
-
-#ifdef CONFIG_PPC_SPLPAR
-/*
- * Must be called before the cpu is added to the online map when
- * a cpu is being brought up at runtime.
- */
-static void snapshot_purr(void)
-{
-       struct cpu_purr_data *pme;
-       unsigned long flags;
-
-       if (!cpu_has_feature(CPU_FTR_PURR))
-               return;
-       local_irq_save(flags);
-       pme = &__get_cpu_var(cpu_purr_data);
-       pme->tb = mftb();
-       pme->purr = mfspr(SPRN_PURR);
-       pme->initialized = 1;
-       local_irq_restore(flags);
-}
-
-#endif /* CONFIG_PPC_SPLPAR */
-
 #else /* ! CONFIG_VIRT_CPU_ACCOUNTING */
 #define calc_cputime_factors()
-#define calculate_steal_time()         do { } while (0)
 #endif
 
-#if !(defined(CONFIG_VIRT_CPU_ACCOUNTING) && defined(CONFIG_PPC_SPLPAR))
-#define snapshot_purr()                        do { } while (0)
-#endif
-
-/*
- * Called when a cpu comes up after the system has finished booting,
- * i.e. as a result of a hotplug cpu action.
- */
-void snapshot_timebase(void)
-{
-       __get_cpu_var(last_jiffy) = get_tb_or_rtc();
-       snapshot_purr();
-}
-
 void __delay(unsigned long loops)
 {
        unsigned long start;
@@ -493,60 +486,60 @@ void __init iSeries_time_init_early(void)
 }
 #endif /* CONFIG_PPC_ISERIES */
 
-#ifdef CONFIG_PERF_EVENTS
+#ifdef CONFIG_IRQ_WORK
 
 /*
  * 64-bit uses a byte in the PACA, 32-bit uses a per-cpu variable...
  */
 #ifdef CONFIG_PPC64
-static inline unsigned long test_perf_event_pending(void)
+static inline unsigned long test_irq_work_pending(void)
 {
        unsigned long x;
 
        asm volatile("lbz %0,%1(13)"
                : "=r" (x)
-               : "i" (offsetof(struct paca_struct, perf_event_pending)));
+               : "i" (offsetof(struct paca_struct, irq_work_pending)));
        return x;
 }
 
-static inline void set_perf_event_pending_flag(void)
+static inline void set_irq_work_pending_flag(void)
 {
        asm volatile("stb %0,%1(13)" : :
                "r" (1),
-               "i" (offsetof(struct paca_struct, perf_event_pending)));
+               "i" (offsetof(struct paca_struct, irq_work_pending)));
 }
 
-static inline void clear_perf_event_pending(void)
+static inline void clear_irq_work_pending(void)
 {
        asm volatile("stb %0,%1(13)" : :
                "r" (0),
-               "i" (offsetof(struct paca_struct, perf_event_pending)));
+               "i" (offsetof(struct paca_struct, irq_work_pending)));
 }
 
 #else /* 32-bit */
 
-DEFINE_PER_CPU(u8, perf_event_pending);
+DEFINE_PER_CPU(u8, irq_work_pending);
 
-#define set_perf_event_pending_flag()  __get_cpu_var(perf_event_pending) = 1
-#define test_perf_event_pending()      __get_cpu_var(perf_event_pending)
-#define clear_perf_event_pending()     __get_cpu_var(perf_event_pending) = 0
+#define set_irq_work_pending_flag()    __get_cpu_var(irq_work_pending) = 1
+#define test_irq_work_pending()                __get_cpu_var(irq_work_pending)
+#define clear_irq_work_pending()       __get_cpu_var(irq_work_pending) = 0
 
 #endif /* 32 vs 64 bit */
 
-void set_perf_event_pending(void)
+void set_irq_work_pending(void)
 {
        preempt_disable();
-       set_perf_event_pending_flag();
+       set_irq_work_pending_flag();
        set_dec(1);
        preempt_enable();
 }
 
-#else  /* CONFIG_PERF_EVENTS */
+#else  /* CONFIG_IRQ_WORK */
 
-#define test_perf_event_pending()      0
-#define clear_perf_event_pending()
+#define test_irq_work_pending()        0
+#define clear_irq_work_pending()
 
-#endif /* CONFIG_PERF_EVENTS */
+#endif /* CONFIG_IRQ_WORK */
 
 /*
  * For iSeries shared processors, we have to let the hypervisor
@@ -585,11 +578,9 @@ void timer_interrupt(struct pt_regs * regs)
        old_regs = set_irq_regs(regs);
        irq_enter();
 
-       calculate_steal_time();
-
-       if (test_perf_event_pending()) {
-               clear_perf_event_pending();
-               perf_event_do_pending();
+       if (test_irq_work_pending()) {
+               clear_irq_work_pending();
+               irq_work_run();
        }
 
 #ifdef CONFIG_PPC_ISERIES
index a45a63c3a0c74bf4f8665afe6073ae13938754c9..1b2cdc8eec901fce78e21d279ca054684bec158c 100644 (file)
@@ -538,6 +538,11 @@ int machine_check_e500(struct pt_regs *regs)
 
        return 0;
 }
+
+int machine_check_generic(struct pt_regs *regs)
+{
+       return 0;
+}
 #elif defined(CONFIG_E200)
 int machine_check_e200(struct pt_regs *regs)
 {
index 13002fe206e7ce16ed79f5ad31e5aec58bc329cb..fd8728729abc9cb671d65bd8cb625fbaf22de12c 100644 (file)
@@ -159,7 +159,7 @@ static void dump_vdso_pages(struct vm_area_struct * vma)
 {
        int i;
 
-       if (!vma || test_thread_flag(TIF_32BIT)) {
+       if (!vma || is_32bit_task()) {
                printk("vDSO32 @ %016lx:\n", (unsigned long)vdso32_kbase);
                for (i=0; i<vdso32_pages; i++) {
                        struct page *pg = virt_to_page(vdso32_kbase +
@@ -170,7 +170,7 @@ static void dump_vdso_pages(struct vm_area_struct * vma)
                        dump_one_vdso_page(pg, upg);
                }
        }
-       if (!vma || !test_thread_flag(TIF_32BIT)) {
+       if (!vma || !is_32bit_task()) {
                printk("vDSO64 @ %016lx:\n", (unsigned long)vdso64_kbase);
                for (i=0; i<vdso64_pages; i++) {
                        struct page *pg = virt_to_page(vdso64_kbase +
@@ -200,7 +200,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
                return 0;
 
 #ifdef CONFIG_PPC64
-       if (test_thread_flag(TIF_32BIT)) {
+       if (is_32bit_task()) {
                vdso_pagelist = vdso32_pagelist;
                vdso_pages = vdso32_pages;
                vdso_base = VDSO32_MBASE;
index 51ead52141bd083774ed3ed13d8c71dc831f0f23..9a7946c417387fdd0c56b4c3dd1010c4b642312f 100644 (file)
@@ -14,10 +14,10 @@ obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
 
 GCOV_PROFILE := n
 
-EXTRA_CFLAGS := -shared -fno-common -fno-builtin
-EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
+ccflags-y := -shared -fno-common -fno-builtin
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
                $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
-EXTRA_AFLAGS := -D__VDSO32__ -s
+asflags-y := -D__VDSO32__ -s
 
 obj-y += vdso32_wrapper.o
 extra-y += vdso32.lds
index 79da65d44a2a78a01bf11f2c0bb5b2003560ae6c..8c500d8622e4d8d7696099b684b0ad519c63a8a4 100644 (file)
@@ -9,10 +9,10 @@ obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
 
 GCOV_PROFILE := n
 
-EXTRA_CFLAGS := -shared -fno-common -fno-builtin
-EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
+ccflags-y := -shared -fno-common -fno-builtin
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
                $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
-EXTRA_AFLAGS := -D__VDSO64__ -s
+asflags-y := -D__VDSO64__ -s
 
 obj-y += vdso64_wrapper.o
 extra-y += vdso64.lds
index fa3469ddaef8d010bca8974765c9c656dfa06635..d692989a4318273c06fc1fdc024448afd15d322d 100644 (file)
@@ -1184,7 +1184,12 @@ EXPORT_SYMBOL(vio_unregister_driver);
 /* vio_dev refcount hit 0 */
 static void __devinit vio_dev_release(struct device *dev)
 {
-       /* XXX should free TCE table */
+       struct iommu_table *tbl = get_iommu_table_base(dev);
+
+       /* iSeries uses a common table for all vio devices */
+       if (!firmware_has_feature(FW_FEATURE_ISERIES) && tbl)
+               iommu_free_table(tbl, dev->of_node ?
+                       dev->of_node->full_name : dev_name(dev));
        of_node_put(dev->of_node);
        kfree(to_vio_dev(dev));
 }
@@ -1254,8 +1259,7 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
        if (device_register(&viodev->dev)) {
                printk(KERN_ERR "%s: failed to register device %s\n",
                                __func__, dev_name(&viodev->dev));
-               /* XXX free TCE table */
-               kfree(viodev);
+               put_device(&viodev->dev);
                return NULL;
        }
 
index d45c818a384c2281f0c8689272bcb130c18de98a..4d6863823f695ddabc15e6adc2e3c1fd62b82074 100644 (file)
@@ -4,7 +4,7 @@
 
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
-EXTRA_CFLAGS += -Ivirt/kvm -Iarch/powerpc/kvm
+ccflags-y := -Ivirt/kvm -Iarch/powerpc/kvm
 
 common-objs-y = $(addprefix ../../../virt/kvm/, kvm_main.o coalesced_mmio.o)
 
index 474f2e24050a03a3d89ca85a7b34993d687a61f3..35a701f3ece479e5eb76849147e27c9bff22ea39 100644 (file)
 
 static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt)
 {
-       kvm_cvt_df(&vcpu->arch.fpr[rt], &vcpu->arch.qpr[rt], &vcpu->arch.fpscr);
+       kvm_cvt_df(&vcpu->arch.fpr[rt], &vcpu->arch.qpr[rt]);
 }
 
 static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
@@ -204,7 +204,7 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
        /* put in registers */
        switch (ls_type) {
        case FPU_LS_SINGLE:
-               kvm_cvt_fd((u32*)tmp, &vcpu->arch.fpr[rs], &vcpu->arch.fpscr);
+               kvm_cvt_fd((u32*)tmp, &vcpu->arch.fpr[rs]);
                vcpu->arch.qpr[rs] = *((u32*)tmp);
                break;
        case FPU_LS_DOUBLE:
@@ -230,7 +230,7 @@ static int kvmppc_emulate_fpr_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
        switch (ls_type) {
        case FPU_LS_SINGLE:
-               kvm_cvt_df(&vcpu->arch.fpr[rs], (u32*)tmp, &vcpu->arch.fpscr);
+               kvm_cvt_df(&vcpu->arch.fpr[rs], (u32*)tmp);
                val = *((u32*)tmp);
                len = sizeof(u32);
                break;
@@ -296,7 +296,7 @@ static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
        emulated = EMULATE_DONE;
 
        /* put in registers */
-       kvm_cvt_fd(&tmp[0], &vcpu->arch.fpr[rs], &vcpu->arch.fpscr);
+       kvm_cvt_fd(&tmp[0], &vcpu->arch.fpr[rs]);
        vcpu->arch.qpr[rs] = tmp[1];
 
        dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0],
@@ -314,7 +314,7 @@ static int kvmppc_emulate_psq_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
        u32 tmp[2];
        int len = w ? sizeof(u32) : sizeof(u64);
 
-       kvm_cvt_df(&vcpu->arch.fpr[rs], &tmp[0], &vcpu->arch.fpscr);
+       kvm_cvt_df(&vcpu->arch.fpr[rs], &tmp[0]);
        tmp[1] = vcpu->arch.qpr[rs];
 
        r = kvmppc_st(vcpu, &addr, len, tmp, true);
@@ -516,9 +516,9 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
        WARN_ON(rc);
 
        /* PS0 */
-       kvm_cvt_df(&fpr[reg_in1], &ps0_in1, &vcpu->arch.fpscr);
-       kvm_cvt_df(&fpr[reg_in2], &ps0_in2, &vcpu->arch.fpscr);
-       kvm_cvt_df(&fpr[reg_in3], &ps0_in3, &vcpu->arch.fpscr);
+       kvm_cvt_df(&fpr[reg_in1], &ps0_in1);
+       kvm_cvt_df(&fpr[reg_in2], &ps0_in2);
+       kvm_cvt_df(&fpr[reg_in3], &ps0_in3);
 
        if (scalar & SCALAR_LOW)
                ps0_in2 = qpr[reg_in2];
@@ -529,7 +529,7 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
                          ps0_in1, ps0_in2, ps0_in3, ps0_out);
 
        if (!(scalar & SCALAR_NO_PS0))
-               kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
+               kvm_cvt_fd(&ps0_out, &fpr[reg_out]);
 
        /* PS1 */
        ps1_in1 = qpr[reg_in1];
@@ -566,12 +566,12 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
        WARN_ON(rc);
 
        /* PS0 */
-       kvm_cvt_df(&fpr[reg_in1], &ps0_in1, &vcpu->arch.fpscr);
+       kvm_cvt_df(&fpr[reg_in1], &ps0_in1);
 
        if (scalar & SCALAR_LOW)
                ps0_in2 = qpr[reg_in2];
        else
-               kvm_cvt_df(&fpr[reg_in2], &ps0_in2, &vcpu->arch.fpscr);
+               kvm_cvt_df(&fpr[reg_in2], &ps0_in2);
 
        func(&vcpu->arch.fpscr, &ps0_out, &ps0_in1, &ps0_in2);
 
@@ -579,7 +579,7 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
                dprintk(KERN_INFO "PS2 ps0 -> f(0x%x, 0x%x) = 0x%x\n",
                                  ps0_in1, ps0_in2, ps0_out);
 
-               kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
+               kvm_cvt_fd(&ps0_out, &fpr[reg_out]);
        }
 
        /* PS1 */
@@ -615,13 +615,13 @@ static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc,
        WARN_ON(rc);
 
        /* PS0 */
-       kvm_cvt_df(&fpr[reg_in], &ps0_in, &vcpu->arch.fpscr);
+       kvm_cvt_df(&fpr[reg_in], &ps0_in);
        func(&vcpu->arch.fpscr, &ps0_out, &ps0_in);
 
        dprintk(KERN_INFO "PS1 ps0 -> f(0x%x) = 0x%x\n",
                          ps0_in, ps0_out);
 
-       kvm_cvt_fd(&ps0_out, &fpr[reg_out], &vcpu->arch.fpscr);
+       kvm_cvt_fd(&ps0_out, &fpr[reg_out]);
 
        /* PS1 */
        ps1_in = qpr[reg_in];
@@ -671,7 +671,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
 #ifdef DEBUG
        for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
                u32 f;
-               kvm_cvt_df(&vcpu->arch.fpr[i], &f, &vcpu->arch.fpscr);
+               kvm_cvt_df(&vcpu->arch.fpr[i], &f);
                dprintk(KERN_INFO "FPR[%d] = 0x%x / 0x%llx    QPR[%d] = 0x%x\n",
                        i, f, vcpu->arch.fpr[i], i, vcpu->arch.qpr[i]);
        }
@@ -796,8 +796,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_ra];
                        /* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
                        kvm_cvt_df(&vcpu->arch.fpr[ax_rb],
-                                  &vcpu->arch.qpr[ax_rd],
-                                  &vcpu->arch.fpscr);
+                                  &vcpu->arch.qpr[ax_rd]);
                        break;
                case OP_4X_PS_MERGE01:
                        WARN_ON(rcomp);
@@ -808,19 +807,16 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        WARN_ON(rcomp);
                        /* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
                        kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
-                                  &vcpu->arch.fpr[ax_rd],
-                                  &vcpu->arch.fpscr);
+                                  &vcpu->arch.fpr[ax_rd]);
                        /* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
                        kvm_cvt_df(&vcpu->arch.fpr[ax_rb],
-                                  &vcpu->arch.qpr[ax_rd],
-                                  &vcpu->arch.fpscr);
+                                  &vcpu->arch.qpr[ax_rd]);
                        break;
                case OP_4X_PS_MERGE11:
                        WARN_ON(rcomp);
                        /* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
                        kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
-                                  &vcpu->arch.fpr[ax_rd],
-                                  &vcpu->arch.fpscr);
+                                  &vcpu->arch.fpr[ax_rd]);
                        vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
                        break;
                }
@@ -1255,7 +1251,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
 #ifdef DEBUG
        for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
                u32 f;
-               kvm_cvt_df(&vcpu->arch.fpr[i], &f, &vcpu->arch.fpscr);
+               kvm_cvt_df(&vcpu->arch.fpr[i], &f);
                dprintk(KERN_INFO "FPR[%d] = 0x%x\n", i, f);
        }
 #endif
index 4568ec386c2aa858afe0a6024adfb476cac18c33..b83ba581fd8edb13e4d552ec8b6c9f5c6eb73076 100644 (file)
@@ -145,7 +145,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
        /* this default type might be overwritten by subcategories */
        kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
 
-       pr_debug(KERN_INFO "Emulating opcode %d / %d\n", get_op(inst), get_xop(inst));
+       pr_debug("Emulating opcode %d / %d\n", get_op(inst), get_xop(inst));
 
        switch (get_op(inst)) {
        case OP_TRAP:
@@ -275,7 +275,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        {
                                u64 jd = get_tb() - vcpu->arch.dec_jiffies;
                                kvmppc_set_gpr(vcpu, rt, vcpu->arch.dec - jd);
-                               pr_debug(KERN_INFO "mfDEC: %x - %llx = %lx\n",
+                               pr_debug("mfDEC: %x - %llx = %lx\n",
                                         vcpu->arch.dec, jd,
                                         kvmppc_get_gpr(vcpu, rt));
                                break;
index cb34bbe1611365c4761ebd1d20c58e8f2997ae12..bf68d597549e4eaa72cb0cdeb7d57043b27c17eb 100644 (file)
@@ -273,19 +273,11 @@ FPD_THREE_IN(fnmsub)
 FPD_THREE_IN(fnmadd)
 
 _GLOBAL(kvm_cvt_fd)
-       lfd     0,0(r5)                 /* load up fpscr value */
-       MTFSF_L(0)
        lfs     0,0(r3)
        stfd    0,0(r4)
-       mffs    0
-       stfd    0,0(r5)                 /* save new fpscr value */
        blr
 
 _GLOBAL(kvm_cvt_df)
-       lfd     0,0(r5)                 /* load up fpscr value */
-       MTFSF_L(0)
        lfd     0,0(r3)
        stfs    0,0(r4)
-       mffs    0
-       stfd    0,0(r5)                 /* save new fpscr value */
        blr
index 5bb89c828070173a3b20496435b65c3928f18515..889f2bc106dd86af018b894dab475d79638f2694 100644 (file)
@@ -4,9 +4,7 @@
 
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
-ifeq ($(CONFIG_PPC64),y)
-EXTRA_CFLAGS           += -mno-minimal-toc
-endif
+ccflags-$(CONFIG_PPC64)        := -mno-minimal-toc
 
 CFLAGS_REMOVE_code-patching.o = -pg
 CFLAGS_REMOVE_feature-fixups.o = -pg
@@ -17,7 +15,8 @@ obj-$(CONFIG_PPC32)   += div64.o copy_32.o
 obj-$(CONFIG_HAS_IOMEM)        += devres.o
 
 obj-$(CONFIG_PPC64)    += copypage_64.o copyuser_64.o \
-                          memcpy_64.o usercopy_64.o mem_64.o string.o
+                          memcpy_64.o usercopy_64.o mem_64.o string.o \
+                          checksum_wrappers_64.o
 obj-$(CONFIG_XMON)     += sstep.o ldstfp.o
 obj-$(CONFIG_KPROBES)  += sstep.o ldstfp.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += sstep.o ldstfp.o
index ef96c6c58efc6644d68ac534fb1f4d40253aa605..18245af38aea7f747bd034dd5892c300ce73111c 100644 (file)
@@ -65,165 +65,393 @@ _GLOBAL(csum_tcpudp_magic)
        srwi    r3,r3,16
        blr
 
+#define STACKFRAMESIZE 256
+#define STK_REG(i)     (112 + ((i)-14)*8)
+
 /*
  * Computes the checksum of a memory block at buff, length len,
  * and adds in "sum" (32-bit).
  *
- * This code assumes at least halfword alignment, though the length
- * can be any number of bytes.  The sum is accumulated in r5.
- *
  * csum_partial(r3=buff, r4=len, r5=sum)
  */
 _GLOBAL(csum_partial)
-        subi   r3,r3,8         /* we'll offset by 8 for the loads */
-        srdi.  r6,r4,3         /* divide by 8 for doubleword count */
-        addic   r5,r5,0         /* clear carry */
-        beq    3f              /* if we're doing < 8 bytes */
-        andi.  r0,r3,2         /* aligned on a word boundary already? */
-        beq+   1f
-        lhz     r6,8(r3)        /* do 2 bytes to get aligned */
-        addi    r3,r3,2
-        subi    r4,r4,2
-        addc    r5,r5,r6
-        srdi.   r6,r4,3         /* recompute number of doublewords */
-        beq     3f              /* any left? */
-1:      mtctr   r6
-2:      ldu     r6,8(r3)        /* main sum loop */
-        adde    r5,r5,r6
-        bdnz    2b
-        andi.  r4,r4,7         /* compute bytes left to sum after doublewords */
-3:     cmpwi   0,r4,4          /* is at least a full word left? */
-       blt     4f
-       lwz     r6,8(r3)        /* sum this word */
+       addic   r0,r5,0                 /* clear carry */
+
+       srdi.   r6,r4,3                 /* less than 8 bytes? */
+       beq     .Lcsum_tail_word
+
+       /*
+        * If only halfword aligned, align to a double word. Since odd
+        * aligned addresses should be rare and they would require more
+        * work to calculate the correct checksum, we ignore that case
+        * and take the potential slowdown of unaligned loads.
+        */
+       rldicl. r6,r3,64-1,64-2         /* r6 = (r3 & 0x3) >> 1 */
+       beq     .Lcsum_aligned
+
+       li      r7,4
+       sub     r6,r7,r6
+       mtctr   r6
+
+1:
+       lhz     r6,0(r3)                /* align to doubleword */
+       subi    r4,r4,2
+       addi    r3,r3,2
+       adde    r0,r0,r6
+       bdnz    1b
+
+.Lcsum_aligned:
+       /*
+        * We unroll the loop such that each iteration is 64 bytes with an
+        * entry and exit limb of 64 bytes, meaning a minimum size of
+        * 128 bytes.
+        */
+       srdi.   r6,r4,7
+       beq     .Lcsum_tail_doublewords         /* len < 128 */
+
+       srdi    r6,r4,6
+       subi    r6,r6,1
+       mtctr   r6
+
+       stdu    r1,-STACKFRAMESIZE(r1)
+       std     r14,STK_REG(r14)(r1)
+       std     r15,STK_REG(r15)(r1)
+       std     r16,STK_REG(r16)(r1)
+
+       ld      r6,0(r3)
+       ld      r9,8(r3)
+
+       ld      r10,16(r3)
+       ld      r11,24(r3)
+
+       /*
+        * On POWER6 and POWER7 back to back addes take 2 cycles because of
+        * the XER dependency. This means the fastest this loop can go is
+        * 16 cycles per iteration. The scheduling of the loop below has
+        * been shown to hit this on both POWER6 and POWER7.
+        */
+       .align 5
+2:
+       adde    r0,r0,r6
+       ld      r12,32(r3)
+       ld      r14,40(r3)
+
+       adde    r0,r0,r9
+       ld      r15,48(r3)
+       ld      r16,56(r3)
+       addi    r3,r3,64
+
+       adde    r0,r0,r10
+
+       adde    r0,r0,r11
+
+       adde    r0,r0,r12
+
+       adde    r0,r0,r14
+
+       adde    r0,r0,r15
+       ld      r6,0(r3)
+       ld      r9,8(r3)
+
+       adde    r0,r0,r16
+       ld      r10,16(r3)
+       ld      r11,24(r3)
+       bdnz    2b
+
+
+       adde    r0,r0,r6
+       ld      r12,32(r3)
+       ld      r14,40(r3)
+
+       adde    r0,r0,r9
+       ld      r15,48(r3)
+       ld      r16,56(r3)
+       addi    r3,r3,64
+
+       adde    r0,r0,r10
+       adde    r0,r0,r11
+       adde    r0,r0,r12
+       adde    r0,r0,r14
+       adde    r0,r0,r15
+       adde    r0,r0,r16
+
+       ld      r14,STK_REG(r14)(r1)
+       ld      r15,STK_REG(r15)(r1)
+       ld      r16,STK_REG(r16)(r1)
+       addi    r1,r1,STACKFRAMESIZE
+
+       andi.   r4,r4,63
+
+.Lcsum_tail_doublewords:               /* Up to 127 bytes to go */
+       srdi.   r6,r4,3
+       beq     .Lcsum_tail_word
+
+       mtctr   r6
+3:
+       ld      r6,0(r3)
+       addi    r3,r3,8
+       adde    r0,r0,r6
+       bdnz    3b
+
+       andi.   r4,r4,7
+
+.Lcsum_tail_word:                      /* Up to 7 bytes to go */
+       srdi.   r6,r4,2
+       beq     .Lcsum_tail_halfword
+
+       lwz     r6,0(r3)
        addi    r3,r3,4
+       adde    r0,r0,r6
        subi    r4,r4,4
-       adde    r5,r5,r6
-4:     cmpwi   0,r4,2          /* is at least a halfword left? */
-        blt+   5f
-        lhz     r6,8(r3)        /* sum this halfword */
-        addi    r3,r3,2
-        subi    r4,r4,2
-        adde    r5,r5,r6
-5:     cmpwi   0,r4,1          /* is at least a byte left? */
-        bne+    6f
-        lbz     r6,8(r3)        /* sum this byte */
-        slwi    r6,r6,8         /* this byte is assumed to be the upper byte of a halfword */
-        adde    r5,r5,r6
-6:      addze  r5,r5           /* add in final carry */
-       rldicl  r4,r5,32,0      /* fold two 32-bit halves together */
-        add     r3,r4,r5
-        srdi    r3,r3,32
-        blr
+
+.Lcsum_tail_halfword:                  /* Up to 3 bytes to go */
+       srdi.   r6,r4,1
+       beq     .Lcsum_tail_byte
+
+       lhz     r6,0(r3)
+       addi    r3,r3,2
+       adde    r0,r0,r6
+       subi    r4,r4,2
+
+.Lcsum_tail_byte:                      /* Up to 1 byte to go */
+       andi.   r6,r4,1
+       beq     .Lcsum_finish
+
+       lbz     r6,0(r3)
+       sldi    r9,r6,8                 /* Pad the byte out to 16 bits */
+       adde    r0,r0,r9
+
+.Lcsum_finish:
+       addze   r0,r0                   /* add in final carry */
+       rldicl  r4,r0,32,0              /* fold two 32 bit halves together */
+       add     r3,r4,r0
+       srdi    r3,r3,32
+       blr
+
+
+       .macro source
+100:
+       .section __ex_table,"a"
+       .align 3
+       .llong 100b,.Lsrc_error
+       .previous
+       .endm
+
+       .macro dest
+200:
+       .section __ex_table,"a"
+       .align 3
+       .llong 200b,.Ldest_error
+       .previous
+       .endm
 
 /*
  * Computes the checksum of a memory block at src, length len,
  * and adds in "sum" (32-bit), while copying the block to dst.
  * If an access exception occurs on src or dst, it stores -EFAULT
- * to *src_err or *dst_err respectively, and (for an error on
- * src) zeroes the rest of dst.
- *
- * This code needs to be reworked to take advantage of 64 bit sum+copy.
- * However, due to tokenring halfword alignment problems this will be very
- * tricky.  For now we'll leave it until we instrument it somehow.
+ * to *src_err or *dst_err respectively. The caller must take any action
+ * required in this case (zeroing memory, recalculating partial checksum etc).
  *
  * csum_partial_copy_generic(r3=src, r4=dst, r5=len, r6=sum, r7=src_err, r8=dst_err)
  */
 _GLOBAL(csum_partial_copy_generic)
-       addic   r0,r6,0
-       subi    r3,r3,4
-       subi    r4,r4,4
-       srwi.   r6,r5,2
-       beq     3f              /* if we're doing < 4 bytes */
-       andi.   r9,r4,2         /* Align dst to longword boundary */
-       beq+    1f
-81:    lhz     r6,4(r3)        /* do 2 bytes to get aligned */
-       addi    r3,r3,2
+       addic   r0,r6,0                 /* clear carry */
+
+       srdi.   r6,r5,3                 /* less than 8 bytes? */
+       beq     .Lcopy_tail_word
+
+       /*
+        * If only halfword aligned, align to a double word. Since odd
+        * aligned addresses should be rare and they would require more
+        * work to calculate the correct checksum, we ignore that case
+        * and take the potential slowdown of unaligned loads.
+        *
+        * If the source and destination are relatively unaligned we only
+        * align the source. This keeps things simple.
+        */
+       rldicl. r6,r3,64-1,64-2         /* r6 = (r3 & 0x3) >> 1 */
+       beq     .Lcopy_aligned
+
+       li      r7,4
+       sub     r6,r7,r6
+       mtctr   r6
+
+1:
+source;        lhz     r6,0(r3)                /* align to doubleword */
        subi    r5,r5,2
-91:    sth     r6,4(r4)
-       addi    r4,r4,2
-       addc    r0,r0,r6
-       srwi.   r6,r5,2         /* # words to do */
-       beq     3f
-1:     mtctr   r6
-82:    lwzu    r6,4(r3)        /* the bdnz has zero overhead, so it should */
-92:    stwu    r6,4(r4)        /* be unnecessary to unroll this loop */
-       adde    r0,r0,r6
-       bdnz    82b
-       andi.   r5,r5,3
-3:     cmpwi   0,r5,2
-       blt+    4f
-83:    lhz     r6,4(r3)
        addi    r3,r3,2
-       subi    r5,r5,2
-93:    sth     r6,4(r4)
+       adde    r0,r0,r6
+dest;  sth     r6,0(r4)
        addi    r4,r4,2
+       bdnz    1b
+
+.Lcopy_aligned:
+       /*
+        * We unroll the loop such that each iteration is 64 bytes with an
+        * entry and exit limb of 64 bytes, meaning a minimum size of
+        * 128 bytes.
+        */
+       srdi.   r6,r5,7
+       beq     .Lcopy_tail_doublewords         /* len < 128 */
+
+       srdi    r6,r5,6
+       subi    r6,r6,1
+       mtctr   r6
+
+       stdu    r1,-STACKFRAMESIZE(r1)
+       std     r14,STK_REG(r14)(r1)
+       std     r15,STK_REG(r15)(r1)
+       std     r16,STK_REG(r16)(r1)
+
+source;        ld      r6,0(r3)
+source;        ld      r9,8(r3)
+
+source;        ld      r10,16(r3)
+source;        ld      r11,24(r3)
+
+       /*
+        * On POWER6 and POWER7 back to back addes take 2 cycles because of
+        * the XER dependency. This means the fastest this loop can go is
+        * 16 cycles per iteration. The scheduling of the loop below has
+        * been shown to hit this on both POWER6 and POWER7.
+        */
+       .align 5
+2:
        adde    r0,r0,r6
-4:     cmpwi   0,r5,1
-       bne+    5f
-84:    lbz     r6,4(r3)
-94:    stb     r6,4(r4)
-       slwi    r6,r6,8         /* Upper byte of word */
+source;        ld      r12,32(r3)
+source;        ld      r14,40(r3)
+
+       adde    r0,r0,r9
+source;        ld      r15,48(r3)
+source;        ld      r16,56(r3)
+       addi    r3,r3,64
+
+       adde    r0,r0,r10
+dest;  std     r6,0(r4)
+dest;  std     r9,8(r4)
+
+       adde    r0,r0,r11
+dest;  std     r10,16(r4)
+dest;  std     r11,24(r4)
+
+       adde    r0,r0,r12
+dest;  std     r12,32(r4)
+dest;  std     r14,40(r4)
+
+       adde    r0,r0,r14
+dest;  std     r15,48(r4)
+dest;  std     r16,56(r4)
+       addi    r4,r4,64
+
+       adde    r0,r0,r15
+source;        ld      r6,0(r3)
+source;        ld      r9,8(r3)
+
+       adde    r0,r0,r16
+source;        ld      r10,16(r3)
+source;        ld      r11,24(r3)
+       bdnz    2b
+
+
        adde    r0,r0,r6
-5:     addze   r3,r0           /* add in final carry (unlikely with 64-bit regs) */
-        rldicl  r4,r3,32,0      /* fold 64 bit value */
-        add     r3,r4,r3
-        srdi    r3,r3,32
-       blr
+source;        ld      r12,32(r3)
+source;        ld      r14,40(r3)
 
-/* These shouldn't go in the fixup section, since that would
-   cause the ex_table addresses to get out of order. */
+       adde    r0,r0,r9
+source;        ld      r15,48(r3)
+source;        ld      r16,56(r3)
+       addi    r3,r3,64
+
+       adde    r0,r0,r10
+dest;  std     r6,0(r4)
+dest;  std     r9,8(r4)
+
+       adde    r0,r0,r11
+dest;  std     r10,16(r4)
+dest;  std     r11,24(r4)
+
+       adde    r0,r0,r12
+dest;  std     r12,32(r4)
+dest;  std     r14,40(r4)
+
+       adde    r0,r0,r14
+dest;  std     r15,48(r4)
+dest;  std     r16,56(r4)
+       addi    r4,r4,64
+
+       adde    r0,r0,r15
+       adde    r0,r0,r16
+
+       ld      r14,STK_REG(r14)(r1)
+       ld      r15,STK_REG(r15)(r1)
+       ld      r16,STK_REG(r16)(r1)
+       addi    r1,r1,STACKFRAMESIZE
+
+       andi.   r5,r5,63
+
+.Lcopy_tail_doublewords:               /* Up to 127 bytes to go */
+       srdi.   r6,r5,3
+       beq     .Lcopy_tail_word
 
-       .globl src_error_1
-src_error_1:
-       li      r6,0
-       subi    r5,r5,2
-95:    sth     r6,4(r4)
-       addi    r4,r4,2
-       srwi.   r6,r5,2
-       beq     3f
        mtctr   r6
-       .globl src_error_2
-src_error_2:
-       li      r6,0
-96:    stwu    r6,4(r4)
-       bdnz    96b
-3:     andi.   r5,r5,3
-       beq     src_error
-       .globl src_error_3
-src_error_3:
-       li      r6,0
-       mtctr   r5
-       addi    r4,r4,3
-97:    stbu    r6,1(r4)
-       bdnz    97b
-       .globl src_error
-src_error:
+3:
+source;        ld      r6,0(r3)
+       addi    r3,r3,8
+       adde    r0,r0,r6
+dest;  std     r6,0(r4)
+       addi    r4,r4,8
+       bdnz    3b
+
+       andi.   r5,r5,7
+
+.Lcopy_tail_word:                      /* Up to 7 bytes to go */
+       srdi.   r6,r5,2
+       beq     .Lcopy_tail_halfword
+
+source;        lwz     r6,0(r3)
+       addi    r3,r3,4
+       adde    r0,r0,r6
+dest;  stw     r6,0(r4)
+       addi    r4,r4,4
+       subi    r5,r5,4
+
+.Lcopy_tail_halfword:                  /* Up to 3 bytes to go */
+       srdi.   r6,r5,1
+       beq     .Lcopy_tail_byte
+
+source;        lhz     r6,0(r3)
+       addi    r3,r3,2
+       adde    r0,r0,r6
+dest;  sth     r6,0(r4)
+       addi    r4,r4,2
+       subi    r5,r5,2
+
+.Lcopy_tail_byte:                      /* Up to 1 byte to go */
+       andi.   r6,r5,1
+       beq     .Lcopy_finish
+
+source;        lbz     r6,0(r3)
+       sldi    r9,r6,8                 /* Pad the byte out to 16 bits */
+       adde    r0,r0,r9
+dest;  stb     r6,0(r4)
+
+.Lcopy_finish:
+       addze   r0,r0                   /* add in final carry */
+       rldicl  r4,r0,32,0              /* fold two 32 bit halves together */
+       add     r3,r4,r0
+       srdi    r3,r3,32
+       blr
+
+.Lsrc_error:
        cmpdi   0,r7,0
-       beq     1f
+       beqlr
        li      r6,-EFAULT
        stw     r6,0(r7)
-1:     addze   r3,r0
        blr
 
-       .globl dst_error
-dst_error:
+.Ldest_error:
        cmpdi   0,r8,0
-       beq     1f
+       beqlr
        li      r6,-EFAULT
        stw     r6,0(r8)
-1:     addze   r3,r0
        blr
-
-.section __ex_table,"a"
-       .align  3
-       .llong  81b,src_error_1
-       .llong  91b,dst_error
-       .llong  82b,src_error_2
-       .llong  92b,dst_error
-       .llong  83b,src_error_3
-       .llong  93b,dst_error
-       .llong  84b,src_error_3
-       .llong  94b,dst_error
-       .llong  95b,dst_error
-       .llong  96b,dst_error
-       .llong  97b,dst_error
diff --git a/arch/powerpc/lib/checksum_wrappers_64.c b/arch/powerpc/lib/checksum_wrappers_64.c
new file mode 100644 (file)
index 0000000..769b817
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) IBM Corporation, 2010
+ *
+ * Author: Anton Blanchard <anton@au.ibm.com>
+ */
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <asm/checksum.h>
+#include <asm/uaccess.h>
+
+__wsum csum_and_copy_from_user(const void __user *src, void *dst,
+                              int len, __wsum sum, int *err_ptr)
+{
+       unsigned int csum;
+
+       might_sleep();
+
+       *err_ptr = 0;
+
+       if (!len) {
+               csum = 0;
+               goto out;
+       }
+
+       if (unlikely((len < 0) || !access_ok(VERIFY_READ, src, len))) {
+               *err_ptr = -EFAULT;
+               csum = (__force unsigned int)sum;
+               goto out;
+       }
+
+       csum = csum_partial_copy_generic((void __force *)src, dst,
+                                        len, sum, err_ptr, NULL);
+
+       if (unlikely(*err_ptr)) {
+               int missing = __copy_from_user(dst, src, len);
+
+               if (missing) {
+                       memset(dst + len - missing, 0, missing);
+                       *err_ptr = -EFAULT;
+               } else {
+                       *err_ptr = 0;
+               }
+
+               csum = csum_partial(dst, len, sum);
+       }
+
+out:
+       return (__force __wsum)csum;
+}
+EXPORT_SYMBOL(csum_and_copy_from_user);
+
+__wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
+                            __wsum sum, int *err_ptr)
+{
+       unsigned int csum;
+
+       might_sleep();
+
+       *err_ptr = 0;
+
+       if (!len) {
+               csum = 0;
+               goto out;
+       }
+
+       if (unlikely((len < 0) || !access_ok(VERIFY_WRITE, dst, len))) {
+               *err_ptr = -EFAULT;
+               csum = -1; /* invalid checksum */
+               goto out;
+       }
+
+       csum = csum_partial_copy_generic(src, (void __force *)dst,
+                                        len, sum, NULL, err_ptr);
+
+       if (unlikely(*err_ptr)) {
+               csum = csum_partial(src, len, sum);
+
+               if (copy_to_user(dst, src, len)) {
+                       *err_ptr = -EFAULT;
+                       csum = -1; /* invalid checksum */
+               }
+       }
+
+out:
+       return (__force __wsum)csum;
+}
+EXPORT_SYMBOL(csum_and_copy_to_user);
index 74a7f4130b4ce5ed34b797227568fa86545650b7..55f19f9fd70823f2320498a9d910ebe919633ffd 100644 (file)
@@ -62,7 +62,7 @@
 
        .text
        .stabs  "arch/powerpc/lib/",N_SO,0,0,0f
-       .stabs  "copy32.S",N_SO,0,0,0f
+       .stabs  "copy_32.S",N_SO,0,0,0f
 0:
 
 CACHELINE_BYTES = L1_CACHE_BYTES
index f6448636baf59eea3c6c3fef71f137f86d243e1c..6a85380520b61163dff57eab585bfa1c4352bffb 100644 (file)
@@ -17,6 +17,8 @@
 #include <asm/asm-offsets.h>
 #include <linux/errno.h>
 
+#ifdef CONFIG_PPC_FPU
+
 #define STKFRM (PPC_MIN_STKFRM + 16)
 
        .macro  extab   instr,handler
@@ -81,7 +83,7 @@ _GLOBAL(do_lfs)
        mfmsr   r6
        ori     r7,r6,MSR_FP
        cmpwi   cr7,r3,0
-       mtmsrd  r7
+       MTMSRD(r7)
        isync
        beq     cr7,1f
        stfd    fr0,STKFRM-16(r1)
@@ -93,7 +95,7 @@ _GLOBAL(do_lfs)
        lfd     fr0,STKFRM-16(r1)
 4:     PPC_LL  r0,STKFRM+PPC_LR_STKOFF(r1)
        mtlr    r0
-       mtmsrd  r6
+       MTMSRD(r6)
        isync
        mr      r3,r9
        addi    r1,r1,STKFRM
@@ -108,7 +110,7 @@ _GLOBAL(do_lfd)
        mfmsr   r6
        ori     r7,r6,MSR_FP
        cmpwi   cr7,r3,0
-       mtmsrd  r7
+       MTMSRD(r7)
        isync
        beq     cr7,1f
        stfd    fr0,STKFRM-16(r1)
@@ -120,7 +122,7 @@ _GLOBAL(do_lfd)
        lfd     fr0,STKFRM-16(r1)
 4:     PPC_LL  r0,STKFRM+PPC_LR_STKOFF(r1)
        mtlr    r0
-       mtmsrd  r6
+       MTMSRD(r6)
        isync
        mr      r3,r9
        addi    r1,r1,STKFRM
@@ -135,7 +137,7 @@ _GLOBAL(do_stfs)
        mfmsr   r6
        ori     r7,r6,MSR_FP
        cmpwi   cr7,r3,0
-       mtmsrd  r7
+       MTMSRD(r7)
        isync
        beq     cr7,1f
        stfd    fr0,STKFRM-16(r1)
@@ -147,7 +149,7 @@ _GLOBAL(do_stfs)
        lfd     fr0,STKFRM-16(r1)
 4:     PPC_LL  r0,STKFRM+PPC_LR_STKOFF(r1)
        mtlr    r0
-       mtmsrd  r6
+       MTMSRD(r6)
        isync
        mr      r3,r9
        addi    r1,r1,STKFRM
@@ -162,7 +164,7 @@ _GLOBAL(do_stfd)
        mfmsr   r6
        ori     r7,r6,MSR_FP
        cmpwi   cr7,r3,0
-       mtmsrd  r7
+       MTMSRD(r7)
        isync
        beq     cr7,1f
        stfd    fr0,STKFRM-16(r1)
@@ -174,7 +176,7 @@ _GLOBAL(do_stfd)
        lfd     fr0,STKFRM-16(r1)
 4:     PPC_LL  r0,STKFRM+PPC_LR_STKOFF(r1)
        mtlr    r0
-       mtmsrd  r6
+       MTMSRD(r6)
        isync
        mr      r3,r9
        addi    r1,r1,STKFRM
@@ -229,7 +231,7 @@ _GLOBAL(do_lvx)
        oris    r7,r6,MSR_VEC@h
        cmpwi   cr7,r3,0
        li      r8,STKFRM-16
-       mtmsrd  r7
+       MTMSRD(r7)
        isync
        beq     cr7,1f
        stvx    vr0,r1,r8
@@ -241,7 +243,7 @@ _GLOBAL(do_lvx)
        lvx     vr0,r1,r8
 4:     PPC_LL  r0,STKFRM+PPC_LR_STKOFF(r1)
        mtlr    r0
-       mtmsrd  r6
+       MTMSRD(r6)
        isync
        mr      r3,r9
        addi    r1,r1,STKFRM
@@ -257,7 +259,7 @@ _GLOBAL(do_stvx)
        oris    r7,r6,MSR_VEC@h
        cmpwi   cr7,r3,0
        li      r8,STKFRM-16
-       mtmsrd  r7
+       MTMSRD(r7)
        isync
        beq     cr7,1f
        stvx    vr0,r1,r8
@@ -269,7 +271,7 @@ _GLOBAL(do_stvx)
        lvx     vr0,r1,r8
 4:     PPC_LL  r0,STKFRM+PPC_LR_STKOFF(r1)
        mtlr    r0
-       mtmsrd  r6
+       MTMSRD(r6)
        isync
        mr      r3,r9
        addi    r1,r1,STKFRM
@@ -325,7 +327,7 @@ _GLOBAL(do_lxvd2x)
        oris    r7,r6,MSR_VSX@h
        cmpwi   cr7,r3,0
        li      r8,STKFRM-16
-       mtmsrd  r7
+       MTMSRD(r7)
        isync
        beq     cr7,1f
        STXVD2X(0,r1,r8)
@@ -337,7 +339,7 @@ _GLOBAL(do_lxvd2x)
        LXVD2X(0,r1,r8)
 4:     PPC_LL  r0,STKFRM+PPC_LR_STKOFF(r1)
        mtlr    r0
-       mtmsrd  r6
+       MTMSRD(r6)
        isync
        mr      r3,r9
        addi    r1,r1,STKFRM
@@ -353,7 +355,7 @@ _GLOBAL(do_stxvd2x)
        oris    r7,r6,MSR_VSX@h
        cmpwi   cr7,r3,0
        li      r8,STKFRM-16
-       mtmsrd  r7
+       MTMSRD(r7)
        isync
        beq     cr7,1f
        STXVD2X(0,r1,r8)
@@ -365,7 +367,7 @@ _GLOBAL(do_stxvd2x)
        LXVD2X(0,r1,r8)
 4:     PPC_LL  r0,STKFRM+PPC_LR_STKOFF(r1)
        mtlr    r0
-       mtmsrd  r6
+       MTMSRD(r6)
        isync
        mr      r3,r9
        addi    r1,r1,STKFRM
@@ -373,3 +375,5 @@ _GLOBAL(do_stxvd2x)
        extab   2b,3b
 
 #endif /* CONFIG_VSX */
+
+#endif /* CONFIG_PPC_FPU */
index 58e14fba11b1d7472b982a9a91a992a20319c9cd..9b8182e82166aa1e431576c3098567c1e15b8fa5 100644 (file)
@@ -34,7 +34,7 @@ void __spin_yield(arch_spinlock_t *lock)
                return;
        holder_cpu = lock_value & 0xffff;
        BUG_ON(holder_cpu >= NR_CPUS);
-       yield_count = lppaca[holder_cpu].yield_count;
+       yield_count = lppaca_of(holder_cpu).yield_count;
        if ((yield_count & 1) == 0)
                return;         /* virtual cpu is currently running */
        rmb();
@@ -65,7 +65,7 @@ void __rw_yield(arch_rwlock_t *rw)
                return;         /* no write lock at present */
        holder_cpu = lock_value & 0xffff;
        BUG_ON(holder_cpu >= NR_CPUS);
-       yield_count = lppaca[holder_cpu].yield_count;
+       yield_count = lppaca_of(holder_cpu).yield_count;
        if ((yield_count & 1) == 0)
                return;         /* virtual cpu is currently running */
        rmb();
index e0a9858d537eaa624246aed33738c0d7240f3bf3..ae5189ab004926072e2f86e04b4b8aa33c0d0867 100644 (file)
@@ -30,6 +30,7 @@ extern char system_call_common[];
 #define XER_OV         0x40000000U
 #define XER_CA         0x20000000U
 
+#ifdef CONFIG_PPC_FPU
 /*
  * Functions in ldstfp.S
  */
@@ -41,6 +42,7 @@ extern int do_lvx(int rn, unsigned long ea);
 extern int do_stvx(int rn, unsigned long ea);
 extern int do_lxvd2x(int rn, unsigned long ea);
 extern int do_stxvd2x(int rn, unsigned long ea);
+#endif
 
 /*
  * Determine whether a conditional branch instruction would branch.
@@ -290,6 +292,7 @@ static int __kprobes write_mem(unsigned long val, unsigned long ea, int nb,
        return write_mem_unaligned(val, ea, nb, regs);
 }
 
+#ifdef CONFIG_PPC_FPU
 /*
  * Check the address and alignment, and call func to do the actual
  * load or store.
@@ -351,6 +354,7 @@ static int __kprobes do_fp_store(int rn, int (*func)(int, unsigned long),
        }
        return err;
 }
+#endif
 
 #ifdef CONFIG_ALTIVEC
 /* For Altivec/VMX, no need to worry about alignment */
@@ -1393,6 +1397,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                                regs->gpr[rd] = byterev_4(val);
                        goto ldst_done;
 
+#ifdef CONFIG_PPC_CPU
                case 535:       /* lfsx */
                case 567:       /* lfsux */
                        if (!(regs->msr & MSR_FP))
@@ -1424,6 +1429,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                        ea = xform_ea(instr, regs, u);
                        err = do_fp_store(rd, do_stfd, ea, 8, regs);
                        goto ldst_done;
+#endif
 
 #ifdef __powerpc64__
                case 660:       /* stdbrx */
@@ -1534,6 +1540,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                } while (++rd < 32);
                goto instr_done;
 
+#ifdef CONFIG_PPC_FPU
        case 48:        /* lfs */
        case 49:        /* lfsu */
                if (!(regs->msr & MSR_FP))
@@ -1565,6 +1572,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
                ea = dform_ea(instr, regs);
                err = do_fp_store(rd, do_stfd, ea, 8, regs);
                goto ldst_done;
+#endif
 
 #ifdef __powerpc64__
        case 58:        /* ld[u], lwa */
index 0c16ab947f1f3f04990874562b604209012c60dc..7d1dba0d57f9e84daa25333a542d5bf6e88d69cc 100644 (file)
@@ -15,4 +15,4 @@ obj-$(CONFIG_SPE)             += math_efp.o
 CFLAGS_fabs.o = -fno-builtin-fabs
 CFLAGS_math.o = -fno-builtin-fabs
 
-EXTRA_CFLAGS = -I. -Iinclude/math-emu -w
+ccflags-y = -I. -Iinclude/math-emu -w
index 1dc2fa5ce1bda72b05df8db2e4d249cfcc8642ab..5810967511d4d01ddef3b8ec96de9cf2ab40a01b 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/highmem.h>
+#include <linux/memblock.h>
 
 #include <asm/pgalloc.h>
 #include <asm/prom.h>
@@ -47,6 +48,7 @@
 #include <asm/bootx.h>
 #include <asm/machdep.h>
 #include <asm/setup.h>
+
 #include "mmu_decl.h"
 
 extern int __map_without_ltlbs;
@@ -139,8 +141,19 @@ unsigned long __init mmu_mapin_ram(unsigned long top)
         * coverage with normal-sized pages (or other reasons) do not
         * attempt to allocate outside the allowed range.
         */
-
-       __initial_memory_limit_addr = memstart_addr + mapped;
+       memblock_set_current_limit(mapped);
 
        return mapped;
 }
+
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+                               phys_addr_t first_memblock_size)
+{
+       /* We don't currently support the first MEMBLOCK not mapping 0
+        * physical on those processors
+        */
+       BUG_ON(first_memblock_base != 0);
+
+       /* 40x can only access 16MB at the moment (see head_40x.S) */
+       memblock_set_current_limit(min_t(u64, first_memblock_size, 0x00800000));
+}
index d8c6efb32bc6af456095aefef37944b9cca4a99b..024acab588fd5bcf54b58dd194429727bc122ffd 100644 (file)
@@ -24,6 +24,8 @@
  */
 
 #include <linux/init.h>
+#include <linux/memblock.h>
+
 #include <asm/mmu.h>
 #include <asm/system.h>
 #include <asm/page.h>
@@ -213,6 +215,18 @@ unsigned long __init mmu_mapin_ram(unsigned long top)
        return total_lowmem;
 }
 
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+                               phys_addr_t first_memblock_size)
+{
+       /* We don't currently support the first MEMBLOCK not mapping 0
+        * physical on those processors
+        */
+       BUG_ON(first_memblock_base != 0);
+
+       /* 44x has a 256M TLB entry pinned at boot */
+       memblock_set_current_limit(min_t(u64, first_memblock_size, PPC_PIN_SIZE));
+}
+
 #ifdef CONFIG_SMP
 void __cpuinit mmu_init_secondary(int cpu)
 {
index ce68708bbad53c016986eabf7dfe2ef08ba33a97..bdca46e0838279ba6a9e26aa106925435865b5d6 100644 (file)
@@ -4,9 +4,7 @@
 
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
-ifeq ($(CONFIG_PPC64),y)
-EXTRA_CFLAGS   += -mno-minimal-toc
-endif
+ccflags-$(CONFIG_PPC64)        := -mno-minimal-toc
 
 obj-y                          := fault.o mem.o pgtable.o gup.o \
                                   init_$(CONFIG_WORD_SIZE).o \
@@ -25,7 +23,7 @@ obj-$(CONFIG_PPC_STD_MMU)     += hash_low_$(CONFIG_WORD_SIZE).o \
                                   mmu_context_hash$(CONFIG_WORD_SIZE).o
 obj-$(CONFIG_40x)              += 40x_mmu.o
 obj-$(CONFIG_44x)              += 44x_mmu.o
-obj-$(CONFIG_FSL_BOOKE)                += fsl_booke_mmu.o
+obj-$(CONFIG_PPC_FSL_BOOK3E)   += fsl_booke_mmu.o
 obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o
 obj-$(CONFIG_PPC_MM_SLICES)    += slice.o
 ifeq ($(CONFIG_HUGETLB_PAGE),y)
index 1bd712c33ce234b679289547ebd1a4f0c9f4ef01..54f4fb994e99aae549ccb38b4ebcd490d0df0e0d 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 #include <linux/perf_event.h>
+#include <linux/magic.h>
 
 #include <asm/firmware.h>
 #include <asm/page.h>
@@ -385,6 +386,7 @@ do_sigbus:
 void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
 {
        const struct exception_table_entry *entry;
+       unsigned long *stackend;
 
        /* Are we prepared to handle this fault?  */
        if ((entry = search_exception_tables(regs->nip)) != NULL) {
@@ -413,5 +415,9 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
        printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n",
                regs->nip);
 
+       stackend = end_of_stack(current);
+       if (current != &init_task && *stackend != STACK_END_MAGIC)
+               printk(KERN_ALERT "Thread overran stack, or stack corrupted\n");
+
        die("Kernel access of bad area", regs, sig);
 }
index 4b66a1ece6d8519b9184249811974d242c322c77..f7802c8bba0a6b31be879ecf1446f474c00d52b8 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/highmem.h>
+#include <linux/memblock.h>
 
 #include <asm/pgalloc.h>
 #include <asm/prom.h>
 
 unsigned int tlbcam_index;
 
-
-#if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS)
-#error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS"
-#endif
-
 #define NUM_TLBCAMS    (64)
 struct tlbcam TLBCAM[NUM_TLBCAMS];
 
@@ -137,7 +133,8 @@ static void settlbcam(int index, unsigned long virt, phys_addr_t phys,
        if (mmu_has_feature(MMU_FTR_BIG_PHYS))
                TLBCAM[index].MAS7 = (u64)phys >> 32;
 
-       if (flags & _PAGE_USER) {
+       /* Below is unlikely -- only for large user pages or similar */
+       if (pte_user(flags)) {
           TLBCAM[index].MAS3 |= MAS3_UX | MAS3_UR;
           TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_UW : 0);
        }
@@ -184,6 +181,12 @@ unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx)
        return amount_mapped;
 }
 
+#ifdef CONFIG_PPC32
+
+#if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS)
+#error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS"
+#endif
+
 unsigned long __init mmu_mapin_ram(unsigned long top)
 {
        return tlbcam_addrs[tlbcam_index - 1].limit - PAGE_OFFSET + 1;
@@ -213,5 +216,15 @@ void __init adjust_total_lowmem(void)
        pr_cont("%lu Mb, residual: %dMb\n", tlbcam_sz(tlbcam_index - 1) >> 20,
                (unsigned int)((total_lowmem - __max_low_memory) >> 20));
 
-       __initial_memory_limit_addr = memstart_addr + __max_low_memory;
+       memblock_set_current_limit(memstart_addr + __max_low_memory);
 }
+
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+                               phys_addr_t first_memblock_size)
+{
+       phys_addr_t limit = first_memblock_base + first_memblock_size;
+
+       /* 64M mapped initially according to head_fsl_booke.S */
+       memblock_set_current_limit(min_t(u64, limit, 0x04000000));
+}
+#endif
index 09dffe6efa46aeae84d62a922215f87fe0a8ca2d..83f534d862db2cd3934fca431e9b4d67b4ac7d38 100644 (file)
@@ -588,7 +588,7 @@ static void __init htab_initialize(void)
        unsigned long pteg_count;
        unsigned long prot;
        unsigned long base = 0, size = 0, limit;
-       int i;
+       struct memblock_region *reg;
 
        DBG(" -> htab_initialize()\n");
 
@@ -625,7 +625,7 @@ static void __init htab_initialize(void)
                if (machine_is(cell))
                        limit = 0x80000000;
                else
-                       limit = 0;
+                       limit = MEMBLOCK_ALLOC_ANYWHERE;
 
                table = memblock_alloc_base(htab_size_bytes, htab_size_bytes, limit);
 
@@ -649,7 +649,7 @@ static void __init htab_initialize(void)
 #ifdef CONFIG_DEBUG_PAGEALLOC
        linear_map_hash_count = memblock_end_of_DRAM() >> PAGE_SHIFT;
        linear_map_hash_slots = __va(memblock_alloc_base(linear_map_hash_count,
-                                                   1, memblock.rmo_size));
+                                                   1, ppc64_rma_size));
        memset(linear_map_hash_slots, 0, linear_map_hash_count);
 #endif /* CONFIG_DEBUG_PAGEALLOC */
 
@@ -659,9 +659,9 @@ static void __init htab_initialize(void)
         */
 
        /* create bolted the linear mapping in the hash table */
-       for (i=0; i < memblock.memory.cnt; i++) {
-               base = (unsigned long)__va(memblock.memory.region[i].base);
-               size = memblock.memory.region[i].size;
+       for_each_memblock(memory, reg) {
+               base = (unsigned long)__va(reg->base);
+               size = reg->size;
 
                DBG("creating mapping for region: %lx..%lx (prot: %lx)\n",
                    base, size, prot);
@@ -696,7 +696,8 @@ static void __init htab_initialize(void)
 #endif /* CONFIG_U3_DART */
                BUG_ON(htab_bolt_mapping(base, base + size, __pa(base),
                                prot, mmu_linear_psize, mmu_kernel_ssize));
-       }
+       }
+       memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
 
        /*
         * If we have a memory_limit and we've allocated TCEs then we need to
@@ -1247,3 +1248,23 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
        local_irq_restore(flags);
 }
 #endif /* CONFIG_DEBUG_PAGEALLOC */
+
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+                               phys_addr_t first_memblock_size)
+{
+       /* We don't currently support the first MEMBLOCK not mapping 0
+        * physical on those processors
+        */
+       BUG_ON(first_memblock_base != 0);
+
+       /* On LPAR systems, the first entry is our RMA region,
+        * non-LPAR 64-bit hash MMU systems don't have a limitation
+        * on real mode access, but using the first entry works well
+        * enough. We also clamp it to 1G to avoid some funky things
+        * such as RTAS bugs etc...
+        */
+       ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000);
+
+       /* Finally limit subsequent allocations */
+       memblock_set_current_limit(ppc64_rma_size);
+}
index 6a6975dc265427bf39c15979374c52501755aa3c..742da43b4ab6ddffe75f0609d4d5021bafccac25 100644 (file)
@@ -91,12 +91,6 @@ int __allow_ioremap_reserved;
 /* max amount of low RAM to map in */
 unsigned long __max_low_memory = MAX_LOW_MEM;
 
-/*
- * address of the limit of what is accessible with initial MMU setup -
- * 256MB usually, but only 16MB on 601.
- */
-phys_addr_t __initial_memory_limit_addr = (phys_addr_t)0x10000000;
-
 /*
  * Check for command-line options that affect what MMU_init will do.
  */
@@ -126,13 +120,6 @@ void __init MMU_init(void)
        if (ppc_md.progress)
                ppc_md.progress("MMU:enter", 0x111);
 
-       /* 601 can only access 16MB at the moment */
-       if (PVR_VER(mfspr(SPRN_PVR)) == 1)
-               __initial_memory_limit_addr = 0x01000000;
-       /* 8xx can only access 8MB at the moment */
-       if (PVR_VER(mfspr(SPRN_PVR)) == 0x50)
-               __initial_memory_limit_addr = 0x00800000;
-
        /* parse args from command line */
        MMU_setup();
 
@@ -190,20 +177,18 @@ void __init MMU_init(void)
 #ifdef CONFIG_BOOTX_TEXT
        btext_unmap();
 #endif
+
+       /* Shortly after that, the entire linear mapping will be available */
+       memblock_set_current_limit(lowmem_end_addr);
 }
 
 /* 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 {
-               p = __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE,
-                                       __initial_memory_limit_addr));
-       }
-       return p;
+       if (init_bootmem_done)
+               return alloc_bootmem_pages(PAGE_SIZE);
+       else
+               return __va(memblock_alloc(PAGE_SIZE, PAGE_SIZE));
 }
 
 /* Free up now-unused memory */
@@ -252,3 +237,17 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
+
+#ifdef CONFIG_8xx /* No 8xx specific .c file to put that in ... */
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+                               phys_addr_t first_memblock_size)
+{
+       /* We don't currently support the first MEMBLOCK not mapping 0
+        * physical on those processors
+        */
+       BUG_ON(first_memblock_base != 0);
+
+       /* 8xx can only access 8MB at the moment */
+       memblock_set_current_limit(min_t(u64, first_memblock_size, 0x00800000));
+}
+#endif /* CONFIG_8xx */
index ace85fa74b2923a63a5924ef6432c84980b41406..6374b2196a17a33b97589fb8097fc0c00a1f176b 100644 (file)
@@ -330,3 +330,4 @@ int __meminit vmemmap_populate(struct page *start_page,
        return 0;
 }
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
+
index 1a84a8d0000503b495ff2d79355f4f756e80591a..a66499650909bb1bce5d97a48ca7894b22d5241e 100644 (file)
@@ -82,18 +82,11 @@ int page_is_ram(unsigned long pfn)
        return pfn < max_pfn;
 #else
        unsigned long paddr = (pfn << PAGE_SHIFT);
-       int i;
-       for (i=0; i < memblock.memory.cnt; i++) {
-               unsigned long base;
+       struct memblock_region *reg;
 
-               base = memblock.memory.region[i].base;
-
-               if ((paddr >= base) &&
-                       (paddr < (base + memblock.memory.region[i].size))) {
+       for_each_memblock(memory, reg)
+               if (paddr >= reg->base && paddr < (reg->base + reg->size))
                        return 1;
-               }
-       }
-
        return 0;
 #endif
 }
@@ -149,23 +142,19 @@ int
 walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages,
                void *arg, int (*func)(unsigned long, unsigned long, void *))
 {
-       struct memblock_property res;
-       unsigned long pfn, len;
-       u64 end;
+       struct memblock_region *reg;
+       unsigned long end_pfn = start_pfn + nr_pages;
+       unsigned long tstart, tend;
        int ret = -1;
 
-       res.base = (u64) start_pfn << PAGE_SHIFT;
-       res.size = (u64) nr_pages << PAGE_SHIFT;
-
-       end = res.base + res.size - 1;
-       while ((res.base < end) && (memblock_find(&res) >= 0)) {
-               pfn = (unsigned long)(res.base >> PAGE_SHIFT);
-               len = (unsigned long)(res.size >> PAGE_SHIFT);
-               ret = (*func)(pfn, len, arg);
+       for_each_memblock(memory, reg) {
+               tstart = max(start_pfn, memblock_region_memory_base_pfn(reg));
+               tend = min(end_pfn, memblock_region_memory_end_pfn(reg));
+               if (tstart >= tend)
+                       continue;
+               ret = (*func)(tstart, tend - tstart, arg);
                if (ret)
                        break;
-               res.base += (res.size + 1);
-               res.size = (end - res.base + 1);
        }
        return ret;
 }
@@ -179,9 +168,9 @@ EXPORT_SYMBOL_GPL(walk_system_ram_range);
 #ifndef CONFIG_NEED_MULTIPLE_NODES
 void __init do_init_bootmem(void)
 {
-       unsigned long i;
        unsigned long start, bootmap_pages;
        unsigned long total_pages;
+       struct memblock_region *reg;
        int boot_mapsize;
 
        max_low_pfn = max_pfn = memblock_end_of_DRAM() >> PAGE_SHIFT;
@@ -204,10 +193,10 @@ void __init do_init_bootmem(void)
        boot_mapsize = init_bootmem_node(NODE_DATA(0), start >> PAGE_SHIFT, min_low_pfn, max_low_pfn);
 
        /* Add active regions with valid PFNs */
-       for (i = 0; i < memblock.memory.cnt; i++) {
+       for_each_memblock(memory, reg) {
                unsigned long start_pfn, end_pfn;
-               start_pfn = memblock.memory.region[i].base >> PAGE_SHIFT;
-               end_pfn = start_pfn + memblock_size_pages(&memblock.memory, i);
+               start_pfn = memblock_region_memory_base_pfn(reg);
+               end_pfn = memblock_region_memory_end_pfn(reg);
                add_active_range(0, start_pfn, end_pfn);
        }
 
@@ -218,29 +207,21 @@ void __init do_init_bootmem(void)
        free_bootmem_with_active_regions(0, lowmem_end_addr >> PAGE_SHIFT);
 
        /* reserve the sections we're already using */
-       for (i = 0; i < memblock.reserved.cnt; i++) {
-               unsigned long addr = memblock.reserved.region[i].base +
-                                    memblock_size_bytes(&memblock.reserved, i) - 1;
-               if (addr < lowmem_end_addr)
-                       reserve_bootmem(memblock.reserved.region[i].base,
-                                       memblock_size_bytes(&memblock.reserved, i),
-                                       BOOTMEM_DEFAULT);
-               else if (memblock.reserved.region[i].base < lowmem_end_addr) {
-                       unsigned long adjusted_size = lowmem_end_addr -
-                                     memblock.reserved.region[i].base;
-                       reserve_bootmem(memblock.reserved.region[i].base,
-                                       adjusted_size, BOOTMEM_DEFAULT);
+       for_each_memblock(reserved, reg) {
+               unsigned long top = reg->base + reg->size - 1;
+               if (top < lowmem_end_addr)
+                       reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+               else if (reg->base < lowmem_end_addr) {
+                       unsigned long trunc_size = lowmem_end_addr - reg->base;
+                       reserve_bootmem(reg->base, trunc_size, BOOTMEM_DEFAULT);
                }
        }
 #else
        free_bootmem_with_active_regions(0, max_pfn);
 
        /* reserve the sections we're already using */
-       for (i = 0; i < memblock.reserved.cnt; i++)
-               reserve_bootmem(memblock.reserved.region[i].base,
-                               memblock_size_bytes(&memblock.reserved, i),
-                               BOOTMEM_DEFAULT);
-
+       for_each_memblock(reserved, reg)
+               reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
 #endif
        /* XXX need to clip this if using highmem? */
        sparse_memory_present_with_active_regions(0);
@@ -251,22 +232,15 @@ void __init do_init_bootmem(void)
 /* mark pages that don't exist as nosave */
 static int __init mark_nonram_nosave(void)
 {
-       unsigned long memblock_next_region_start_pfn,
-                     memblock_region_max_pfn;
-       int i;
-
-       for (i = 0; i < memblock.memory.cnt - 1; i++) {
-               memblock_region_max_pfn =
-                       (memblock.memory.region[i].base >> PAGE_SHIFT) +
-                       (memblock.memory.region[i].size >> PAGE_SHIFT);
-               memblock_next_region_start_pfn =
-                       memblock.memory.region[i+1].base >> PAGE_SHIFT;
-
-               if (memblock_region_max_pfn < memblock_next_region_start_pfn)
-                       register_nosave_region(memblock_region_max_pfn,
-                                              memblock_next_region_start_pfn);
+       struct memblock_region *reg, *prev = NULL;
+
+       for_each_memblock(memory, reg) {
+               if (prev &&
+                   memblock_region_memory_end_pfn(prev) < memblock_region_memory_base_pfn(reg))
+                       register_nosave_region(memblock_region_memory_end_pfn(prev),
+                                              memblock_region_memory_base_pfn(reg));
+               prev = reg;
        }
-
        return 0;
 }
 
@@ -327,7 +301,7 @@ void __init mem_init(void)
                swiotlb_init(1);
 #endif
 
-       num_physpages = memblock.memory.size >> PAGE_SHIFT;
+       num_physpages = memblock_phys_mem_size() >> PAGE_SHIFT;
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 
 #ifdef CONFIG_NEED_MULTIPLE_NODES
index ddfd7ad4e1d60ade761b5f039b745307d6ce5a82..5ce99848d91e49aa3fb03d90c0f8c116a4d9d42a 100644 (file)
@@ -334,7 +334,7 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
        /* We don't touch CPU 0 map, it's allocated at aboot and kept
         * around forever
         */
-       if (cpu == 0)
+       if (cpu == boot_cpuid)
                return NOTIFY_OK;
 
        switch (action) {
@@ -420,9 +420,11 @@ void __init mmu_context_init(void)
         */
        context_map = alloc_bootmem(CTX_MAP_SIZE);
        context_mm = alloc_bootmem(sizeof(void *) * (last_context + 1));
+#ifndef CONFIG_SMP
        stale_map[0] = alloc_bootmem(CTX_MAP_SIZE);
+#else
+       stale_map[boot_cpuid] = alloc_bootmem(CTX_MAP_SIZE);
 
-#ifdef CONFIG_SMP
        register_cpu_notifier(&mmu_context_cpu_nb);
 #endif
 
index 63b84a0d3b10baccf4e252382c1b66640b2e56e2..dd0a2589591dc0a66fffe8f7eb4d5b3a17944224 100644 (file)
@@ -140,10 +140,13 @@ extern void wii_memory_fixups(void);
 extern void MMU_init_hw(void);
 extern unsigned long mmu_mapin_ram(unsigned long top);
 
-#elif defined(CONFIG_FSL_BOOKE)
+#elif defined(CONFIG_PPC_FSL_BOOK3E)
+extern unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx);
+#ifdef CONFIG_PPC32
 extern void MMU_init_hw(void);
 extern unsigned long mmu_mapin_ram(unsigned long top);
 extern void adjust_total_lowmem(void);
+#endif
 extern void loadcam_entry(unsigned int index);
 
 struct tlbcam {
index 002878ccf90b04bc46b12e1556d6e7f8775595be..74505b245374e305d64625056271147ab4125b1d 100644 (file)
@@ -802,16 +802,17 @@ static void __init setup_nonnuma(void)
        unsigned long top_of_ram = memblock_end_of_DRAM();
        unsigned long total_ram = memblock_phys_mem_size();
        unsigned long start_pfn, end_pfn;
-       unsigned int i, nid = 0;
+       unsigned int nid = 0;
+       struct memblock_region *reg;
 
        printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
               top_of_ram, total_ram);
        printk(KERN_DEBUG "Memory hole size: %ldMB\n",
               (top_of_ram - total_ram) >> 20);
 
-       for (i = 0; i < memblock.memory.cnt; ++i) {
-               start_pfn = memblock.memory.region[i].base >> PAGE_SHIFT;
-               end_pfn = start_pfn + memblock_size_pages(&memblock.memory, i);
+       for_each_memblock(memory, reg) {
+               start_pfn = memblock_region_memory_base_pfn(reg);
+               end_pfn = memblock_region_memory_end_pfn(reg);
 
                fake_numa_create_new_node(end_pfn, &nid);
                add_active_range(nid, start_pfn, end_pfn);
@@ -947,11 +948,11 @@ static struct notifier_block __cpuinitdata ppc64_numa_nb = {
 static void mark_reserved_regions_for_nid(int nid)
 {
        struct pglist_data *node = NODE_DATA(nid);
-       int i;
+       struct memblock_region *reg;
 
-       for (i = 0; i < memblock.reserved.cnt; i++) {
-               unsigned long physbase = memblock.reserved.region[i].base;
-               unsigned long size = memblock.reserved.region[i].size;
+       for_each_memblock(reserved, reg) {
+               unsigned long physbase = reg->base;
+               unsigned long size = reg->size;
                unsigned long start_pfn = physbase >> PAGE_SHIFT;
                unsigned long end_pfn = PFN_UP(physbase + size);
                struct node_active_region node_ar;
index f8a01829d64fd4820921f3148a17c32b98e74b67..11571e118831404bf656bcb699ec9765e42b6c9d 100644 (file)
@@ -223,8 +223,7 @@ void __init MMU_init_hw(void)
         * Find some memory for the hash table.
         */
        if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
-       Hash = __va(memblock_alloc_base(Hash_size, Hash_size,
-                                  __initial_memory_limit_addr));
+       Hash = __va(memblock_alloc(Hash_size, Hash_size));
        cacheable_memzero(Hash, Hash_size);
        _SDR1 = __pa(Hash) | SDR1_LOW_BITS;
 
@@ -272,3 +271,18 @@ void __init MMU_init_hw(void)
 
        if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
 }
+
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+                               phys_addr_t first_memblock_size)
+{
+       /* We don't currently support the first MEMBLOCK not mapping 0
+        * physical on those processors
+        */
+       BUG_ON(first_memblock_base != 0);
+
+       /* 601 can only access 16MB at the moment */
+       if (PVR_VER(mfspr(SPRN_PVR)) == 1)
+               memblock_set_current_limit(min_t(u64, first_memblock_size, 0x01000000));
+       else /* Anything else has 256M mapped */
+               memblock_set_current_limit(min_t(u64, first_memblock_size, 0x10000000));
+}
index fe391e942521bee44787a99387c304284184e16a..36c0c449a89993659c60d1b4c4b772fb5aa5f94c 100644 (file)
@@ -349,11 +349,47 @@ void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address)
 
 static void setup_page_sizes(void)
 {
-       unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
-       unsigned int tlb0ps = mfspr(SPRN_TLB0PS);
-       unsigned int eptcfg = mfspr(SPRN_EPTCFG);
+       unsigned int tlb0cfg;
+       unsigned int tlb0ps;
+       unsigned int eptcfg;
        int i, psize;
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+       unsigned int mmucfg = mfspr(SPRN_MMUCFG);
+
+       if (((mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V1) &&
+               (mmu_has_feature(MMU_FTR_TYPE_FSL_E))) {
+               unsigned int tlb1cfg = mfspr(SPRN_TLB1CFG);
+               unsigned int min_pg, max_pg;
+
+               min_pg = (tlb1cfg & TLBnCFG_MINSIZE) >> TLBnCFG_MINSIZE_SHIFT;
+               max_pg = (tlb1cfg & TLBnCFG_MAXSIZE) >> TLBnCFG_MAXSIZE_SHIFT;
+
+               for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
+                       struct mmu_psize_def *def;
+                       unsigned int shift;
+
+                       def = &mmu_psize_defs[psize];
+                       shift = def->shift;
+
+                       if (shift == 0)
+                               continue;
+
+                       /* adjust to be in terms of 4^shift Kb */
+                       shift = (shift - 10) >> 1;
+
+                       if ((shift >= min_pg) && (shift <= max_pg))
+                               def->flags |= MMU_PAGE_SIZE_DIRECT;
+               }
+
+               goto no_indirect;
+       }
+#endif
+
+       tlb0cfg = mfspr(SPRN_TLB0CFG);
+       tlb0ps = mfspr(SPRN_TLB0PS);
+       eptcfg = mfspr(SPRN_EPTCFG);
+
        /* Look for supported direct sizes */
        for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
                struct mmu_psize_def *def = &mmu_psize_defs[psize];
@@ -505,10 +541,26 @@ static void __early_init_mmu(int boot_cpu)
         */
        linear_map_top = memblock_end_of_DRAM();
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+       if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) {
+               unsigned int num_cams;
+
+               /* use a quarter of the TLBCAM for bolted linear map */
+               num_cams = (mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY) / 4;
+               linear_map_top = map_mem_in_cams(linear_map_top, num_cams);
+
+               /* limit memory so we dont have linear faults */
+               memblock_enforce_memory_limit(linear_map_top);
+               memblock_analyze();
+       }
+#endif
+
        /* A sync won't hurt us after mucking around with
         * the MMU configuration
         */
        mb();
+
+       memblock_set_current_limit(linear_map_top);
 }
 
 void __init early_init_mmu(void)
@@ -521,4 +573,18 @@ void __cpuinit early_init_mmu_secondary(void)
        __early_init_mmu(0);
 }
 
+void setup_initial_memory_limit(phys_addr_t first_memblock_base,
+                               phys_addr_t first_memblock_size)
+{
+       /* On Embedded 64-bit, we adjust the RMA size to match
+        * the bolted TLB entry. We know for now that only 1G
+        * entries are supported though that may eventually
+        * change. We crop it to the size of the first MEMBLOCK to
+        * avoid going over total available memory just in case...
+        */
+       ppc64_rma_size = min_t(u64, first_memblock_size, 0x40000000);
+
+       /* Finally limit subsequent allocations */
+       memblock_set_current_limit(ppc64_memblock_base + ppc64_rma_size);
+}
 #endif /* CONFIG_PPC64 */
index b9d9fed8f36e355083f32d22de3ba2274fa5fb71..af405eefe48d6b1f17b0f180eaab2682b56c716b 100644 (file)
@@ -367,7 +367,7 @@ _GLOBAL(set_context)
 #error Unsupported processor type !
 #endif
 
-#if defined(CONFIG_FSL_BOOKE)
+#if defined(CONFIG_PPC_FSL_BOOK3E)
 /*
  * extern void loadcam_entry(unsigned int index)
  *
index e219ca43962d0539f8b78d94ede969e7f1852d98..73456c4cec28aa102d43ea07fedf48ad48b73b6f 100644 (file)
@@ -1,8 +1,6 @@
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
-ifeq ($(CONFIG_PPC64),y)
-EXTRA_CFLAGS   += -mno-minimal-toc
-endif
+ccflags-$(CONFIG_PPC64)        := -mno-minimal-toc
 
 obj-$(CONFIG_OPROFILE) += oprofile.o
 
index b4278cfd1f80cccb5596f29b6c5068961aad06c2..f75301f2c85fd2960acd21ee427527614934585e 100644 (file)
@@ -105,7 +105,7 @@ void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth)
                }
        } else {
 #ifdef CONFIG_PPC64
-               if (!test_thread_flag(TIF_32BIT)) {
+               if (!is_32bit_task()) {
                        while (depth--) {
                                sp = user_getsp64(sp, first_frame);
                                if (!sp)
index 62312abffa28793561a78f37aaf776bc85526ae1..d4e6507277b5ea6ee43dbc1110027f2c4534eef4 100644 (file)
@@ -2,7 +2,7 @@
  * Freescale Embedded oprofile support, based on ppc64 oprofile support
  * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
  *
- * Copyright (c) 2004 Freescale Semiconductor, Inc
+ * Copyright (c) 2004, 2010 Freescale Semiconductor, Inc
  *
  * Author: Andy Fleming
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
@@ -321,9 +321,6 @@ static void fsl_emb_handle_interrupt(struct pt_regs *regs,
        int val;
        int i;
 
-       /* set the PMM bit (see comment below) */
-       mtmsr(mfmsr() | MSR_PMM);
-
        pc = regs->nip;
        is_kernel = is_kernel_addr(pc);
 
@@ -340,9 +337,13 @@ static void fsl_emb_handle_interrupt(struct pt_regs *regs,
        }
 
        /* The freeze bit was set by the interrupt. */
-       /* Clear the freeze bit, and reenable the interrupt.
-        * The counters won't actually start until the rfi clears
-        * the PMM bit */
+       /* Clear the freeze bit, and reenable the interrupt.  The
+        * counters won't actually start until the rfi clears the PMM
+        * bit.  The PMM bit should not be set until after the interrupt
+        * is cleared to avoid it getting lost in some hypervisor
+        * environments.
+        */
+       mtmsr(mfmsr() | MSR_PMM);
        pmc_start_ctrs(1);
 }
 
index 69d668c072aeab579aab54182d0c9bd544dac956..0f979c5c756b5ab129c5914b81869957d655cfe2 100644 (file)
@@ -17,6 +17,16 @@ config BAMBOO
        help
          This option enables support for the IBM PPC440EP evaluation board.
 
+config BLUESTONE
+       bool "Bluestone"
+       depends on 44x
+       default n
+       select PPC44x_SIMPLE
+       select APM821xx
+       select IBM_NEW_EMAC_RGMII
+       help
+         This option enables support for the APM APM821xx Evaluation board.
+
 config EBONY
        bool "Ebony"
        depends on 44x
@@ -293,6 +303,12 @@ config 460SX
        select IBM_NEW_EMAC_ZMII
        select IBM_NEW_EMAC_TAH
 
+config APM821xx
+       bool
+       select PPC_FPU
+       select IBM_NEW_EMAC_EMAC4
+       select IBM_NEW_EMAC_TAH
+
 # 44x errata/workaround config symbols, selected by the CPU models above
 config IBM440EP_ERR42
        bool
index 5f7a29d7f59091fa958e063b661421aa447e48fa..7ddcba3b93976c5ad46ba99ea7688b4d59786476 100644 (file)
@@ -52,6 +52,7 @@ machine_device_initcall(ppc44x_simple, ppc44x_device_probe);
 static char *board[] __initdata = {
        "amcc,arches",
        "amcc,bamboo",
+       "amcc,bluestone",
        "amcc,canyonlands",
        "amcc,glacier",
        "ibm,ebony",
index 021763a32c2f66bed742c4fb2207b3bca4360e4a..73f4135f3a1a6e8780e976b83fa0afc4a73d902f 100644 (file)
@@ -10,12 +10,12 @@ menuconfig PPC_83xx
 if PPC_83xx
 
 config MPC830x_RDB
-       bool "Freescale MPC830x RDB"
+       bool "Freescale MPC830x RDB and derivatives"
        select DEFAULT_UIMAGE
        select PPC_MPC831x
        select FSL_GTM
        help
-         This option enables support for the MPC8308 RDB board.
+         This option enables support for the MPC8308 RDB and MPC8308 P1M boards.
 
 config MPC831x_RDB
        bool "Freescale MPC831x RDB"
index ac102ee9abe8f046f57134c0ef8e44980da338a1..846831d495b57f6c1c9e123308ed9e3f2013848f 100644 (file)
@@ -65,7 +65,8 @@ static int __init mpc830x_rdb_probe(void)
        unsigned long root = of_get_flat_dt_root();
 
        return of_flat_dt_is_compatible(root, "MPC8308RDB") ||
-              of_flat_dt_is_compatible(root, "fsl,mpc8308rdb");
+              of_flat_dt_is_compatible(root, "fsl,mpc8308rdb") ||
+              of_flat_dt_is_compatible(root, "denx,mpc8308_p1m");
 }
 
 static struct of_device_id __initdata of_bus_ids[] = {
index bea1f5905ad42a4e9f18bfba115d02ef824c12f6..b6976e1726e4c43585e87e689a4b6c0250bf39b3 100644 (file)
@@ -11,6 +11,8 @@ menuconfig FSL_SOC_BOOKE
 
 if FSL_SOC_BOOKE
 
+if PPC32
+
 config MPC8540_ADS
        bool "Freescale MPC8540 ADS"
        select DEFAULT_UIMAGE
@@ -153,10 +155,20 @@ config SBC8560
        help
          This option enables support for the Wind River SBC8560 board
 
+config P3041_DS
+       bool "Freescale P3041 DS"
+       select DEFAULT_UIMAGE
+       select PPC_E500MC
+       select PHYS_64BIT
+       select SWIOTLB
+       select MPC8xxx_GPIO
+       select HAS_RAPIDIO
+       help
+         This option enables support for the P3041 DS board
+
 config P4080_DS
        bool "Freescale P4080 DS"
        select DEFAULT_UIMAGE
-       select PPC_FSL_BOOK3E
        select PPC_E500MC
        select PHYS_64BIT
        select SWIOTLB
@@ -165,6 +177,20 @@ config P4080_DS
        help
          This option enables support for the P4080 DS board
 
+endif # PPC32
+
+config P5020_DS
+       bool "Freescale P5020 DS"
+       select DEFAULT_UIMAGE
+       select E500
+       select PPC_E500MC
+       select PHYS_64BIT
+       select SWIOTLB
+       select MPC8xxx_GPIO
+       select HAS_RAPIDIO
+       help
+         This option enables support for the P5020 DS board
+
 endif # FSL_SOC_BOOKE
 
 config TQM85xx
index a2ec3f8f4d06bd01929d30f7fdce732282b27e14..dd70db77d63eb5d8d9a5bf08d1d28d649a61c887 100644 (file)
@@ -11,7 +11,9 @@ obj-$(CONFIG_MPC85xx_DS)  += mpc85xx_ds.o
 obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
 obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o
 obj-$(CONFIG_P1022_DS)    += p1022_ds.o
+obj-$(CONFIG_P3041_DS)    += p3041_ds.o corenet_ds.o
 obj-$(CONFIG_P4080_DS)    += p4080_ds.o corenet_ds.o
+obj-$(CONFIG_P5020_DS)    += p5020_ds.o corenet_ds.o
 obj-$(CONFIG_STX_GP3)    += stx_gp3.o
 obj-$(CONFIG_TQM85xx)    += tqm85xx.o
 obj-$(CONFIG_SBC8560)     += sbc8560.o
index 34e00902ce86229bf7aafe28eb5e5c9ae4a632e0..2b390d19a1d179bfd1d1c0d58498f693ed1f4c27 100644 (file)
@@ -112,6 +112,8 @@ static struct of_device_id __initdata p1022_ds_ids[] = {
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
        { .compatible = "gianfar", },
+       /* So that the DMA channel nodes can be probed individually: */
+       { .compatible = "fsl,eloplus-dma", },
        {},
 };
 
diff --git a/arch/powerpc/platforms/85xx/p3041_ds.c b/arch/powerpc/platforms/85xx/p3041_ds.c
new file mode 100644 (file)
index 0000000..0ed52e1
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * P3041 DS Setup
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2009-2010 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/phy.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <linux/of_platform.h>
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+
+#include "corenet_ds.h"
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p3041_ds_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "fsl,P3041DS");
+}
+
+define_machine(p3041_ds) {
+       .name                   = "P3041 DS",
+       .probe                  = p3041_ds_probe,
+       .setup_arch             = corenet_ds_setup_arch,
+       .init_IRQ               = corenet_ds_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_coreint_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
+
+machine_device_initcall(p3041_ds, corenet_ds_publish_devices);
+
+#ifdef CONFIG_SWIOTLB
+machine_arch_initcall(p3041_ds, swiotlb_setup_bus_notifier);
+#endif
diff --git a/arch/powerpc/platforms/85xx/p5020_ds.c b/arch/powerpc/platforms/85xx/p5020_ds.c
new file mode 100644 (file)
index 0000000..7467b71
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * P5020 DS Setup
+ *
+ * Maintained by Kumar Gala (see MAINTAINERS for contact information)
+ *
+ * Copyright 2009-2010 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/phy.h>
+
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <linux/of_platform.h>
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+
+#include "corenet_ds.h"
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p5020_ds_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "fsl,P5020DS");
+}
+
+define_machine(p5020_ds) {
+       .name                   = "P5020 DS",
+       .probe                  = p5020_ds_probe,
+       .setup_arch             = corenet_ds_setup_arch,
+       .init_IRQ               = corenet_ds_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
+#ifdef CONFIG_PPC64
+       .get_irq                = mpic_get_irq,
+#else
+       .get_irq                = mpic_get_coreint_irq,
+#endif
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
+
+machine_device_initcall(p5020_ds, corenet_ds_publish_devices);
+
+#ifdef CONFIG_SWIOTLB
+machine_arch_initcall(p5020_ds, swiotlb_setup_bus_notifier);
+#endif
index a6b106557be4ac6e15d45663a7ea3d28ee3bc36f..5c91a992f02b82049a6dbdaf21dc2974501f8b22 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/kexec.h>
+#include <linux/highmem.h>
 
 #include <asm/machdep.h>
 #include <asm/pgtable.h>
@@ -79,6 +80,7 @@ smp_85xx_kick_cpu(int nr)
        local_irq_save(flags);
 
        out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
+#ifdef CONFIG_PPC32
        out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
 
        if (!ioremappable)
@@ -88,6 +90,12 @@ smp_85xx_kick_cpu(int nr)
        /* Wait a bit for the CPU to ack. */
        while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
                mdelay(1);
+#else
+       out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER),
+               __pa((u64)*((unsigned long long *) generic_secondary_smp_init)));
+
+       smp_generic_kick_cpu(nr);
+#endif
 
        local_irq_restore(flags);
 
@@ -114,19 +122,15 @@ struct smp_ops_t smp_85xx_ops = {
 };
 
 #ifdef CONFIG_KEXEC
-static int kexec_down_cpus = 0;
+atomic_t kexec_down_cpus = ATOMIC_INIT(0);
 
 void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary)
 {
-       mpic_teardown_this_cpu(1);
-
-       /* When crashing, this gets called on all CPU's we only
-        * take down the non-boot cpus */
-       if (smp_processor_id() != boot_cpuid)
-       {
-               local_irq_disable();
-               kexec_down_cpus++;
+       local_irq_disable();
 
+       if (secondary) {
+               atomic_inc(&kexec_down_cpus);
+               /* loop forever */
                while (1);
        }
 }
@@ -137,16 +141,65 @@ static void mpc85xx_smp_kexec_down(void *arg)
                ppc_md.kexec_cpu_down(0,1);
 }
 
-static void mpc85xx_smp_machine_kexec(struct kimage *image)
+static void map_and_flush(unsigned long paddr)
 {
-       int timeout = 2000;
+       struct page *page = pfn_to_page(paddr >> PAGE_SHIFT);
+       unsigned long kaddr  = (unsigned long)kmap(page);
+
+       flush_dcache_range(kaddr, kaddr + PAGE_SIZE);
+       kunmap(page);
+}
+
+/**
+ * Before we reset the other cores, we need to flush relevant cache
+ * out to memory so we don't get anything corrupted, some of these flushes
+ * are performed out of an overabundance of caution as interrupts are not
+ * disabled yet and we can switch cores
+ */
+static void mpc85xx_smp_flush_dcache_kexec(struct kimage *image)
+{
+       kimage_entry_t *ptr, entry;
+       unsigned long paddr;
        int i;
 
-       set_cpus_allowed(current, cpumask_of_cpu(boot_cpuid));
+       if (image->type == KEXEC_TYPE_DEFAULT) {
+               /* normal kexec images are stored in temporary pages */
+               for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE);
+                    ptr = (entry & IND_INDIRECTION) ?
+                               phys_to_virt(entry & PAGE_MASK) : ptr + 1) {
+                       if (!(entry & IND_DESTINATION)) {
+                               map_and_flush(entry);
+                       }
+               }
+               /* flush out last IND_DONE page */
+               map_and_flush(entry);
+       } else {
+               /* crash type kexec images are copied to the crash region */
+               for (i = 0; i < image->nr_segments; i++) {
+                       struct kexec_segment *seg = &image->segment[i];
+                       for (paddr = seg->mem; paddr < seg->mem + seg->memsz;
+                            paddr += PAGE_SIZE) {
+                               map_and_flush(paddr);
+                       }
+               }
+       }
+
+       /* also flush the kimage struct to be passed in as well */
+       flush_dcache_range((unsigned long)image,
+                          (unsigned long)image + sizeof(*image));
+}
+
+static void mpc85xx_smp_machine_kexec(struct kimage *image)
+{
+       int timeout = INT_MAX;
+       int i, num_cpus = num_present_cpus();
+
+       mpc85xx_smp_flush_dcache_kexec(image);
 
-       smp_call_function(mpc85xx_smp_kexec_down, NULL, 0);
+       if (image->type == KEXEC_TYPE_DEFAULT)
+               smp_call_function(mpc85xx_smp_kexec_down, NULL, 0);
 
-       while ( (kexec_down_cpus != (num_online_cpus() - 1)) &&
+       while ( (atomic_read(&kexec_down_cpus) != (num_cpus - 1)) &&
                ( timeout > 0 ) )
        {
                timeout--;
@@ -155,7 +208,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image)
        if ( !timeout )
                printk(KERN_ERR "Unable to bring down secondary cpu(s)");
 
-       for (i = 0; i < num_present_cpus(); i++)
+       for (i = 0; i < num_cpus; i++)
        {
                if ( i == smp_processor_id() ) continue;
                mpic_reset_core(i);
index d361f8119b1e50680511535f0c373147d8267c43..111138c55f9c909e87cfa040d36316bd2ecda96c 100644 (file)
@@ -125,6 +125,7 @@ config 8xx
 
 config E500
        select FSL_EMB_PERFMON
+       select PPC_FSL_BOOK3E
        bool
 
 config PPC_E500MC
@@ -166,9 +167,14 @@ config BOOKE
 
 config FSL_BOOKE
        bool
-       depends on E200 || E500
+       depends on (E200 || E500) && PPC32
        default y
 
+# this is for common code between PPC32 & PPC64 FSL BOOKE
+config PPC_FSL_BOOK3E
+       bool
+       select FSL_EMB_PERFMON
+       default y if FSL_BOOKE
 
 config PTE_64BIT
        bool
index 97085530aa63b291c677dfbeb5e198b1859a0daf..e3e379c6caa79c6a423707d21b1e08face564534 100644 (file)
@@ -310,9 +310,9 @@ static void axon_msi_teardown_msi_irqs(struct pci_dev *dev)
 }
 
 static struct irq_chip msic_irq_chip = {
-       .mask           = mask_msi_irq,
-       .unmask         = unmask_msi_irq,
-       .shutdown       = unmask_msi_irq,
+       .irq_mask       = mask_msi_irq,
+       .irq_unmask     = unmask_msi_irq,
+       .irq_shutdown   = mask_msi_irq,
        .name           = "AXON-MSI",
 };
 
index 1d3c4effea10d1592acf1ea7fdd62370bef7055f..5ec1e47a0d771eba56e8b8c42111a19aed7df25a 100644 (file)
@@ -173,8 +173,10 @@ static int __init cbe_ptcal_enable(void)
                return -ENODEV;
 
        size = of_get_property(np, "ibm,cbe-ptcal-size", NULL);
-       if (!size)
+       if (!size) {
+               of_node_put(np);
                return -ENODEV;
+       }
 
        pr_debug("%s: enabling PTCAL, size = 0x%x\n", __func__, *size);
        order = get_order(*size);
index 5876e888e41251020c71495935125ea8bbe37f83..3f2e557344a31c719783923783c3b3275a7ef379 100644 (file)
@@ -258,8 +258,10 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
                return NO_IRQ;
        imap += intsize + 1;
        tmp = of_get_property(iic, "#interrupt-cells", NULL);
-       if (tmp == NULL)
+       if (tmp == NULL) {
+               of_node_put(iic);
                return NO_IRQ;
+       }
        intsize = *tmp;
        /* Assume unit is last entry of interrupt specifier */
        unit = imap[intsize - 1];
index 1a40da92154c99cab1568cf80d743eca5fab4d2c..02f7b113a31baf119c1528b04fdd319c156f770d 100644 (file)
@@ -154,6 +154,7 @@ static const struct file_operations __fops = {                              \
        .release = spufs_attr_release,                                  \
        .read    = spufs_attr_read,                                     \
        .write   = spufs_attr_write,                                    \
+       .llseek  = generic_file_llseek,                                 \
 };
 
 
@@ -521,6 +522,7 @@ static const struct file_operations spufs_cntl_fops = {
        .release = spufs_cntl_release,
        .read = simple_attr_read,
        .write = simple_attr_write,
+       .llseek = generic_file_llseek,
        .mmap = spufs_cntl_mmap,
 };
 
@@ -714,6 +716,7 @@ static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
 static const struct file_operations spufs_mbox_fops = {
        .open   = spufs_pipe_open,
        .read   = spufs_mbox_read,
+       .llseek = no_llseek,
 };
 
 static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
@@ -743,6 +746,7 @@ static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf,
 static const struct file_operations spufs_mbox_stat_fops = {
        .open   = spufs_pipe_open,
        .read   = spufs_mbox_stat_read,
+       .llseek = no_llseek,
 };
 
 /* low-level ibox access function */
@@ -863,6 +867,7 @@ static const struct file_operations spufs_ibox_fops = {
        .read   = spufs_ibox_read,
        .poll   = spufs_ibox_poll,
        .fasync = spufs_ibox_fasync,
+       .llseek = no_llseek,
 };
 
 static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
@@ -890,6 +895,7 @@ static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf,
 static const struct file_operations spufs_ibox_stat_fops = {
        .open   = spufs_pipe_open,
        .read   = spufs_ibox_stat_read,
+       .llseek = no_llseek,
 };
 
 /* low-level mailbox write */
@@ -1011,6 +1017,7 @@ static const struct file_operations spufs_wbox_fops = {
        .write  = spufs_wbox_write,
        .poll   = spufs_wbox_poll,
        .fasync = spufs_wbox_fasync,
+       .llseek = no_llseek,
 };
 
 static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
@@ -1038,6 +1045,7 @@ static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf,
 static const struct file_operations spufs_wbox_stat_fops = {
        .open   = spufs_pipe_open,
        .read   = spufs_wbox_stat_read,
+       .llseek = no_llseek,
 };
 
 static int spufs_signal1_open(struct inode *inode, struct file *file)
@@ -1166,6 +1174,7 @@ static const struct file_operations spufs_signal1_fops = {
        .read = spufs_signal1_read,
        .write = spufs_signal1_write,
        .mmap = spufs_signal1_mmap,
+       .llseek = no_llseek,
 };
 
 static const struct file_operations spufs_signal1_nosched_fops = {
@@ -1173,6 +1182,7 @@ static const struct file_operations spufs_signal1_nosched_fops = {
        .release = spufs_signal1_release,
        .write = spufs_signal1_write,
        .mmap = spufs_signal1_mmap,
+       .llseek = no_llseek,
 };
 
 static int spufs_signal2_open(struct inode *inode, struct file *file)
@@ -1305,6 +1315,7 @@ static const struct file_operations spufs_signal2_fops = {
        .read = spufs_signal2_read,
        .write = spufs_signal2_write,
        .mmap = spufs_signal2_mmap,
+       .llseek = no_llseek,
 };
 
 static const struct file_operations spufs_signal2_nosched_fops = {
@@ -1312,6 +1323,7 @@ static const struct file_operations spufs_signal2_nosched_fops = {
        .release = spufs_signal2_release,
        .write = spufs_signal2_write,
        .mmap = spufs_signal2_mmap,
+       .llseek = no_llseek,
 };
 
 /*
@@ -1451,6 +1463,7 @@ static const struct file_operations spufs_mss_fops = {
        .open    = spufs_mss_open,
        .release = spufs_mss_release,
        .mmap    = spufs_mss_mmap,
+       .llseek  = no_llseek,
 };
 
 static int
@@ -1508,6 +1521,7 @@ static const struct file_operations spufs_psmap_fops = {
        .open    = spufs_psmap_open,
        .release = spufs_psmap_release,
        .mmap    = spufs_psmap_mmap,
+       .llseek  = no_llseek,
 };
 
 
@@ -1871,6 +1885,7 @@ static const struct file_operations spufs_mfc_fops = {
        .fsync   = spufs_mfc_fsync,
        .fasync  = spufs_mfc_fasync,
        .mmap    = spufs_mfc_mmap,
+       .llseek  = no_llseek,
 };
 
 static int spufs_npc_set(void *data, u64 val)
@@ -2246,6 +2261,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
 static const struct file_operations spufs_dma_info_fops = {
        .open = spufs_info_open,
        .read = spufs_dma_info_read,
+       .llseek = no_llseek,
 };
 
 static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,
@@ -2299,6 +2315,7 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
 static const struct file_operations spufs_proxydma_info_fops = {
        .open = spufs_info_open,
        .read = spufs_proxydma_info_read,
+       .llseek = no_llseek,
 };
 
 static int spufs_show_tid(struct seq_file *s, void *private)
@@ -2585,6 +2602,7 @@ static const struct file_operations spufs_switch_log_fops = {
        .read           = spufs_switch_log_read,
        .poll           = spufs_switch_log_poll,
        .release        = spufs_switch_log_release,
+       .llseek         = no_llseek,
 };
 
 /**
index ba3588f2d8e0c2df441907788046d2f8128b092c..d3ceff04ffc79c6832b8b96087913e4fa02692e0 100644 (file)
@@ -74,8 +74,10 @@ void __init chrp_nvram_init(void)
                return;
 
        nbytes_p = of_get_property(nvram, "#bytes", &proplen);
-       if (nbytes_p == NULL || proplen != sizeof(unsigned int))
+       if (nbytes_p == NULL || proplen != sizeof(unsigned int)) {
+               of_node_put(nvram);
                return;
+       }
 
        nvram_size = *nbytes_p;
 
index 5cdcc7c8d9738416a8055840235ca5954d33abd2..649473a729b8843b251a2bbffaf26927b63ac15e 100644 (file)
@@ -65,7 +65,7 @@ static int __init page_aligned(unsigned long x)
 
 void __init wii_memory_fixups(void)
 {
-       struct memblock_property *p = memblock.memory.region;
+       struct memblock_region *p = memblock.memory.regions;
 
        /*
         * This is part of a workaround to allow the use of two
index ce014928d4605b9cf4489fe4e1d4e7a3a61b256f..a7602b11ed9d27e167bc77dd6bb2dfc56406e587 100644 (file)
@@ -1,4 +1,4 @@
-EXTRA_CFLAGS   += -mno-minimal-toc
+ccflags-y      := -mno-minimal-toc
 
 obj-y += exception.o
 obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \
index 7f45a51fe793eadd7816c7a8cd41715aa33239a1..fdb7384c0c4f3fe372207d4ad8bdc48a364a97c0 100644 (file)
@@ -243,7 +243,7 @@ static void __init dt_cpus(struct iseries_flat_dt *dt)
        pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE);
 
        for (i = 0; i < NR_CPUS; i++) {
-               if (lppaca[i].dyn_proc_status >= 2)
+               if (lppaca_of(i).dyn_proc_status >= 2)
                        continue;
 
                snprintf(p, 32 - (p - buf), "@%d", i);
@@ -251,7 +251,7 @@ static void __init dt_cpus(struct iseries_flat_dt *dt)
 
                dt_prop_str(dt, "device_type", device_type_cpu);
 
-               index = lppaca[i].dyn_hv_phys_proc_index;
+               index = lppaca_of(i).dyn_hv_phys_proc_index;
                d = &xIoHriProcessorVpd[index];
 
                dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024);
index 6590850045afe0c9c4d6184725cdb7d5ca29fb81..6c6029914dbc36380a8a94d1ef8438afb64701de 100644 (file)
@@ -91,7 +91,7 @@ static void smp_iSeries_kick_cpu(int nr)
        BUG_ON((nr < 0) || (nr >= NR_CPUS));
 
        /* Verify that our partition has a processor nr */
-       if (lppaca[nr].dyn_proc_status >= 2)
+       if (lppaca_of(nr).dyn_proc_status >= 2)
                return;
 
        /* The processor is currently spinning, waiting
index 3fff8d979b41a809743ca28e4234fcaa28e81400..fe34c3d9bb741739411dc5f156e17c3aa1215c33 100644 (file)
@@ -358,6 +358,7 @@ static int __init maple_cpc925_edac_setup(void)
        model = (const unsigned char *)of_get_property(np, "model", NULL);
        if (!model) {
                printk(KERN_ERR "%s: Unabel to get model info\n", __func__);
+               of_node_put(np);
                return -ENODEV;
        }
 
index cec6359426573d87a8d42a3439fc10393d8918ae..b0c3777528a1e418387e312b4ae75183aa2de8c8 100644 (file)
@@ -837,8 +837,10 @@ struct pmf_function *__pmf_find_function(struct device_node *target,
                return NULL;
  find_it:
        dev = pmf_find_device(actor);
-       if (dev == NULL)
-               return NULL;
+       if (dev == NULL) {
+               result = NULL;
+               goto out;
+       }
 
        list_for_each_entry(func, &dev->functions, link) {
                if (name && strcmp(name, func->name))
@@ -850,8 +852,9 @@ struct pmf_function *__pmf_find_function(struct device_node *target,
                result = func;
                break;
        }
-       of_node_put(actor);
        pmf_put_device(dev);
+out:
+       of_node_put(actor);
        return result;
 }
 
index 046ace9c43819b86efcb2b241ae6ed5ebd6d02a2..59eb8bdaa79d0be02611c01df68351c5bcbf3ff8 100644 (file)
@@ -1,14 +1,9 @@
-ifeq ($(CONFIG_PPC64),y)
-EXTRA_CFLAGS           += -mno-minimal-toc
-endif
-
-ifeq ($(CONFIG_PPC_PSERIES_DEBUG),y)
-EXTRA_CFLAGS           += -DDEBUG
-endif
+ccflags-$(CONFIG_PPC64)                        := -mno-minimal-toc
+ccflags-$(CONFIG_PPC_PSERIES_DEBUG)    += -DDEBUG
 
 obj-y                  := lpar.o hvCall.o nvram.o reconfig.o \
                           setup.o iommu.o event_sources.o ras.o \
-                          firmware.o power.o dlpar.o
+                          firmware.o power.o dlpar.o mobility.o
 obj-$(CONFIG_SMP)      += smp.o
 obj-$(CONFIG_XICS)     += xics.o
 obj-$(CONFIG_SCANLOG)  += scanlog.o
@@ -23,7 +18,7 @@ obj-$(CONFIG_MEMORY_HOTPLUG)  += hotplug-memory.o
 obj-$(CONFIG_HVC_CONSOLE)      += hvconsole.o
 obj-$(CONFIG_HVCS)             += hvcserver.o
 obj-$(CONFIG_HCALL_STATS)      += hvCall_inst.o
-obj-$(CONFIG_PHYP_DUMP)        += phyp_dump.o
+obj-$(CONFIG_PHYP_DUMP)                += phyp_dump.o
 obj-$(CONFIG_CMM)              += cmm.o
 obj-$(CONFIG_DTL)              += dtl.o
 
index 72d8054fa739055ddc03521aaa6e0ff961ca3670..b74a9230edc9a0454856b5f4cf18d730f9a0c05e 100644 (file)
@@ -33,7 +33,7 @@ struct cc_workarea {
        u32     prop_offset;
 };
 
-static void dlpar_free_cc_property(struct property *prop)
+void dlpar_free_cc_property(struct property *prop)
 {
        kfree(prop->name);
        kfree(prop->value);
@@ -55,13 +55,12 @@ static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa)
 
        prop->length = ccwa->prop_length;
        value = (char *)ccwa + ccwa->prop_offset;
-       prop->value = kzalloc(prop->length, GFP_KERNEL);
+       prop->value = kmemdup(value, prop->length, GFP_KERNEL);
        if (!prop->value) {
                dlpar_free_cc_property(prop);
                return NULL;
        }
 
-       memcpy(prop->value, value, prop->length);
        return prop;
 }
 
@@ -102,7 +101,7 @@ static void dlpar_free_one_cc_node(struct device_node *dn)
        kfree(dn);
 }
 
-static void dlpar_free_cc_nodes(struct device_node *dn)
+void dlpar_free_cc_nodes(struct device_node *dn)
 {
        if (dn->child)
                dlpar_free_cc_nodes(dn->child);
index a00addb559456e6c3ea69658887f630378863ff1..c371bc06434bf5f4121db3b4b6d79c7b64073e3c 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
+#include <linux/spinlock.h>
 #include <asm/smp.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/firmware.h>
+#include <asm/lppaca.h>
 
 #include "plpar_wrappers.h"
 
-/*
- * Layout of entries in the hypervisor's DTL buffer. Although we don't
- * actually access the internals of an entry (we only need to know the size),
- * we might as well define it here for reference.
- */
-struct dtl_entry {
-       u8      dispatch_reason;
-       u8      preempt_reason;
-       u16     processor_id;
-       u32     enqueue_to_dispatch_time;
-       u32     ready_to_enqueue_time;
-       u32     waiting_to_ready_time;
-       u64     timebase;
-       u64     fault_addr;
-       u64     srr0;
-       u64     srr1;
-};
-
 struct dtl {
        struct dtl_entry        *buf;
        struct dentry           *file;
        int                     cpu;
        int                     buf_entries;
        u64                     last_idx;
+       spinlock_t              lock;
 };
 static DEFINE_PER_CPU(struct dtl, cpu_dtl);
 
@@ -72,25 +57,97 @@ static u8 dtl_event_mask = 0x7;
 static int dtl_buf_entries = (16 * 85);
 
 
-static int dtl_enable(struct dtl *dtl)
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+struct dtl_ring {
+       u64     write_index;
+       struct dtl_entry *write_ptr;
+       struct dtl_entry *buf;
+       struct dtl_entry *buf_end;
+       u8      saved_dtl_mask;
+};
+
+static DEFINE_PER_CPU(struct dtl_ring, dtl_rings);
+
+static atomic_t dtl_count;
+
+/*
+ * The cpu accounting code controls the DTL ring buffer, and we get
+ * given entries as they are processed.
+ */
+static void consume_dtle(struct dtl_entry *dtle, u64 index)
 {
-       unsigned long addr;
-       int ret, hwcpu;
+       struct dtl_ring *dtlr = &__get_cpu_var(dtl_rings);
+       struct dtl_entry *wp = dtlr->write_ptr;
+       struct lppaca *vpa = local_paca->lppaca_ptr;
 
-       /* only allow one reader */
-       if (dtl->buf)
-               return -EBUSY;
+       if (!wp)
+               return;
 
-       /* we need to store the original allocation size for use during read */
-       dtl->buf_entries = dtl_buf_entries;
+       *wp = *dtle;
+       barrier();
 
-       dtl->buf = kmalloc_node(dtl->buf_entries * sizeof(struct dtl_entry),
-                       GFP_KERNEL, cpu_to_node(dtl->cpu));
-       if (!dtl->buf) {
-               printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n",
-                               __func__, dtl->cpu);
-               return -ENOMEM;
-       }
+       /* check for hypervisor ring buffer overflow, ignore this entry if so */
+       if (index + N_DISPATCH_LOG < vpa->dtl_idx)
+               return;
+
+       ++wp;
+       if (wp == dtlr->buf_end)
+               wp = dtlr->buf;
+       dtlr->write_ptr = wp;
+
+       /* incrementing write_index makes the new entry visible */
+       smp_wmb();
+       ++dtlr->write_index;
+}
+
+static int dtl_start(struct dtl *dtl)
+{
+       struct dtl_ring *dtlr = &per_cpu(dtl_rings, dtl->cpu);
+
+       dtlr->buf = dtl->buf;
+       dtlr->buf_end = dtl->buf + dtl->buf_entries;
+       dtlr->write_index = 0;
+
+       /* setting write_ptr enables logging into our buffer */
+       smp_wmb();
+       dtlr->write_ptr = dtl->buf;
+
+       /* enable event logging */
+       dtlr->saved_dtl_mask = lppaca_of(dtl->cpu).dtl_enable_mask;
+       lppaca_of(dtl->cpu).dtl_enable_mask |= dtl_event_mask;
+
+       dtl_consumer = consume_dtle;
+       atomic_inc(&dtl_count);
+       return 0;
+}
+
+static void dtl_stop(struct dtl *dtl)
+{
+       struct dtl_ring *dtlr = &per_cpu(dtl_rings, dtl->cpu);
+
+       dtlr->write_ptr = NULL;
+       smp_wmb();
+
+       dtlr->buf = NULL;
+
+       /* restore dtl_enable_mask */
+       lppaca_of(dtl->cpu).dtl_enable_mask = dtlr->saved_dtl_mask;
+
+       if (atomic_dec_and_test(&dtl_count))
+               dtl_consumer = NULL;
+}
+
+static u64 dtl_current_index(struct dtl *dtl)
+{
+       return per_cpu(dtl_rings, dtl->cpu).write_index;
+}
+
+#else /* CONFIG_VIRT_CPU_ACCOUNTING */
+
+static int dtl_start(struct dtl *dtl)
+{
+       unsigned long addr;
+       int ret, hwcpu;
 
        /* Register our dtl buffer with the hypervisor. The HV expects the
         * buffer size to be passed in the second word of the buffer */
@@ -102,34 +159,82 @@ static int dtl_enable(struct dtl *dtl)
        if (ret) {
                printk(KERN_WARNING "%s: DTL registration for cpu %d (hw %d) "
                       "failed with %d\n", __func__, dtl->cpu, hwcpu, ret);
-               kfree(dtl->buf);
                return -EIO;
        }
 
        /* set our initial buffer indices */
-       dtl->last_idx = lppaca[dtl->cpu].dtl_idx = 0;
+       lppaca_of(dtl->cpu).dtl_idx = 0;
 
        /* ensure that our updates to the lppaca fields have occurred before
         * we actually enable the logging */
        smp_wmb();
 
        /* enable event logging */
-       lppaca[dtl->cpu].dtl_enable_mask = dtl_event_mask;
+       lppaca_of(dtl->cpu).dtl_enable_mask = dtl_event_mask;
 
        return 0;
 }
 
-static void dtl_disable(struct dtl *dtl)
+static void dtl_stop(struct dtl *dtl)
 {
        int hwcpu = get_hard_smp_processor_id(dtl->cpu);
 
-       lppaca[dtl->cpu].dtl_enable_mask = 0x0;
+       lppaca_of(dtl->cpu).dtl_enable_mask = 0x0;
 
        unregister_dtl(hwcpu, __pa(dtl->buf));
+}
+
+static u64 dtl_current_index(struct dtl *dtl)
+{
+       return lppaca_of(dtl->cpu).dtl_idx;
+}
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+
+static int dtl_enable(struct dtl *dtl)
+{
+       long int n_entries;
+       long int rc;
+       struct dtl_entry *buf = NULL;
 
+       /* only allow one reader */
+       if (dtl->buf)
+               return -EBUSY;
+
+       n_entries = dtl_buf_entries;
+       buf = kmalloc_node(n_entries * sizeof(struct dtl_entry),
+                       GFP_KERNEL, cpu_to_node(dtl->cpu));
+       if (!buf) {
+               printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n",
+                               __func__, dtl->cpu);
+               return -ENOMEM;
+       }
+
+       spin_lock(&dtl->lock);
+       rc = -EBUSY;
+       if (!dtl->buf) {
+               /* store the original allocation size for use during read */
+               dtl->buf_entries = n_entries;
+               dtl->buf = buf;
+               dtl->last_idx = 0;
+               rc = dtl_start(dtl);
+               if (rc)
+                       dtl->buf = NULL;
+       }
+       spin_unlock(&dtl->lock);
+
+       if (rc)
+               kfree(buf);
+       return rc;
+}
+
+static void dtl_disable(struct dtl *dtl)
+{
+       spin_lock(&dtl->lock);
+       dtl_stop(dtl);
        kfree(dtl->buf);
        dtl->buf = NULL;
        dtl->buf_entries = 0;
+       spin_unlock(&dtl->lock);
 }
 
 /* file interface */
@@ -157,8 +262,9 @@ static int dtl_file_release(struct inode *inode, struct file *filp)
 static ssize_t dtl_file_read(struct file *filp, char __user *buf, size_t len,
                loff_t *pos)
 {
-       int rc, cur_idx, last_idx, n_read, n_req, read_size;
+       long int rc, n_read, n_req, read_size;
        struct dtl *dtl;
+       u64 cur_idx, last_idx, i;
 
        if ((len % sizeof(struct dtl_entry)) != 0)
                return -EINVAL;
@@ -171,41 +277,48 @@ static ssize_t dtl_file_read(struct file *filp, char __user *buf, size_t len,
        /* actual number of entries read */
        n_read = 0;
 
-       cur_idx = lppaca[dtl->cpu].dtl_idx;
+       spin_lock(&dtl->lock);
+
+       cur_idx = dtl_current_index(dtl);
        last_idx = dtl->last_idx;
 
-       if (cur_idx - last_idx > dtl->buf_entries) {
-               pr_debug("%s: hv buffer overflow for cpu %d, samples lost\n",
-                               __func__, dtl->cpu);
-       }
+       if (last_idx + dtl->buf_entries <= cur_idx)
+               last_idx = cur_idx - dtl->buf_entries + 1;
+
+       if (last_idx + n_req > cur_idx)
+               n_req = cur_idx - last_idx;
+
+       if (n_req > 0)
+               dtl->last_idx = last_idx + n_req;
+
+       spin_unlock(&dtl->lock);
+
+       if (n_req <= 0)
+               return 0;
 
-       cur_idx  %= dtl->buf_entries;
-       last_idx %= dtl->buf_entries;
+       i = last_idx % dtl->buf_entries;
 
        /* read the tail of the buffer if we've wrapped */
-       if (last_idx > cur_idx) {
-               read_size = min(n_req, dtl->buf_entries - last_idx);
+       if (i + n_req > dtl->buf_entries) {
+               read_size = dtl->buf_entries - i;
 
-               rc = copy_to_user(buf, &dtl->buf[last_idx],
+               rc = copy_to_user(buf, &dtl->buf[i],
                                read_size * sizeof(struct dtl_entry));
                if (rc)
                        return -EFAULT;
 
-               last_idx = 0;
+               i = 0;
                n_req -= read_size;
                n_read += read_size;
                buf += read_size * sizeof(struct dtl_entry);
        }
 
        /* .. and now the head */
-       read_size = min(n_req, cur_idx - last_idx);
-       rc = copy_to_user(buf, &dtl->buf[last_idx],
-                       read_size * sizeof(struct dtl_entry));
+       rc = copy_to_user(buf, &dtl->buf[i], n_req * sizeof(struct dtl_entry));
        if (rc)
                return -EFAULT;
 
-       n_read += read_size;
-       dtl->last_idx += n_read;
+       n_read += n_req;
 
        return n_read * sizeof(struct dtl_entry);
 }
@@ -263,6 +376,7 @@ static int dtl_init(void)
        /* set up the per-cpu log structures */
        for_each_possible_cpu(i) {
                struct dtl *dtl = &per_cpu(cpu_dtl, i);
+               spin_lock_init(&dtl->lock);
                dtl->cpu = i;
 
                rc = dtl_setup_file(dtl);
index cf79b46d8f885539d28bc4ca9bcb4f766a2e107c..f129040d974ce2a9faffc1d0899d6eb7410dc31e 100644 (file)
@@ -248,11 +248,13 @@ void vpa_init(int cpu)
        int hwcpu = get_hard_smp_processor_id(cpu);
        unsigned long addr;
        long ret;
+       struct paca_struct *pp;
+       struct dtl_entry *dtl;
 
        if (cpu_has_feature(CPU_FTR_ALTIVEC))
-               lppaca[cpu].vmxregs_in_use = 1;
+               lppaca_of(cpu).vmxregs_in_use = 1;
 
-       addr = __pa(&lppaca[cpu]);
+       addr = __pa(&lppaca_of(cpu));
        ret = register_vpa(hwcpu, addr);
 
        if (ret) {
@@ -274,6 +276,25 @@ void vpa_init(int cpu)
                               "registration for cpu %d (hw %d) of area %lx "
                               "returns %ld\n", cpu, hwcpu, addr, ret);
        }
+
+       /*
+        * Register dispatch trace log, if one has been allocated.
+        */
+       pp = &paca[cpu];
+       dtl = pp->dispatch_log;
+       if (dtl) {
+               pp->dtl_ridx = 0;
+               pp->dtl_curr = dtl;
+               lppaca_of(cpu).dtl_idx = 0;
+
+               /* hypervisor reads buffer length from this field */
+               dtl->enqueue_to_dispatch_time = DISPATCH_LOG_BYTES;
+               ret = register_dtl(hwcpu, __pa(dtl));
+               if (ret)
+                       pr_warn("DTL registration failed for cpu %d (%ld)\n",
+                               cpu, ret);
+               lppaca_of(cpu).dtl_enable_mask = 2;
+       }
 }
 
 static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
new file mode 100644 (file)
index 0000000..3e7f651
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Support for Partition Mobility/Migration
+ *
+ * Copyright (C) 2010 Nathan Fontenot
+ * Copyright (C) 2010 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kobject.h>
+#include <linux/smp.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include <asm/rtas.h>
+#include "pseries.h"
+
+static struct kobject *mobility_kobj;
+
+struct update_props_workarea {
+       u32 phandle;
+       u32 state;
+       u64 reserved;
+       u32 nprops;
+};
+
+#define NODE_ACTION_MASK       0xff000000
+#define NODE_COUNT_MASK                0x00ffffff
+
+#define DELETE_DT_NODE 0x01000000
+#define UPDATE_DT_NODE 0x02000000
+#define ADD_DT_NODE    0x03000000
+
+static int mobility_rtas_call(int token, char *buf)
+{
+       int rc;
+
+       spin_lock(&rtas_data_buf_lock);
+
+       memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE);
+       rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, 1);
+       memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
+
+       spin_unlock(&rtas_data_buf_lock);
+       return rc;
+}
+
+static int delete_dt_node(u32 phandle)
+{
+       struct device_node *dn;
+
+       dn = of_find_node_by_phandle(phandle);
+       if (!dn)
+               return -ENOENT;
+
+       dlpar_detach_node(dn);
+       return 0;
+}
+
+static int update_dt_property(struct device_node *dn, struct property **prop,
+                             const char *name, u32 vd, char *value)
+{
+       struct property *new_prop = *prop;
+       struct property *old_prop;
+       int more = 0;
+
+       /* A negative 'vd' value indicates that only part of the new property
+        * value is contained in the buffer and we need to call
+        * ibm,update-properties again to get the rest of the value.
+        *
+        * A negative value is also the two's compliment of the actual value.
+        */
+       if (vd & 0x80000000) {
+               vd = ~vd + 1;
+               more = 1;
+       }
+
+       if (new_prop) {
+               /* partial property fixup */
+               char *new_data = kzalloc(new_prop->length + vd, GFP_KERNEL);
+               if (!new_data)
+                       return -ENOMEM;
+
+               memcpy(new_data, new_prop->value, new_prop->length);
+               memcpy(new_data + new_prop->length, value, vd);
+
+               kfree(new_prop->value);
+               new_prop->value = new_data;
+               new_prop->length += vd;
+       } else {
+               new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
+               if (!new_prop)
+                       return -ENOMEM;
+
+               new_prop->name = kstrdup(name, GFP_KERNEL);
+               if (!new_prop->name) {
+                       kfree(new_prop);
+                       return -ENOMEM;
+               }
+
+               new_prop->length = vd;
+               new_prop->value = kzalloc(new_prop->length, GFP_KERNEL);
+               if (!new_prop->value) {
+                       kfree(new_prop->name);
+                       kfree(new_prop);
+                       return -ENOMEM;
+               }
+
+               memcpy(new_prop->value, value, vd);
+               *prop = new_prop;
+       }
+
+       if (!more) {
+               old_prop = of_find_property(dn, new_prop->name, NULL);
+               if (old_prop)
+                       prom_update_property(dn, new_prop, old_prop);
+               else
+                       prom_add_property(dn, new_prop);
+
+               new_prop = NULL;
+       }
+
+       return 0;
+}
+
+static int update_dt_node(u32 phandle)
+{
+       struct update_props_workarea *upwa;
+       struct device_node *dn;
+       struct property *prop = NULL;
+       int i, rc;
+       char *prop_data;
+       char *rtas_buf;
+       int update_properties_token;
+
+       update_properties_token = rtas_token("ibm,update-properties");
+       if (update_properties_token == RTAS_UNKNOWN_SERVICE)
+               return -EINVAL;
+
+       rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+       if (!rtas_buf)
+               return -ENOMEM;
+
+       dn = of_find_node_by_phandle(phandle);
+       if (!dn) {
+               kfree(rtas_buf);
+               return -ENOENT;
+       }
+
+       upwa = (struct update_props_workarea *)&rtas_buf[0];
+       upwa->phandle = phandle;
+
+       do {
+               rc = mobility_rtas_call(update_properties_token, rtas_buf);
+               if (rc < 0)
+                       break;
+
+               prop_data = rtas_buf + sizeof(*upwa);
+
+               for (i = 0; i < upwa->nprops; i++) {
+                       char *prop_name;
+                       u32 vd;
+
+                       prop_name = prop_data + 1;
+                       prop_data += strlen(prop_name) + 1;
+                       vd = *prop_data++;
+
+                       switch (vd) {
+                       case 0x00000000:
+                               /* name only property, nothing to do */
+                               break;
+
+                       case 0x80000000:
+                               prop = of_find_property(dn, prop_name, NULL);
+                               prom_remove_property(dn, prop);
+                               prop = NULL;
+                               break;
+
+                       default:
+                               rc = update_dt_property(dn, &prop, prop_name,
+                                                       vd, prop_data);
+                               if (rc) {
+                                       printk(KERN_ERR "Could not update %s"
+                                              " property\n", prop_name);
+                               }
+
+                               prop_data += vd;
+                       }
+               }
+       } while (rc == 1);
+
+       of_node_put(dn);
+       kfree(rtas_buf);
+       return 0;
+}
+
+static int add_dt_node(u32 parent_phandle, u32 drc_index)
+{
+       struct device_node *dn;
+       struct device_node *parent_dn;
+       int rc;
+
+       dn = dlpar_configure_connector(drc_index);
+       if (!dn)
+               return -ENOENT;
+
+       parent_dn = of_find_node_by_phandle(parent_phandle);
+       if (!parent_dn) {
+               dlpar_free_cc_nodes(dn);
+               return -ENOENT;
+       }
+
+       dn->parent = parent_dn;
+       rc = dlpar_attach_node(dn);
+       if (rc)
+               dlpar_free_cc_nodes(dn);
+
+       of_node_put(parent_dn);
+       return rc;
+}
+
+static int pseries_devicetree_update(void)
+{
+       char *rtas_buf;
+       u32 *data;
+       int update_nodes_token;
+       int rc;
+
+       update_nodes_token = rtas_token("ibm,update-nodes");
+       if (update_nodes_token == RTAS_UNKNOWN_SERVICE)
+               return -EINVAL;
+
+       rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
+       if (!rtas_buf)
+               return -ENOMEM;
+
+       do {
+               rc = mobility_rtas_call(update_nodes_token, rtas_buf);
+               if (rc && rc != 1)
+                       break;
+
+               data = (u32 *)rtas_buf + 4;
+               while (*data & NODE_ACTION_MASK) {
+                       int i;
+                       u32 action = *data & NODE_ACTION_MASK;
+                       int node_count = *data & NODE_COUNT_MASK;
+
+                       data++;
+
+                       for (i = 0; i < node_count; i++) {
+                               u32 phandle = *data++;
+                               u32 drc_index;
+
+                               switch (action) {
+                               case DELETE_DT_NODE:
+                                       delete_dt_node(phandle);
+                                       break;
+                               case UPDATE_DT_NODE:
+                                       update_dt_node(phandle);
+                                       break;
+                               case ADD_DT_NODE:
+                                       drc_index = *data++;
+                                       add_dt_node(phandle, drc_index);
+                                       break;
+                               }
+                       }
+               }
+       } while (rc == 1);
+
+       kfree(rtas_buf);
+       return rc;
+}
+
+void post_mobility_fixup(void)
+{
+       int rc;
+       int activate_fw_token;
+
+       rc = pseries_devicetree_update();
+       if (rc) {
+               printk(KERN_ERR "Initial post-mobility device tree update "
+                      "failed: %d\n", rc);
+               return;
+       }
+
+       activate_fw_token = rtas_token("ibm,activate-firmware");
+       if (activate_fw_token == RTAS_UNKNOWN_SERVICE) {
+               printk(KERN_ERR "Could not make post-mobility "
+                      "activate-fw call.\n");
+               return;
+       }
+
+       rc = rtas_call(activate_fw_token, 0, 1, NULL);
+       if (!rc) {
+               rc = pseries_devicetree_update();
+               if (rc)
+                       printk(KERN_ERR "Secondary post-mobility device tree "
+                              "update failed: %d\n", rc);
+       } else {
+               printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc);
+               return;
+       }
+
+       return;
+}
+
+static ssize_t migrate_store(struct class *class, struct class_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct rtas_args args;
+       u64 streamid;
+       int rc;
+
+       rc = strict_strtoull(buf, 0, &streamid);
+       if (rc)
+               return rc;
+
+       memset(&args, 0, sizeof(args));
+       args.token = rtas_token("ibm,suspend-me");
+       args.nargs = 2;
+       args.nret = 1;
+
+       args.args[0] = streamid >> 32 ;
+       args.args[1] = streamid & 0xffffffff;
+       args.rets = &args.args[args.nargs];
+
+       do {
+               args.rets[0] = 0;
+               rc = rtas_ibm_suspend_me(&args);
+               if (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE)
+                       ssleep(1);
+       } while (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE);
+
+       if (rc)
+               return rc;
+       else if (args.rets[0])
+               return args.rets[0];
+
+       post_mobility_fixup();
+       return count;
+}
+
+static CLASS_ATTR(migration, S_IWUSR, NULL, migrate_store);
+
+static int __init mobility_sysfs_init(void)
+{
+       int rc;
+
+       mobility_kobj = kobject_create_and_add("mobility", kernel_kobj);
+       if (!mobility_kobj)
+               return -ENOMEM;
+
+       rc = sysfs_create_file(mobility_kobj, &class_attr_migration.attr);
+
+       return rc;
+}
+device_initcall(mobility_sysfs_init);
index 40c93cad91d211e05dd2b4362068a14ce7701f45..e9f6d2859c3cf3dd67b5a27a34fd77992d56b4cc 100644 (file)
@@ -17,6 +17,8 @@ struct device_node;
 extern void request_event_sources_irqs(struct device_node *np,
                                       irq_handler_t handler, const char *name);
 
+#include <linux/of.h>
+
 extern void __init fw_feature_init(const char *hypertas, unsigned long len);
 
 struct pt_regs;
@@ -47,4 +49,11 @@ extern unsigned long rtas_poweron_auto;
 
 extern void find_udbg_vterm(void);
 
+/* Dynamic logical Partitioning/Mobility */
+extern void dlpar_free_cc_nodes(struct device_node *);
+extern void dlpar_free_cc_property(struct property *);
+extern struct device_node *dlpar_configure_connector(u32);
+extern int dlpar_attach_node(struct device_node *);
+extern int dlpar_detach_node(struct device_node *);
+
 #endif /* _PSERIES_PSERIES_H */
index a6d19e3a505e62b15958573ca7f95a093aef5394..d345bfd56bbe35ead2c45e166704a98264524bf9 100644 (file)
@@ -273,6 +273,58 @@ static struct notifier_block pci_dn_reconfig_nb = {
        .notifier_call = pci_dn_reconfig_notifier,
 };
 
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+/*
+ * Allocate space for the dispatch trace log for all possible cpus
+ * and register the buffers with the hypervisor.  This is used for
+ * computing time stolen by the hypervisor.
+ */
+static int alloc_dispatch_logs(void)
+{
+       int cpu, ret;
+       struct paca_struct *pp;
+       struct dtl_entry *dtl;
+
+       if (!firmware_has_feature(FW_FEATURE_SPLPAR))
+               return 0;
+
+       for_each_possible_cpu(cpu) {
+               pp = &paca[cpu];
+               dtl = kmalloc_node(DISPATCH_LOG_BYTES, GFP_KERNEL,
+                                  cpu_to_node(cpu));
+               if (!dtl) {
+                       pr_warn("Failed to allocate dispatch trace log for cpu %d\n",
+                               cpu);
+                       pr_warn("Stolen time statistics will be unreliable\n");
+                       break;
+               }
+
+               pp->dtl_ridx = 0;
+               pp->dispatch_log = dtl;
+               pp->dispatch_log_end = dtl + N_DISPATCH_LOG;
+               pp->dtl_curr = dtl;
+       }
+
+       /* Register the DTL for the current (boot) cpu */
+       dtl = get_paca()->dispatch_log;
+       get_paca()->dtl_ridx = 0;
+       get_paca()->dtl_curr = dtl;
+       get_paca()->lppaca_ptr->dtl_idx = 0;
+
+       /* hypervisor reads buffer length from this field */
+       dtl->enqueue_to_dispatch_time = DISPATCH_LOG_BYTES;
+       ret = register_dtl(hard_smp_processor_id(), __pa(dtl));
+       if (ret)
+               pr_warn("DTL registration failed for boot cpu %d (%d)\n",
+                       smp_processor_id(), ret);
+       get_paca()->lppaca_ptr->dtl_enable_mask = 2;
+
+       return 0;
+}
+
+early_initcall(alloc_dispatch_logs);
+#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+
 static void __init pSeries_setup_arch(void)
 {
        /* Discover PIC type and setup ppc_md accordingly */
index 93834b0d8272231f5c9376784bc5e82bd98c9e38..7b96e5a270ce7b768ad13a8f4de2de3d84f4c692 100644 (file)
@@ -178,7 +178,7 @@ static int get_irq_server(unsigned int virq, const struct cpumask *cpumask,
        if (!distribute_irqs)
                return default_server;
 
-       if (!cpumask_equal(cpumask, cpu_all_mask)) {
+       if (!cpumask_subset(cpu_possible_mask, cpumask)) {
                int server = cpumask_first_and(cpu_online_mask, cpumask);
 
                if (server < nr_cpu_ids)
@@ -243,7 +243,7 @@ static unsigned int xics_startup(unsigned int virq)
         * at that level, so we do it here by hand.
         */
        if (irq_to_desc(virq)->msi_desc)
-               unmask_msi_irq(virq);
+               unmask_msi_irq(irq_get_irq_data(virq));
 
        /* unmask it */
        xics_unmask_irq(virq);
index 5642924fb9fb437637d4fe963253ce9d0b75a58d..0bef9dacb64e4586ef16dca61434604663204e8e 100644 (file)
@@ -1,8 +1,6 @@
 subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
-ifeq ($(CONFIG_PPC64),y)
-EXTRA_CFLAGS                   += -mno-minimal-toc
-endif
+ccflags-$(CONFIG_PPC64)                := -mno-minimal-toc
 
 mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
 obj-$(CONFIG_MPIC)             += mpic.o $(mpic-msi-obj-y)
@@ -20,6 +18,7 @@ obj-$(CONFIG_FSL_PMC)         += fsl_pmc.o
 obj-$(CONFIG_FSL_LBC)          += fsl_lbc.o
 obj-$(CONFIG_FSL_GTM)          += fsl_gtm.o
 obj-$(CONFIG_MPC8xxx_GPIO)     += mpc8xxx_gpio.o
+obj-$(CONFIG_FSL_85XX_CACHE_SRAM)      += fsl_85xx_l2ctlr.o fsl_85xx_cache_sram.o
 obj-$(CONFIG_SIMPLE_GPIO)      += simple_gpio.o
 obj-$(CONFIG_RAPIDIO)          += fsl_rio.o
 obj-$(CONFIG_TSI108_BRIDGE)    += tsi108_pci.o tsi108_dev.o
index 559db2b846a9dcd4428d4feb0467ff14bdd4cdbc..17cf15ec38be1d111eab991ebe74c6c9b6279e27 100644 (file)
@@ -70,6 +70,8 @@ static int iommu_table_dart_inited;
 static int dart_dirty;
 static int dart_is_u4;
 
+#define DART_U4_BYPASS_BASE    0x8000000000ull
+
 #define DBG(...)
 
 static inline void dart_tlb_invalidate_all(void)
@@ -292,12 +294,20 @@ static void iommu_table_dart_setup(void)
        set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map);
 }
 
-static void pci_dma_dev_setup_dart(struct pci_dev *dev)
+static void dma_dev_setup_dart(struct device *dev)
 {
        /* We only have one iommu table on the mac for now, which makes
         * things simple. Setup all PCI devices to point to this table
         */
-       set_iommu_table_base(&dev->dev, &iommu_table_dart);
+       if (get_dma_ops(dev) == &dma_direct_ops)
+               set_dma_offset(dev, DART_U4_BYPASS_BASE);
+       else
+               set_iommu_table_base(dev, &iommu_table_dart);
+}
+
+static void pci_dma_dev_setup_dart(struct pci_dev *dev)
+{
+       dma_dev_setup_dart(&dev->dev);
 }
 
 static void pci_dma_bus_setup_dart(struct pci_bus *bus)
@@ -315,6 +325,45 @@ static void pci_dma_bus_setup_dart(struct pci_bus *bus)
                PCI_DN(dn)->iommu_table = &iommu_table_dart;
 }
 
+static bool dart_device_on_pcie(struct device *dev)
+{
+       struct device_node *np = of_node_get(dev->of_node);
+
+       while(np) {
+               if (of_device_is_compatible(np, "U4-pcie") ||
+                   of_device_is_compatible(np, "u4-pcie")) {
+                       of_node_put(np);
+                       return true;
+               }
+               np = of_get_next_parent(np);
+       }
+       return false;
+}
+
+static int dart_dma_set_mask(struct device *dev, u64 dma_mask)
+{
+       if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+               return -EIO;
+
+       /* U4 supports a DART bypass, we use it for 64-bit capable
+        * devices to improve performances. However, that only works
+        * for devices connected to U4 own PCIe interface, not bridged
+        * through hypertransport. We need the device to support at
+        * least 40 bits of addresses.
+        */
+       if (dart_device_on_pcie(dev) && dma_mask >= DMA_BIT_MASK(40)) {
+               dev_info(dev, "Using 64-bit DMA iommu bypass\n");
+               set_dma_ops(dev, &dma_direct_ops);
+       } else {
+               dev_info(dev, "Using 32-bit DMA via iommu\n");
+               set_dma_ops(dev, &dma_iommu_ops);
+       }
+       dma_dev_setup_dart(dev);
+
+       *dev->dma_mask = dma_mask;
+       return 0;
+}
+
 void __init iommu_init_early_dart(void)
 {
        struct device_node *dn;
@@ -328,20 +377,25 @@ void __init iommu_init_early_dart(void)
                dart_is_u4 = 1;
        }
 
+       /* Initialize the DART HW */
+       if (dart_init(dn) != 0)
+               goto bail;
+
        /* Setup low level TCE operations for the core IOMMU code */
        ppc_md.tce_build = dart_build;
        ppc_md.tce_free  = dart_free;
        ppc_md.tce_flush = dart_flush;
 
-       /* Initialize the DART HW */
-       if (dart_init(dn) == 0) {
-               ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart;
-               ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
+       /* Setup bypass if supported */
+       if (dart_is_u4)
+               ppc_md.dma_set_mask = dart_dma_set_mask;
 
-               /* Setup pci_dma ops */
-               set_pci_dma_ops(&dma_iommu_ops);
-               return;
-       }
+       ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart;
+       ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
+
+       /* Setup pci_dma ops */
+       set_pci_dma_ops(&dma_iommu_ops);
+       return;
 
  bail:
        /* If init failed, use direct iommu and null setup functions */
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h b/arch/powerpc/sysdev/fsl_85xx_cache_ctlr.h
new file mode 100644 (file)
index 0000000..60c9c0b
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc
+ *
+ * QorIQ based Cache Controller Memory Mapped Registers
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __FSL_85XX_CACHE_CTLR_H__
+#define __FSL_85XX_CACHE_CTLR_H__
+
+#define L2CR_L2FI              0x40000000      /* L2 flash invalidate */
+#define L2CR_L2IO              0x00200000      /* L2 instruction only */
+#define L2CR_SRAM_ZERO         0x00000000      /* L2SRAM zero size */
+#define L2CR_SRAM_FULL         0x00010000      /* L2SRAM full size */
+#define L2CR_SRAM_HALF         0x00020000      /* L2SRAM half size */
+#define L2CR_SRAM_TWO_HALFS    0x00030000      /* L2SRAM two half sizes */
+#define L2CR_SRAM_QUART                0x00040000      /* L2SRAM one quarter size */
+#define L2CR_SRAM_TWO_QUARTS   0x00050000      /* L2SRAM two quarter size */
+#define L2CR_SRAM_EIGHTH       0x00060000      /* L2SRAM one eighth size */
+#define L2CR_SRAM_TWO_EIGHTH   0x00070000      /* L2SRAM two eighth size */
+
+#define L2SRAM_OPTIMAL_SZ_SHIFT        0x00000003      /* Optimum size for L2SRAM */
+
+#define L2SRAM_BAR_MSK_LO18    0xFFFFC000      /* Lower 18 bits */
+#define L2SRAM_BARE_MSK_HI4    0x0000000F      /* Upper 4 bits */
+
+enum cache_sram_lock_ways {
+       LOCK_WAYS_ZERO,
+       LOCK_WAYS_EIGHTH,
+       LOCK_WAYS_TWO_EIGHTH,
+       LOCK_WAYS_HALF = 4,
+       LOCK_WAYS_FULL = 8,
+};
+
+struct mpc85xx_l2ctlr {
+       u32     ctl;            /* 0x000 - L2 control */
+       u8      res1[0xC];
+       u32     ewar0;          /* 0x010 - External write address 0 */
+       u32     ewarea0;        /* 0x014 - External write address extended 0 */
+       u32     ewcr0;          /* 0x018 - External write ctrl */
+       u8      res2[4];
+       u32     ewar1;          /* 0x020 - External write address 1 */
+       u32     ewarea1;        /* 0x024 - External write address extended 1 */
+       u32     ewcr1;          /* 0x028 - External write ctrl 1 */
+       u8      res3[4];
+       u32     ewar2;          /* 0x030 - External write address 2 */
+       u32     ewarea2;        /* 0x034 - External write address extended 2 */
+       u32     ewcr2;          /* 0x038 - External write ctrl 2 */
+       u8      res4[4];
+       u32     ewar3;          /* 0x040 - External write address 3 */
+       u32     ewarea3;        /* 0x044 - External write address extended 3 */
+       u32     ewcr3;          /* 0x048 - External write ctrl 3 */
+       u8      res5[0xB4];
+       u32     srbar0;         /* 0x100 - SRAM base address 0 */
+       u32     srbarea0;       /* 0x104 - SRAM base addr reg ext address 0 */
+       u32     srbar1;         /* 0x108 - SRAM base address 1 */
+       u32     srbarea1;       /* 0x10C - SRAM base addr reg ext address 1 */
+       u8      res6[0xCF0];
+       u32     errinjhi;       /* 0xE00 - Error injection mask high */
+       u32     errinjlo;       /* 0xE04 - Error injection mask low */
+       u32     errinjctl;      /* 0xE08 - Error injection tag/ecc control */
+       u8      res7[0x14];
+       u32     captdatahi;     /* 0xE20 - Error data high capture */
+       u32     captdatalo;     /* 0xE24 - Error data low capture */
+       u32     captecc;        /* 0xE28 - Error syndrome */
+       u8      res8[0x14];
+       u32     errdet;         /* 0xE40 - Error detect */
+       u32     errdis;         /* 0xE44 - Error disable */
+       u32     errinten;       /* 0xE48 - Error interrupt enable */
+       u32     errattr;        /* 0xE4c - Error attribute capture */
+       u32     erradrrl;       /* 0xE50 - Error address capture low */
+       u32     erradrrh;       /* 0xE54 - Error address capture high */
+       u32     errctl;         /* 0xE58 - Error control */
+       u8      res9[0x1A4];
+};
+
+struct sram_parameters {
+       unsigned int sram_size;
+       uint64_t sram_offset;
+};
+
+extern int instantiate_cache_sram(struct platform_device *dev,
+               struct sram_parameters sram_params);
+extern void remove_cache_sram(struct platform_device *dev);
+
+#endif /* __FSL_85XX_CACHE_CTLR_H__ */
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
new file mode 100644 (file)
index 0000000..54fb192
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * Simple memory allocator abstraction for QorIQ (P1/P2) based Cache-SRAM
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * This file is derived from the original work done
+ * by Sylvain Munaut for the Bestcomm SRAM allocator.
+ *
+ * This program is free software; you can redistribute  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/slab.h>
+#include <linux/err.h>
+#include <linux/of_platform.h>
+#include <asm/pgtable.h>
+#include <asm/fsl_85xx_cache_sram.h>
+
+#include "fsl_85xx_cache_ctlr.h"
+
+struct mpc85xx_cache_sram *cache_sram;
+
+void *mpc85xx_cache_sram_alloc(unsigned int size,
+                               phys_addr_t *phys, unsigned int align)
+{
+       unsigned long offset;
+       unsigned long flags;
+
+       if (unlikely(cache_sram == NULL))
+               return NULL;
+
+       if (!size || (size > cache_sram->size) || (align > cache_sram->size)) {
+               pr_err("%s(): size(=%x) or align(=%x) zero or too big\n",
+                       __func__, size, align);
+               return NULL;
+       }
+
+       if ((align & (align - 1)) || align <= 1) {
+               pr_err("%s(): align(=%x) must be power of two and >1\n",
+                       __func__, align);
+               return NULL;
+       }
+
+       spin_lock_irqsave(&cache_sram->lock, flags);
+       offset = rh_alloc_align(cache_sram->rh, size, align, NULL);
+       spin_unlock_irqrestore(&cache_sram->lock, flags);
+
+       if (IS_ERR_VALUE(offset))
+               return NULL;
+
+       *phys = cache_sram->base_phys + offset;
+
+       return (unsigned char *)cache_sram->base_virt + offset;
+}
+EXPORT_SYMBOL(mpc85xx_cache_sram_alloc);
+
+void mpc85xx_cache_sram_free(void *ptr)
+{
+       unsigned long flags;
+       BUG_ON(!ptr);
+
+       spin_lock_irqsave(&cache_sram->lock, flags);
+       rh_free(cache_sram->rh, ptr - cache_sram->base_virt);
+       spin_unlock_irqrestore(&cache_sram->lock, flags);
+}
+EXPORT_SYMBOL(mpc85xx_cache_sram_free);
+
+int __init instantiate_cache_sram(struct platform_device *dev,
+               struct sram_parameters sram_params)
+{
+       int ret = 0;
+
+       if (cache_sram) {
+               dev_err(&dev->dev, "Already initialized cache-sram\n");
+               return -EBUSY;
+       }
+
+       cache_sram = kzalloc(sizeof(struct mpc85xx_cache_sram), GFP_KERNEL);
+       if (!cache_sram) {
+               dev_err(&dev->dev, "Out of memory for cache_sram structure\n");
+               return -ENOMEM;
+       }
+
+       cache_sram->base_phys = sram_params.sram_offset;
+       cache_sram->size = sram_params.sram_size;
+
+       if (!request_mem_region(cache_sram->base_phys, cache_sram->size,
+                                               "fsl_85xx_cache_sram")) {
+               dev_err(&dev->dev, "%s: request memory failed\n",
+                               dev->dev.of_node->full_name);
+               ret = -ENXIO;
+               goto out_free;
+       }
+
+       cache_sram->base_virt = ioremap_flags(cache_sram->base_phys,
+                               cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL);
+       if (!cache_sram->base_virt) {
+               dev_err(&dev->dev, "%s: ioremap_flags failed\n",
+                               dev->dev.of_node->full_name);
+               ret = -ENOMEM;
+               goto out_release;
+       }
+
+       cache_sram->rh = rh_create(sizeof(unsigned int));
+       if (IS_ERR(cache_sram->rh)) {
+               dev_err(&dev->dev, "%s: Unable to create remote heap\n",
+                               dev->dev.of_node->full_name);
+               ret = PTR_ERR(cache_sram->rh);
+               goto out_unmap;
+       }
+
+       rh_attach_region(cache_sram->rh, 0, cache_sram->size);
+       spin_lock_init(&cache_sram->lock);
+
+       dev_info(&dev->dev, "[base:0x%llx, size:0x%x] configured and loaded\n",
+               (unsigned long long)cache_sram->base_phys, cache_sram->size);
+
+       return 0;
+
+out_unmap:
+       iounmap(cache_sram->base_virt);
+
+out_release:
+       release_mem_region(cache_sram->base_phys, cache_sram->size);
+
+out_free:
+       kfree(cache_sram);
+       return ret;
+}
+
+void remove_cache_sram(struct platform_device *dev)
+{
+       BUG_ON(!cache_sram);
+
+       rh_detach_region(cache_sram->rh, 0, cache_sram->size);
+       rh_destroy(cache_sram->rh);
+
+       iounmap(cache_sram->base_virt);
+       release_mem_region(cache_sram->base_phys, cache_sram->size);
+
+       kfree(cache_sram);
+       cache_sram = NULL;
+
+       dev_info(&dev->dev, "MPC85xx Cache-SRAM driver unloaded\n");
+}
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
new file mode 100644 (file)
index 0000000..cc8d655
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
+ *
+ * QorIQ (P1/P2) L2 controller init for Cache-SRAM instantiation
+ *
+ * Author: Vivek Mahajan <vivek.mahajan@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+
+#include "fsl_85xx_cache_ctlr.h"
+
+static char *sram_size;
+static char *sram_offset;
+struct mpc85xx_l2ctlr __iomem *l2ctlr;
+
+static long get_cache_sram_size(void)
+{
+       unsigned long val;
+
+       if (!sram_size || (strict_strtoul(sram_size, 0, &val) < 0))
+               return -EINVAL;
+
+       return val;
+}
+
+static long get_cache_sram_offset(void)
+{
+       unsigned long val;
+
+       if (!sram_offset || (strict_strtoul(sram_offset, 0, &val) < 0))
+               return -EINVAL;
+
+       return val;
+}
+
+static int __init get_size_from_cmdline(char *str)
+{
+       if (!str)
+               return 0;
+
+       sram_size = str;
+       return 1;
+}
+
+static int __init get_offset_from_cmdline(char *str)
+{
+       if (!str)
+               return 0;
+
+       sram_offset = str;
+       return 1;
+}
+
+__setup("cache-sram-size=", get_size_from_cmdline);
+__setup("cache-sram-offset=", get_offset_from_cmdline);
+
+static int __devinit mpc85xx_l2ctlr_of_probe(struct platform_device *dev,
+                                         const struct of_device_id *match)
+{
+       long rval;
+       unsigned int rem;
+       unsigned char ways;
+       const unsigned int *prop;
+       unsigned int l2cache_size;
+       struct sram_parameters sram_params;
+
+       if (!dev->dev.of_node) {
+               dev_err(&dev->dev, "Device's OF-node is NULL\n");
+               return -EINVAL;
+       }
+
+       prop = of_get_property(dev->dev.of_node, "cache-size", NULL);
+       if (!prop) {
+               dev_err(&dev->dev, "Missing L2 cache-size\n");
+               return -EINVAL;
+       }
+       l2cache_size = *prop;
+
+       sram_params.sram_size  = get_cache_sram_size();
+       if (sram_params.sram_size <= 0) {
+               dev_err(&dev->dev,
+                       "Entire L2 as cache, Aborting Cache-SRAM stuff\n");
+               return -EINVAL;
+       }
+
+       sram_params.sram_offset  = get_cache_sram_offset();
+       if (sram_params.sram_offset <= 0) {
+               dev_err(&dev->dev,
+                       "Entire L2 as cache, provide a valid sram offset\n");
+               return -EINVAL;
+       }
+
+
+       rem = l2cache_size % sram_params.sram_size;
+       ways = LOCK_WAYS_FULL * sram_params.sram_size / l2cache_size;
+       if (rem || (ways & (ways - 1))) {
+               dev_err(&dev->dev, "Illegal cache-sram-size in command line\n");
+               return -EINVAL;
+       }
+
+       l2ctlr = of_iomap(dev->dev.of_node, 0);
+       if (!l2ctlr) {
+               dev_err(&dev->dev, "Can't map L2 controller\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Write bits[0-17] to srbar0
+        */
+       out_be32(&l2ctlr->srbar0,
+               sram_params.sram_offset & L2SRAM_BAR_MSK_LO18);
+
+       /*
+        * Write bits[18-21] to srbare0
+        */
+#ifdef CONFIG_PHYS_64BIT
+       out_be32(&l2ctlr->srbarea0,
+               (sram_params.sram_offset >> 32) & L2SRAM_BARE_MSK_HI4);
+#endif
+
+       clrsetbits_be32(&l2ctlr->ctl, L2CR_L2E, L2CR_L2FI);
+
+       switch (ways) {
+       case LOCK_WAYS_EIGHTH:
+               setbits32(&l2ctlr->ctl,
+                       L2CR_L2E | L2CR_L2FI | L2CR_SRAM_EIGHTH);
+               break;
+
+       case LOCK_WAYS_TWO_EIGHTH:
+               setbits32(&l2ctlr->ctl,
+                       L2CR_L2E | L2CR_L2FI | L2CR_SRAM_QUART);
+               break;
+
+       case LOCK_WAYS_HALF:
+               setbits32(&l2ctlr->ctl,
+                       L2CR_L2E | L2CR_L2FI | L2CR_SRAM_HALF);
+               break;
+
+       case LOCK_WAYS_FULL:
+       default:
+               setbits32(&l2ctlr->ctl,
+                       L2CR_L2E | L2CR_L2FI | L2CR_SRAM_FULL);
+               break;
+       }
+       eieio();
+
+       rval = instantiate_cache_sram(dev, sram_params);
+       if (rval < 0) {
+               dev_err(&dev->dev, "Can't instantiate Cache-SRAM\n");
+               iounmap(l2ctlr);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int __devexit mpc85xx_l2ctlr_of_remove(struct platform_device *dev)
+{
+       BUG_ON(!l2ctlr);
+
+       iounmap(l2ctlr);
+       remove_cache_sram(dev);
+       dev_info(&dev->dev, "MPC85xx L2 controller unloaded\n");
+
+       return 0;
+}
+
+static struct of_device_id mpc85xx_l2ctlr_of_match[] = {
+       {
+               .compatible = "fsl,p2020-l2-cache-controller",
+       },
+       {
+               .compatible = "fsl,p2010-l2-cache-controller",
+       },
+       {
+               .compatible = "fsl,p1020-l2-cache-controller",
+       },
+       {
+               .compatible = "fsl,p1011-l2-cache-controller",
+       },
+       {
+               .compatible = "fsl,p1013-l2-cache-controller",
+       },
+       {
+               .compatible = "fsl,p1022-l2-cache-controller",
+       },
+       {},
+};
+
+static struct of_platform_driver mpc85xx_l2ctlr_of_platform_driver = {
+       .driver = {
+               .name           = "fsl-l2ctlr",
+               .owner          = THIS_MODULE,
+               .of_match_table = mpc85xx_l2ctlr_of_match,
+       },
+       .probe          = mpc85xx_l2ctlr_of_probe,
+       .remove         = __devexit_p(mpc85xx_l2ctlr_of_remove),
+};
+
+static __init int mpc85xx_l2ctlr_of_init(void)
+{
+       return of_register_platform_driver(&mpc85xx_l2ctlr_of_platform_driver);
+}
+
+static void __exit mpc85xx_l2ctlr_of_exit(void)
+{
+       of_unregister_platform_driver(&mpc85xx_l2ctlr_of_platform_driver);
+}
+
+subsys_initcall(mpc85xx_l2ctlr_of_init);
+module_exit(mpc85xx_l2ctlr_of_exit);
+
+MODULE_DESCRIPTION("Freescale MPC85xx L2 controller init");
+MODULE_LICENSE("GPL v2");
index 87991d3abbab1c2e90268386be666764112cab38..108d76fa8f1c997f566a1a3448402ce9e55d3bae 100644 (file)
@@ -24,6 +24,7 @@
 #include <asm/ppc-pci.h>
 #include <asm/mpic.h>
 #include "fsl_msi.h"
+#include "fsl_pci.h"
 
 LIST_HEAD(msi_head);
 
@@ -51,8 +52,8 @@ static void fsl_msi_end_irq(unsigned int virq)
 }
 
 static struct irq_chip fsl_msi_chip = {
-       .mask           = mask_msi_irq,
-       .unmask         = unmask_msi_irq,
+       .irq_mask       = mask_msi_irq,
+       .irq_unmask     = unmask_msi_irq,
        .ack            = fsl_msi_end_irq,
        .name           = "FSL-MSI",
 };
@@ -125,13 +126,11 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
 {
        struct fsl_msi *msi_data = fsl_msi_data;
        struct pci_controller *hose = pci_bus_to_host(pdev->bus);
-       u32 base = 0;
+       u64 base = fsl_pci_immrbar_base(hose);
 
-       pci_bus_read_config_dword(hose->bus,
-               PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base);
+       msg->address_lo = msi_data->msi_addr_lo + lower_32_bits(base);
+       msg->address_hi = msi_data->msi_addr_hi + upper_32_bits(base);
 
-       msg->address_lo = msi_data->msi_addr_lo + base;
-       msg->address_hi = msi_data->msi_addr_hi;
        msg->data = hwirq;
 
        pr_debug("%s: allocated srs: %d, ibs: %d\n",
index 4ae933225251e0ae7312ea55f4e00732fc899911..818f7c6c8fa1f907adda6d911f323b808fadbb4d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MPC83xx/85xx/86xx PCI/PCIE support routing.
  *
- * Copyright 2007-2009 Freescale Semiconductor, Inc.
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
  * Copyright 2008-2009 MontaVista Software, Inc.
  *
  * Initial author: Xianghua Xiao <x.xiao@freescale.com>
@@ -34,7 +34,7 @@
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
 
-static int fsl_pcie_bus_fixup;
+static int fsl_pcie_bus_fixup, is_mpc83xx_pci;
 
 static void __init quirk_fsl_pcie_header(struct pci_dev *dev)
 {
@@ -407,10 +407,18 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010E, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2040E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2040, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P3041E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P3041, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040E, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080E, quirk_fsl_pcie_header);
 DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5010E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5010, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5020E, quirk_fsl_pcie_header);
+DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5020, quirk_fsl_pcie_header);
 #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */
 
 #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x)
@@ -430,6 +438,13 @@ struct mpc83xx_pcie_priv {
        u32 dev_base;
 };
 
+struct pex_inbound_window {
+       u32 ar;
+       u32 tar;
+       u32 barl;
+       u32 barh;
+};
+
 /*
  * With the convention of u-boot, the PCIE outbound window 0 serves
  * as configuration transactions outbound.
@@ -437,6 +452,8 @@ struct mpc83xx_pcie_priv {
 #define PEX_OUTWIN0_BAR                0xCA4
 #define PEX_OUTWIN0_TAL                0xCA8
 #define PEX_OUTWIN0_TAH                0xCAC
+#define PEX_RC_INWIN_BASE      0xE60
+#define PEX_RCIWARn_EN         0x1
 
 static int mpc83xx_pcie_exclude_device(struct pci_bus *bus, unsigned int devfn)
 {
@@ -604,6 +621,8 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
        const int *bus_range;
        int primary;
 
+       is_mpc83xx_pci = 1;
+
        if (!of_device_is_available(dev)) {
                pr_warning("%s: disabled by the firmware.\n",
                           dev->full_name);
@@ -683,3 +702,40 @@ err0:
        return ret;
 }
 #endif /* CONFIG_PPC_83xx */
+
+u64 fsl_pci_immrbar_base(struct pci_controller *hose)
+{
+#ifdef CONFIG_PPC_83xx
+       if (is_mpc83xx_pci) {
+               struct mpc83xx_pcie_priv *pcie = hose->dn->data;
+               struct pex_inbound_window *in;
+               int i;
+
+               /* Walk the Root Complex Inbound windows to match IMMR base */
+               in = pcie->cfg_type0 + PEX_RC_INWIN_BASE;
+               for (i = 0; i < 4; i++) {
+                       /* not enabled, skip */
+                       if (!in_le32(&in[i].ar) & PEX_RCIWARn_EN)
+                                continue;
+
+                       if (get_immrbase() == in_le32(&in[i].tar))
+                               return (u64)in_le32(&in[i].barh) << 32 |
+                                           in_le32(&in[i].barl);
+               }
+
+               printk(KERN_WARNING "could not find PCI BAR matching IMMR\n");
+       }
+#endif
+
+#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
+       if (!is_mpc83xx_pci) {
+               u32 base;
+
+               pci_bus_read_config_dword(hose->bus,
+                       PCI_DEVFN(0, 0), PCI_BASE_ADDRESS_0, &base);
+               return base;
+       }
+#endif
+
+       return 0;
+}
index a9d8bbebed80b231511bf862d594c769798a16d3..8ad72a11f77bec20ee473602b503423f77370d55 100644 (file)
@@ -88,6 +88,7 @@ struct ccsr_pci {
 extern int fsl_add_bridge(struct device_node *dev, int is_primary);
 extern void fsl_pcibios_fixup_bus(struct pci_bus *bus);
 extern int mpc83xx_add_bridge(struct device_node *dev);
+u64 fsl_pci_immrbar_base(struct pci_controller *hose);
 
 #endif /* __POWERPC_FSL_PCI_H */
 #endif /* __KERNEL__ */
index 3017532319c8d0df73ba36e3858c5368c17cccaf..412763672d23faa754e26d5b655cccd21046f4ad 100644 (file)
@@ -117,44 +117,59 @@ struct rio_atmu_regs {
 };
 
 struct rio_msg_regs {
-       u32 omr;
-       u32 osr;
+       u32 omr;        /* 0xD_3000 - Outbound message 0 mode register */
+       u32 osr;        /* 0xD_3004 - Outbound message 0 status register */
        u32 pad1;
-       u32 odqdpar;
+       u32 odqdpar;    /* 0xD_300C - Outbound message 0 descriptor queue
+                          dequeue pointer address register */
        u32 pad2;
-       u32 osar;
-       u32 odpr;
-       u32 odatr;
-       u32 odcr;
+       u32 osar;       /* 0xD_3014 - Outbound message 0 source address
+                          register */
+       u32 odpr;       /* 0xD_3018 - Outbound message 0 destination port
+                          register */
+       u32 odatr;      /* 0xD_301C - Outbound message 0 destination attributes
+                          Register*/
+       u32 odcr;       /* 0xD_3020 - Outbound message 0 double-word count
+                          register */
        u32 pad3;
-       u32 odqepar;
+       u32 odqepar;    /* 0xD_3028 - Outbound message 0 descriptor queue
+                          enqueue pointer address register */
        u32 pad4[13];
-       u32 imr;
-       u32 isr;
+       u32 imr;        /* 0xD_3060 - Inbound message 0 mode register */
+       u32 isr;        /* 0xD_3064 - Inbound message 0 status register */
        u32 pad5;
-       u32 ifqdpar;
+       u32 ifqdpar;    /* 0xD_306C - Inbound message 0 frame queue dequeue
+                          pointer address register*/
        u32 pad6;
-       u32 ifqepar;
+       u32 ifqepar;    /* 0xD_3074 - Inbound message 0 frame queue enqueue
+                          pointer address register */
        u32 pad7[226];
-       u32 odmr;
-       u32 odsr;
+       u32 odmr;       /* 0xD_3400 - Outbound doorbell mode register */
+       u32 odsr;       /* 0xD_3404 - Outbound doorbell status register */
        u32 res0[4];
-       u32 oddpr;
-       u32 oddatr;
+       u32 oddpr;      /* 0xD_3418 - Outbound doorbell destination port
+                          register */
+       u32 oddatr;     /* 0xD_341c - Outbound doorbell destination attributes
+                          register */
        u32 res1[3];
-       u32 odretcr;
+       u32 odretcr;    /* 0xD_342C - Outbound doorbell retry error threshold
+                          configuration register */
        u32 res2[12];
-       u32 dmr;
-       u32 dsr;
+       u32 dmr;        /* 0xD_3460 - Inbound doorbell mode register */
+       u32 dsr;        /* 0xD_3464 - Inbound doorbell status register */
        u32 pad8;
-       u32 dqdpar;
+       u32 dqdpar;     /* 0xD_346C - Inbound doorbell queue dequeue Pointer
+                          address register */
        u32 pad9;
-       u32 dqepar;
+       u32 dqepar;     /* 0xD_3474 - Inbound doorbell Queue enqueue pointer
+                          address register */
        u32 pad10[26];
-       u32 pwmr;
-       u32 pwsr;
-       u32 epwqbar;
-       u32 pwqbar;
+       u32 pwmr;       /* 0xD_34E0 - Inbound port-write mode register */
+       u32 pwsr;       /* 0xD_34E4 - Inbound port-write status register */
+       u32 epwqbar;    /* 0xD_34E8 - Extended Port-Write Queue Base Address
+                          register */
+       u32 pwqbar;     /* 0xD_34EC - Inbound port-write queue base address
+                          register */
 };
 
 struct rio_tx_desc {
index b91f7acdda6f72aa09d49669258d18e2d9527a73..6c67d9ebf1669e80886614e1e3d3b78528716e62 100644 (file)
@@ -378,17 +378,23 @@ static __be32 __iomem *rstcr;
 static int __init setup_rstcr(void)
 {
        struct device_node *np;
-       np = of_find_node_by_name(NULL, "global-utilities");
-       if ((np && of_get_property(np, "fsl,has-rstcr", NULL))) {
-               rstcr = of_iomap(np, 0) + 0xb0;
-               if (!rstcr)
-                       printk (KERN_EMERG "Error: reset control register "
-                                       "not mapped!\n");
-       } else if (ppc_md.restart == fsl_rstcr_restart)
+
+       for_each_node_by_name(np, "global-utilities") {
+               if ((of_get_property(np, "fsl,has-rstcr", NULL))) {
+                       rstcr = of_iomap(np, 0) + 0xb0;
+                       if (!rstcr)
+                               printk (KERN_ERR "Error: reset control "
+                                               "register not mapped!\n");
+                       break;
+               }
+       }
+
+       if (!rstcr && ppc_md.restart == fsl_rstcr_restart)
                printk(KERN_ERR "No RSTCR register, warm reboot won't work\n");
 
        if (np)
                of_node_put(np);
+
        return 0;
 }
 
index 2b69084d0f0cb7f9cc0acdb4a0d4d1c024bb1a69..c0ea05e87f1db143dfe4439c69eb14f08fed03d0 100644 (file)
@@ -330,6 +330,9 @@ static int __init mpc8xxx_add_gpiochips(void)
        for_each_compatible_node(np, NULL, "fsl,mpc8610-gpio")
                mpc8xxx_add_controller(np);
 
+       for_each_compatible_node(np, NULL, "fsl,qoriq-gpio")
+               mpc8xxx_add_controller(np);
+
        return 0;
 }
 arch_initcall(mpc8xxx_add_gpiochips);
index 3b6a9a43718fb46ba240f52fa581c256075129cc..320ad5a9a25d3b649dddbc3f8a787dc6759dbb26 100644 (file)
 static struct mpic *msi_mpic;
 
 
-static void mpic_pasemi_msi_mask_irq(unsigned int irq)
+static void mpic_pasemi_msi_mask_irq(struct irq_data *data)
 {
-       pr_debug("mpic_pasemi_msi_mask_irq %d\n", irq);
-       mask_msi_irq(irq);
-       mpic_mask_irq(irq);
+       pr_debug("mpic_pasemi_msi_mask_irq %d\n", data->irq);
+       mask_msi_irq(data);
+       mpic_mask_irq(data->irq);
 }
 
-static void mpic_pasemi_msi_unmask_irq(unsigned int irq)
+static void mpic_pasemi_msi_unmask_irq(struct irq_data *data)
 {
-       pr_debug("mpic_pasemi_msi_unmask_irq %d\n", irq);
-       mpic_unmask_irq(irq);
-       unmask_msi_irq(irq);
+       pr_debug("mpic_pasemi_msi_unmask_irq %d\n", data->irq);
+       mpic_unmask_irq(data->irq);
+       unmask_msi_irq(data);
 }
 
 static struct irq_chip mpic_pasemi_msi_chip = {
-       .shutdown       = mpic_pasemi_msi_mask_irq,
-       .mask           = mpic_pasemi_msi_mask_irq,
-       .unmask         = mpic_pasemi_msi_unmask_irq,
+       .irq_shutdown   = mpic_pasemi_msi_mask_irq,
+       .irq_mask       = mpic_pasemi_msi_mask_irq,
+       .irq_unmask     = mpic_pasemi_msi_unmask_irq,
        .eoi            = mpic_end_irq,
        .set_type       = mpic_set_irq_type,
        .set_affinity   = mpic_set_affinity,
index bcbfe79c704bb42f6e8bcebe893eadf6aaf341da..a2b028b4a2020db8c609c80d8b2444107502bce8 100644 (file)
 /* A bit ugly, can we get this from the pci_dev somehow? */
 static struct mpic *msi_mpic;
 
-static void mpic_u3msi_mask_irq(unsigned int irq)
+static void mpic_u3msi_mask_irq(struct irq_data *data)
 {
-       mask_msi_irq(irq);
-       mpic_mask_irq(irq);
+       mask_msi_irq(data);
+       mpic_mask_irq(data->irq);
 }
 
-static void mpic_u3msi_unmask_irq(unsigned int irq)
+static void mpic_u3msi_unmask_irq(struct irq_data *data)
 {
-       mpic_unmask_irq(irq);
-       unmask_msi_irq(irq);
+       mpic_unmask_irq(data->irq);
+       unmask_msi_irq(data);
 }
 
 static struct irq_chip mpic_u3msi_chip = {
-       .shutdown       = mpic_u3msi_mask_irq,
-       .mask           = mpic_u3msi_mask_irq,
-       .unmask         = mpic_u3msi_unmask_irq,
+       .irq_shutdown   = mpic_u3msi_mask_irq,
+       .irq_mask       = mpic_u3msi_mask_irq,
+       .irq_unmask     = mpic_u3msi_unmask_irq,
        .eoi            = mpic_end_irq,
        .set_type       = mpic_set_irq_type,
        .set_affinity   = mpic_set_affinity,
index 24a0bb955b184bba92c6d0d9efda52ac568bee74..4260f368db5233391769204de3da3f67db1cf07c 100644 (file)
@@ -114,7 +114,7 @@ static void pmi_notify_handlers(struct work_struct *work)
 
        spin_lock(&data->handler_spinlock);
        list_for_each_entry(handler, &data->handler, node) {
-               pr_debug(KERN_INFO "pmi: notifying handler %p\n", handler);
+               pr_debug("pmi: notifying handler %p\n", handler);
                if (handler->type == data->msg.type)
                        handler->handle_pmi_message(data->msg);
        }
index faa81b6a66126531c87f94897f33d2affc7c43f3..c168c54e3c40caed0ead0ad449ebe00ad0232fd0 100644 (file)
@@ -4,9 +4,7 @@ subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
 
 GCOV_PROFILE := n
 
-ifdef CONFIG_PPC64
-EXTRA_CFLAGS += -mno-minimal-toc
-endif
+ccflags-$(CONFIG_PPC64) := -mno-minimal-toc
 
 obj-y                  += xmon.o start.o nonstdio.o
 
index f0777a47e3a531c17156a76694648aaf89cacd44..75976a14194770390154ca124d9e94f95eedecf4 100644 (file)
@@ -95,6 +95,7 @@ config S390
        select HAVE_KVM if 64BIT
        select HAVE_ARCH_TRACEHOOK
        select INIT_ALL_POSSIBLE
+       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
@@ -198,6 +199,13 @@ config HOTPLUG_CPU
          can be controlled through /sys/devices/system/cpu/cpu#.
          Say N if you want to disable CPU hotplug.
 
+config SCHED_BOOK
+       bool "Book scheduler support"
+       depends on SMP
+       help
+         Book scheduler support improves the CPU scheduler's decision making
+         when dealing with machines that have several books.
+
 config MATHEMU
        bool "IEEE FPU emulation"
        depends on MARCH_G5
index 498bc38923856ddb1957ddd0ac934b7c7e510003..881d94590aeb4c84efb8e5c58fae68b73b70f6e5 100644 (file)
 #ifndef __ASM_HARDIRQ_H
 #define __ASM_HARDIRQ_H
 
-#include <linux/threads.h>
-#include <linux/sched.h>
-#include <linux/cache.h>
-#include <linux/interrupt.h>
 #include <asm/lowcore.h>
 
 #define local_softirq_pending() (S390_lowcore.softirq_pending)
index 15b3ac253898d8029e886c192f5d887bf1b3948f..865d6d891ace56f0b45d7d50aeca02f7daf46a23 100644 (file)
@@ -8,8 +8,8 @@
 
 #include <linux/types.h>
 
-/* store then or system mask. */
-#define __raw_local_irq_stosm(__or)                                    \
+/* store then OR system mask. */
+#define __arch_local_irq_stosm(__or)                                   \
 ({                                                                     \
        unsigned long __mask;                                           \
        asm volatile(                                                   \
@@ -18,8 +18,8 @@
        __mask;                                                         \
 })
 
-/* store then and system mask. */
-#define __raw_local_irq_stnsm(__and)                                   \
+/* store then AND system mask. */
+#define __arch_local_irq_stnsm(__and)                                  \
 ({                                                                     \
        unsigned long __mask;                                           \
        asm volatile(                                                   \
 })
 
 /* set system mask. */
-#define __raw_local_irq_ssm(__mask)                                    \
-({                                                                     \
-       asm volatile("ssm   %0" : : "Q" (__mask) : "memory");           \
-})
+static inline void __arch_local_irq_ssm(unsigned long flags)
+{
+       asm volatile("ssm   %0" : : "Q" (flags) : "memory");
+}
 
-/* interrupt control.. */
-static inline unsigned long raw_local_irq_enable(void)
+static inline unsigned long arch_local_save_flags(void)
 {
-       return __raw_local_irq_stosm(0x03);
+       return __arch_local_irq_stosm(0x00);
 }
 
-static inline unsigned long raw_local_irq_disable(void)
+static inline unsigned long arch_local_irq_save(void)
 {
-       return __raw_local_irq_stnsm(0xfc);
+       return __arch_local_irq_stnsm(0xfc);
 }
 
-#define raw_local_save_flags(x)                                                \
-do {                                                                   \
-       typecheck(unsigned long, x);                                    \
-       (x) = __raw_local_irq_stosm(0x00);                              \
-} while (0)
+static inline void arch_local_irq_disable(void)
+{
+       arch_local_irq_save();
+}
 
-static inline void raw_local_irq_restore(unsigned long flags)
+static inline void arch_local_irq_enable(void)
 {
-       __raw_local_irq_ssm(flags);
+       __arch_local_irq_stosm(0x03);
 }
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       __arch_local_irq_ssm(flags);
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
        return !(flags & (3UL << (BITS_PER_LONG - 8)));
 }
 
-/* For spinlocks etc */
-#define raw_local_irq_save(x)  ((x) = raw_local_irq_disable())
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
 
 #endif /* __ASM_IRQFLAGS_H */
index 3840cbe77637fe1ffef8c5baceb2c82c8ed7759d..a75f168d2718578544914c8a00eb0e1245ef9c8f 100644 (file)
@@ -4,7 +4,6 @@
  * Copyright 2009 Martin Schwidefsky, IBM Corporation.
  */
 
-static inline void set_perf_event_pending(void) {}
-static inline void clear_perf_event_pending(void) {}
+/* Empty, just to avoid compiling error */
 
 #define PERF_EVENT_INDEX_OFFSET 0
index cef66210c8466d68e13eaccce453582060c18a4f..1f2ebc4afd828f47da56d6763be4a16ba713263c 100644 (file)
@@ -97,7 +97,6 @@ static inline void restore_access_regs(unsigned int *acrs)
 
 extern void account_vtime(struct task_struct *, struct task_struct *);
 extern void account_tick_vtime(struct task_struct *);
-extern void account_system_vtime(struct task_struct *);
 
 #ifdef CONFIG_PFAULT
 extern void pfault_irq_init(void);
@@ -399,7 +398,7 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
 static inline void
 __set_psw_mask(unsigned long mask)
 {
-       __load_psw_mask(mask | (__raw_local_irq_stosm(0x00) & ~(-1UL >> 8)));
+       __load_psw_mask(mask | (arch_local_save_flags() & ~(-1UL >> 8)));
 }
 
 #define local_mcck_enable()  __set_psw_mask(psw_kernel_bits)
index 831bd033ea77b3f2c72c408f40621a82d22ac017..051107a2c5e249397f71163544ae105dbde6d302 100644 (file)
@@ -3,15 +3,32 @@
 
 #include <linux/cpumask.h>
 
-#define mc_capable()   (1)
-
-const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
-
 extern unsigned char cpu_core_id[NR_CPUS];
 extern cpumask_t cpu_core_map[NR_CPUS];
 
+static inline const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
+{
+       return &cpu_core_map[cpu];
+}
+
 #define topology_core_id(cpu)          (cpu_core_id[cpu])
 #define topology_core_cpumask(cpu)     (&cpu_core_map[cpu])
+#define mc_capable()                   (1)
+
+#ifdef CONFIG_SCHED_BOOK
+
+extern unsigned char cpu_book_id[NR_CPUS];
+extern cpumask_t cpu_book_map[NR_CPUS];
+
+static inline const struct cpumask *cpu_book_mask(unsigned int cpu)
+{
+       return &cpu_book_map[cpu];
+}
+
+#define topology_book_id(cpu)          (cpu_book_id[cpu])
+#define topology_book_cpumask(cpu)     (&cpu_book_map[cpu])
+
+#endif /* CONFIG_SCHED_BOOK */
 
 int topology_set_cpu_management(int fc);
 void topology_schedule_update(void);
@@ -30,6 +47,8 @@ static inline void s390_init_cpu_topology(void)
 };
 #endif
 
+#define SD_BOOK_INIT   SD_CPU_INIT
+
 #include <asm-generic/topology.h>
 
 #endif /* _ASM_S390_TOPOLOGY_H */
index 559af0d07878867cb0e382226c33852af5e17e62..0fbe4e32f7ba298c83b22dfe831b66545fba8ace 100644 (file)
@@ -54,11 +54,11 @@ void detect_memory_layout(struct mem_chunk chunk[])
         * right thing and we don't get scheduled away with low address
         * protection disabled.
         */
-       flags = __raw_local_irq_stnsm(0xf8);
+       flags = __arch_local_irq_stnsm(0xf8);
        __ctl_store(cr0, 0, 0);
        __ctl_clear_bit(0, 28);
        find_memory_chunks(chunk);
        __ctl_load(cr0, 0, 0);
-       __raw_local_irq_ssm(flags);
+       arch_local_irq_restore(flags);
 }
 EXPORT_SYMBOL(detect_memory_layout);
index bcef00766a646dec0a5158bdf10c0574d8177293..13559c9938470b9d7d0c2597f6418e518d865c78 100644 (file)
@@ -57,8 +57,8 @@ struct tl_info {
        union tl_entry tle[0];
 };
 
-struct core_info {
-       struct core_info *next;
+struct mask_info {
+       struct mask_info *next;
        unsigned char id;
        cpumask_t mask;
 };
@@ -66,7 +66,6 @@ struct core_info {
 static int topology_enabled;
 static void topology_work_fn(struct work_struct *work);
 static struct tl_info *tl_info;
-static struct core_info core_info;
 static int machine_has_topology;
 static struct timer_list topology_timer;
 static void set_topology_timer(void);
@@ -74,38 +73,37 @@ static DECLARE_WORK(topology_work, topology_work_fn);
 /* topology_lock protects the core linked list */
 static DEFINE_SPINLOCK(topology_lock);
 
+static struct mask_info core_info;
 cpumask_t cpu_core_map[NR_CPUS];
 unsigned char cpu_core_id[NR_CPUS];
 
-static cpumask_t cpu_coregroup_map(unsigned int cpu)
+#ifdef CONFIG_SCHED_BOOK
+static struct mask_info book_info;
+cpumask_t cpu_book_map[NR_CPUS];
+unsigned char cpu_book_id[NR_CPUS];
+#endif
+
+static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
 {
-       struct core_info *core = &core_info;
-       unsigned long flags;
        cpumask_t mask;
 
        cpus_clear(mask);
        if (!topology_enabled || !machine_has_topology)
                return cpu_possible_map;
-       spin_lock_irqsave(&topology_lock, flags);
-       while (core) {
-               if (cpu_isset(cpu, core->mask)) {
-                       mask = core->mask;
+       while (info) {
+               if (cpu_isset(cpu, info->mask)) {
+                       mask = info->mask;
                        break;
                }
-               core = core->next;
+               info = info->next;
        }
-       spin_unlock_irqrestore(&topology_lock, flags);
        if (cpus_empty(mask))
                mask = cpumask_of_cpu(cpu);
        return mask;
 }
 
-const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
-{
-       return &cpu_core_map[cpu];
-}
-
-static void add_cpus_to_core(struct tl_cpu *tl_cpu, struct core_info *core)
+static void add_cpus_to_mask(struct tl_cpu *tl_cpu, struct mask_info *book,
+                            struct mask_info *core)
 {
        unsigned int cpu;
 
@@ -117,23 +115,35 @@ static void add_cpus_to_core(struct tl_cpu *tl_cpu, struct core_info *core)
 
                rcpu = CPU_BITS - 1 - cpu + tl_cpu->origin;
                for_each_present_cpu(lcpu) {
-                       if (cpu_logical_map(lcpu) == rcpu) {
-                               cpu_set(lcpu, core->mask);
-                               cpu_core_id[lcpu] = core->id;
-                               smp_cpu_polarization[lcpu] = tl_cpu->pp;
-                       }
+                       if (cpu_logical_map(lcpu) != rcpu)
+                               continue;
+#ifdef CONFIG_SCHED_BOOK
+                       cpu_set(lcpu, book->mask);
+                       cpu_book_id[lcpu] = book->id;
+#endif
+                       cpu_set(lcpu, core->mask);
+                       cpu_core_id[lcpu] = core->id;
+                       smp_cpu_polarization[lcpu] = tl_cpu->pp;
                }
        }
 }
 
-static void clear_cores(void)
+static void clear_masks(void)
 {
-       struct core_info *core = &core_info;
+       struct mask_info *info;
 
-       while (core) {
-               cpus_clear(core->mask);
-               core = core->next;
+       info = &core_info;
+       while (info) {
+               cpus_clear(info->mask);
+               info = info->next;
+       }
+#ifdef CONFIG_SCHED_BOOK
+       info = &book_info;
+       while (info) {
+               cpus_clear(info->mask);
+               info = info->next;
        }
+#endif
 }
 
 static union tl_entry *next_tle(union tl_entry *tle)
@@ -146,29 +156,36 @@ static union tl_entry *next_tle(union tl_entry *tle)
 
 static void tl_to_cores(struct tl_info *info)
 {
+#ifdef CONFIG_SCHED_BOOK
+       struct mask_info *book = &book_info;
+#else
+       struct mask_info *book = NULL;
+#endif
+       struct mask_info *core = &core_info;
        union tl_entry *tle, *end;
-       struct core_info *core = &core_info;
+
 
        spin_lock_irq(&topology_lock);
-       clear_cores();
+       clear_masks();
        tle = info->tle;
        end = (union tl_entry *)((unsigned long)info + info->length);
        while (tle < end) {
                switch (tle->nl) {
-               case 5:
-               case 4:
-               case 3:
+#ifdef CONFIG_SCHED_BOOK
                case 2:
+                       book = book->next;
+                       book->id = tle->container.id;
                        break;
+#endif
                case 1:
                        core = core->next;
                        core->id = tle->container.id;
                        break;
                case 0:
-                       add_cpus_to_core(&tle->cpu, core);
+                       add_cpus_to_mask(&tle->cpu, book, core);
                        break;
                default:
-                       clear_cores();
+                       clear_masks();
                        machine_has_topology = 0;
                        goto out;
                }
@@ -221,10 +238,29 @@ int topology_set_cpu_management(int fc)
 
 static void update_cpu_core_map(void)
 {
+       unsigned long flags;
        int cpu;
 
-       for_each_possible_cpu(cpu)
-               cpu_core_map[cpu] = cpu_coregroup_map(cpu);
+       spin_lock_irqsave(&topology_lock, flags);
+       for_each_possible_cpu(cpu) {
+               cpu_core_map[cpu] = cpu_group_map(&core_info, cpu);
+#ifdef CONFIG_SCHED_BOOK
+               cpu_book_map[cpu] = cpu_group_map(&book_info, cpu);
+#endif
+       }
+       spin_unlock_irqrestore(&topology_lock, flags);
+}
+
+static void store_topology(struct tl_info *info)
+{
+#ifdef CONFIG_SCHED_BOOK
+       int rc;
+
+       rc = stsi(info, 15, 1, 3);
+       if (rc != -ENOSYS)
+               return;
+#endif
+       stsi(info, 15, 1, 2);
 }
 
 int arch_update_cpu_topology(void)
@@ -238,7 +274,7 @@ int arch_update_cpu_topology(void)
                topology_update_polarization_simple();
                return 0;
        }
-       stsi(info, 15, 1, 2);
+       store_topology(info);
        tl_to_cores(info);
        update_cpu_core_map();
        for_each_online_cpu(cpu) {
@@ -299,12 +335,24 @@ out:
 }
 __initcall(init_topology_update);
 
+static void alloc_masks(struct tl_info *info, struct mask_info *mask, int offset)
+{
+       int i, nr_masks;
+
+       nr_masks = info->mag[NR_MAG - offset];
+       for (i = 0; i < info->mnest - offset; i++)
+               nr_masks *= info->mag[NR_MAG - offset - 1 - i];
+       nr_masks = max(nr_masks, 1);
+       for (i = 0; i < nr_masks; i++) {
+               mask->next = alloc_bootmem(sizeof(struct mask_info));
+               mask = mask->next;
+       }
+}
+
 void __init s390_init_cpu_topology(void)
 {
        unsigned long long facility_bits;
        struct tl_info *info;
-       struct core_info *core;
-       int nr_cores;
        int i;
 
        if (stfle(&facility_bits, 1) <= 0)
@@ -315,25 +363,13 @@ void __init s390_init_cpu_topology(void)
 
        tl_info = alloc_bootmem_pages(PAGE_SIZE);
        info = tl_info;
-       stsi(info, 15, 1, 2);
-
-       nr_cores = info->mag[NR_MAG - 2];
-       for (i = 0; i < info->mnest - 2; i++)
-               nr_cores *= info->mag[NR_MAG - 3 - i];
-
+       store_topology(info);
        pr_info("The CPU configuration topology of the machine is:");
        for (i = 0; i < NR_MAG; i++)
                printk(" %d", info->mag[i]);
        printk(" / %d\n", info->mnest);
-
-       core = &core_info;
-       for (i = 0; i < nr_cores; i++) {
-               core->next = alloc_bootmem(sizeof(struct core_info));
-               core = core->next;
-               if (!core)
-                       goto error;
-       }
-       return;
-error:
-       machine_has_topology = 0;
+       alloc_masks(info, &core_info, 2);
+#ifdef CONFIG_SCHED_BOOK
+       alloc_masks(info, &book_info, 3);
+#endif
 }
index 30eb6d02ddb89d59bf11d57ecbf743823cc44087..94b8ba2ec8575d814613bab79fa191ba5a2564ca 100644 (file)
@@ -50,7 +50,6 @@ EXPORT_SYMBOL(empty_zero_page);
  */
 void __init paging_init(void)
 {
-       static const int ssm_mask = 0x04000000L;
        unsigned long max_zone_pfns[MAX_NR_ZONES];
        unsigned long pgd_type;
 
@@ -72,7 +71,7 @@ void __init paging_init(void)
        __ctl_load(S390_lowcore.kernel_asce, 1, 1);
        __ctl_load(S390_lowcore.kernel_asce, 7, 7);
        __ctl_load(S390_lowcore.kernel_asce, 13, 13);
-       __raw_local_irq_ssm(ssm_mask);
+       arch_local_irq_restore(4UL << (BITS_PER_LONG - 8));
 
        atomic_set(&init_mm.context.attach_count, 1);
 
index a8c2af8c650fabd9c96a4f9efaf3c0c4f530f294..71a4b0d34be09625c2fecfd28a23d61b47e29019 100644 (file)
@@ -71,7 +71,7 @@ int memcpy_real(void *dest, void *src, size_t count)
 
        if (!count)
                return 0;
-       flags = __raw_local_irq_stnsm(0xf8UL);
+       flags = __arch_local_irq_stnsm(0xf8UL);
        asm volatile (
                "0:     mvcle   %1,%2,0x0\n"
                "1:     jo      0b\n"
@@ -82,6 +82,6 @@ int memcpy_real(void *dest, void *src, size_t count)
                  "+d" (_len2), "=m" (*((long *) dest))
                : "m" (*((long *) src))
                : "cc", "memory");
-       __raw_local_irq_ssm(flags);
+       arch_local_irq_restore(flags);
        return rc;
 }
index 690a6cae729416807b5120d20d45beb047487ffe..5c7563891e288e9b972e9ecc38b8a1b1dd361ee0 100644 (file)
 
 #ifndef __ASSEMBLY__
 
-#define raw_local_irq_save(x)                  \
-{                                              \
-       __asm__ __volatile__(                   \
-               "mfcr   r8, cr0;"               \
-               "li     r9, 0xfffffffe;"        \
-               "nop;"                          \
-               "mv     %0, r8;"                \
-               "and    r8, r8, r9;"            \
-               "mtcr   r8, cr0;"               \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               : "=r" (x)                      \
-               :                               \
-               : "r8", "r9"                    \
-               );                              \
+#include <linux/types.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+
+       asm volatile(
+               "       mfcr    r8, cr0         \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       mv      %0, r8          \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       ldi     r9, 0x1         \n"
+               "       and     %0, %0, r9      \n"
+               : "=r" (flags)
+               :
+               : "r8", "r9");
+       return flags;
 }
 
-#define raw_local_irq_restore(x)               \
-{                                              \
-       __asm__ __volatile__(                   \
-               "mfcr   r8, cr0;"               \
-               "ldi    r9, 0x1;"               \
-               "and    %0, %0, r9;"            \
-               "or     r8, r8, %0;"            \
-               "mtcr   r8, cr0;"               \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               :                               \
-               : "r"(x)                        \
-               : "r8", "r9"                    \
-               );                              \
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags
+
+       asm volatile(
+               "       mfcr    r8, cr0         \n"
+               "       li      r9, 0xfffffffe  \n"
+               "       nop                     \n"
+               "       mv      %0, r8          \n"
+               "       and     r8, r8, r9      \n"
+               "       mtcr    r8, cr0         \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               : "=r" (flags)
+               :
+               : "r8", "r9", "memory");
+
+       return flags;
 }
 
-#define raw_local_irq_enable(void)             \
-{                                              \
-       __asm__ __volatile__(                   \
-               "mfcr\tr8,cr0;"                 \
-               "nop;"                          \
-               "nop;"                          \
-               "ori\tr8,0x1;"                  \
-               "mtcr\tr8,cr0;"                 \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               :                               \
-               :                               \
-               : "r8");                        \
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile(
+               "       mfcr    r8, cr0         \n"
+               "       ldi     r9, 0x1         \n"
+               "       and     %0, %0, r9      \n"
+               "       or      r8, r8, %0      \n"
+               "       mtcr    r8, cr0         \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               :
+               : "r"(flags)
+               : "r8", "r9", "memory");
 }
 
-#define raw_local_irq_disable(void)            \
-{                                              \
-       __asm__ __volatile__(                   \
-               "mfcr\tr8,cr0;"                 \
-               "nop;"                          \
-               "nop;"                          \
-               "srli\tr8,r8,1;"                \
-               "slli\tr8,r8,1;"                \
-               "mtcr\tr8,cr0;"                 \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               :                               \
-               :                               \
-               : "r8");                        \
+static inline void arch_local_irq_enable(void)
+{
+       asm volatile(
+               "       mfcr    r8,cr0          \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       ori     r8,0x1          \n"
+               "       mtcr    r8,cr0          \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               :
+               :
+               : "r8", "memory");
 }
 
-#define raw_local_save_flags(x)                        \
-{                                              \
-       __asm__ __volatile__(                   \
-               "mfcr   r8, cr0;"               \
-               "nop;"                          \
-               "nop;"                          \
-               "mv     %0, r8;"                \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "nop;"                          \
-               "ldi    r9, 0x1;"               \
-               "and    %0, %0, r9;"            \
-               : "=r" (x)                      \
-               :                               \
-               : "r8", "r9"                    \
-               );                              \
+static inline void arch_local_irq_disable(void)
+{
+       asm volatile(
+               "       mfcr    r8,cr0          \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       srli    r8,r8,1         \n"
+               "       slli    r8,r8,1         \n"
+               "       mtcr    r8,cr0          \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               "       nop                     \n"
+               :
+               :
+               : "r8", "memory");
 }
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
 {
        return !(flags & 1);
 }
 
-#endif
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_SCORE_IRQFLAGS_H */
index 33990fa95af013a64e081c4bfc411f58228f64cb..35b6879628a04feccd1dd2071846cb92563f5586 100644 (file)
@@ -16,6 +16,7 @@ config SUPERH
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
        select HAVE_DMA_ATTRS
+       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
        select HAVE_KERNEL_GZIP
@@ -249,6 +250,11 @@ config ARCH_SHMOBILE
        select PM
        select PM_RUNTIME
 
+config CPU_HAS_PMU
+       depends on CPU_SH4 || CPU_SH4A
+       default y
+       bool
+
 if SUPERH32
 
 choice
@@ -738,6 +744,14 @@ config GUSA_RB
          LLSC, this should be more efficient than the other alternative of
          disabling interrupts around the atomic sequence.
 
+config HW_PERF_EVENTS
+       bool "Enable hardware performance counter support for perf events"
+       depends on PERF_EVENTS && CPU_HAS_PMU
+       default y
+       help
+         Enable hardware performance counter support for perf events. If
+         disabled, perf events will use software events only.
+
 source "drivers/sh/Kconfig"
 
 endmenu
index a741153b41c2d1eb5eb4c4e428410bac86f81135..43b7608606c32434f6508a07153a2c4847c4bcf6 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef __ASM_SH_IRQFLAGS_H
 #define __ASM_SH_IRQFLAGS_H
 
-#define RAW_IRQ_DISABLED       0xf0
-#define RAW_IRQ_ENABLED                0x00
+#define ARCH_IRQ_DISABLED      0xf0
+#define ARCH_IRQ_ENABLED       0x00
 
 #include <asm-generic/irqflags.h>
 
index dfe683b88075fa98b7f28f6f1ef98f34752e7981..e87063fad2ea7ecd558aeba712e68760fb7d80b3 100644 (file)
@@ -1,6 +1,4 @@
 #ifndef __ASM_SH_MEMBLOCK_H
 #define __ASM_SH_MEMBLOCK_H
 
-#define MEMBLOCK_REAL_LIMIT    0
-
 #endif /* __ASM_SH_MEMBLOCK_H */
index 3d0c9f36d15050bb049fe8cfdbe4e7ae73f08f6d..14308bed7ea510cb6b43429887ca727cf1f0510d 100644 (file)
@@ -26,11 +26,4 @@ extern int register_sh_pmu(struct sh_pmu *);
 extern int reserve_pmc_hardware(void);
 extern void release_pmc_hardware(void);
 
-static inline void set_perf_event_pending(void)
-{
-       /* Nothing to see here, move along. */
-}
-
-#define PERF_EVENT_INDEX_OFFSET        0
-
 #endif /* __ASM_SH_PERF_EVENT_H */
index be201fdc97aa79bbf5470c8a582e20ecb7e78991..ae717e3c26d6d4178c1260c1602099d86534caed 100644 (file)
@@ -19,9 +19,10 @@ asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
 asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
                         unsigned long r6, unsigned long r7,
                         struct pt_regs __regs);
-asmlinkage int sys_execve(const char __user *ufilename, char __user * __user *uargv,
-                         char __user * __user *uenvp, unsigned long r7,
-                         struct pt_regs __regs);
+asmlinkage int sys_execve(const char __user *ufilename,
+                         const char __user *const __user *uargv,
+                         const char __user *const __user *uenvp,
+                         unsigned long r7, struct pt_regs __regs);
 asmlinkage int sys_sigsuspend(old_sigset_t mask, unsigned long r5,
                              unsigned long r6, unsigned long r7,
                              struct pt_regs __regs);
index 257de1f0692b19ade90daefcf1089c3c127ce72c..ae5bac39b896d052e0b3b1b663e3edb69a754339 100644 (file)
@@ -290,7 +290,7 @@ void __init init_IRQ(void)
 int __init arch_probe_nr_irqs(void)
 {
        nr_irqs = sh_mv.mv_nr_irqs;
-       return 0;
+       return NR_IRQS_LEGACY;
 }
 #endif
 
index e33ab15831f94dc62dc1d3b19e426de038db916d..e5a755be9129a1c9d497be4851ac0948fbd8a210 100644 (file)
 #include <linux/irqflags.h>
 #include <linux/module.h>
 
-void notrace raw_local_irq_restore(unsigned long flags)
+void notrace arch_local_irq_restore(unsigned long flags)
 {
        unsigned long __dummy0, __dummy1;
 
-       if (flags == RAW_IRQ_DISABLED) {
+       if (flags == ARCH_IRQ_DISABLED) {
                __asm__ __volatile__ (
                        "stc    sr, %0\n\t"
                        "or     #0xf0, %0\n\t"
@@ -33,14 +33,14 @@ void notrace raw_local_irq_restore(unsigned long flags)
 #endif
                        "ldc    %0, sr\n\t"
                        : "=&r" (__dummy0), "=r" (__dummy1)
-                       : "1" (~RAW_IRQ_DISABLED)
+                       : "1" (~ARCH_IRQ_DISABLED)
                        : "memory"
                );
        }
 }
-EXPORT_SYMBOL(raw_local_irq_restore);
+EXPORT_SYMBOL(arch_local_irq_restore);
 
-unsigned long notrace __raw_local_save_flags(void)
+unsigned long notrace arch_local_save_flags(void)
 {
        unsigned long flags;
 
@@ -54,4 +54,4 @@ unsigned long notrace __raw_local_save_flags(void)
 
        return flags;
 }
-EXPORT_SYMBOL(__raw_local_save_flags);
+EXPORT_SYMBOL(arch_local_save_flags);
index a9dd3abde28e3f45bbd7d7654e8717c13aed8f34..d5ca1ef50fa9694a1942a8c304bd2c5aa69d9388 100644 (file)
 #include <asm/unwinder.h>
 #include <asm/ptrace.h>
 
-static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip)
-{
-       if (entry->nr < PERF_MAX_STACK_DEPTH)
-               entry->ip[entry->nr++] = ip;
-}
 
 static void callchain_warning(void *data, char *msg)
 {
@@ -39,7 +34,7 @@ static void callchain_address(void *data, unsigned long addr, int reliable)
        struct perf_callchain_entry *entry = data;
 
        if (reliable)
-               callchain_store(entry, addr);
+               perf_callchain_store(entry, addr);
 }
 
 static const struct stacktrace_ops callchain_ops = {
@@ -49,47 +44,10 @@ static const struct stacktrace_ops callchain_ops = {
        .address        = callchain_address,
 };
 
-static void
-perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry)
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
-       callchain_store(entry, PERF_CONTEXT_KERNEL);
-       callchain_store(entry, regs->pc);
+       perf_callchain_store(entry, regs->pc);
 
        unwind_stack(NULL, regs, NULL, &callchain_ops, entry);
 }
-
-static void
-perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry)
-{
-       int is_user;
-
-       if (!regs)
-               return;
-
-       is_user = user_mode(regs);
-
-       if (is_user && current->state != TASK_RUNNING)
-               return;
-
-       /*
-        * Only the kernel side is implemented for now.
-        */
-       if (!is_user)
-               perf_callchain_kernel(regs, entry);
-}
-
-/*
- * No need for separate IRQ and NMI entries.
- */
-static DEFINE_PER_CPU(struct perf_callchain_entry, callchain);
-
-struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
-{
-       struct perf_callchain_entry *entry = &__get_cpu_var(callchain);
-
-       entry->nr = 0;
-
-       perf_do_callchain(regs, entry);
-
-       return entry;
-}
index 7a3dc356725839f2cf8579491efd8d02ba11b483..5a4b33435650c8ea108668d8e7e30786a20bd335 100644 (file)
@@ -59,6 +59,24 @@ static inline int sh_pmu_initialized(void)
        return !!sh_pmu;
 }
 
+const char *perf_pmu_name(void)
+{
+       if (!sh_pmu)
+               return NULL;
+
+       return sh_pmu->name;
+}
+EXPORT_SYMBOL_GPL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+       if (!sh_pmu)
+               return 0;
+
+       return sh_pmu->num_events;
+}
+EXPORT_SYMBOL_GPL(perf_num_counters);
+
 /*
  * Release the PMU if this is the last perf_event.
  */
@@ -206,50 +224,80 @@ again:
        local64_add(delta, &event->count);
 }
 
-static void sh_pmu_disable(struct perf_event *event)
+static void sh_pmu_stop(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
 
-       clear_bit(idx, cpuc->active_mask);
-       sh_pmu->disable(hwc, idx);
+       if (!(event->hw.state & PERF_HES_STOPPED)) {
+               sh_pmu->disable(hwc, idx);
+               cpuc->events[idx] = NULL;
+               event->hw.state |= PERF_HES_STOPPED;
+       }
+
+       if ((flags & PERF_EF_UPDATE) && !(event->hw.state & PERF_HES_UPTODATE)) {
+               sh_perf_event_update(event, &event->hw, idx);
+               event->hw.state |= PERF_HES_UPTODATE;
+       }
+}
+
+static void sh_pmu_start(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       struct hw_perf_event *hwc = &event->hw;
+       int idx = hwc->idx;
+
+       if (WARN_ON_ONCE(idx == -1))
+               return;
+
+       if (flags & PERF_EF_RELOAD)
+               WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
 
-       barrier();
+       cpuc->events[idx] = event;
+       event->hw.state = 0;
+       sh_pmu->enable(hwc, idx);
+}
 
-       sh_perf_event_update(event, &event->hw, idx);
+static void sh_pmu_del(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
-       cpuc->events[idx] = NULL;
-       clear_bit(idx, cpuc->used_mask);
+       sh_pmu_stop(event, PERF_EF_UPDATE);
+       __clear_bit(event->hw.idx, cpuc->used_mask);
 
        perf_event_update_userpage(event);
 }
 
-static int sh_pmu_enable(struct perf_event *event)
+static int sh_pmu_add(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
+       int ret = -EAGAIN;
+
+       perf_pmu_disable(event->pmu);
 
-       if (test_and_set_bit(idx, cpuc->used_mask)) {
+       if (__test_and_set_bit(idx, cpuc->used_mask)) {
                idx = find_first_zero_bit(cpuc->used_mask, sh_pmu->num_events);
                if (idx == sh_pmu->num_events)
-                       return -EAGAIN;
+                       goto out;
 
-               set_bit(idx, cpuc->used_mask);
+               __set_bit(idx, cpuc->used_mask);
                hwc->idx = idx;
        }
 
        sh_pmu->disable(hwc, idx);
 
-       cpuc->events[idx] = event;
-       set_bit(idx, cpuc->active_mask);
-
-       sh_pmu->enable(hwc, idx);
+       event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+       if (flags & PERF_EF_START)
+               sh_pmu_start(event, PERF_EF_RELOAD);
 
        perf_event_update_userpage(event);
-
-       return 0;
+       ret = 0;
+out:
+       perf_pmu_enable(event->pmu);
+       return ret;
 }
 
 static void sh_pmu_read(struct perf_event *event)
@@ -257,24 +305,56 @@ static void sh_pmu_read(struct perf_event *event)
        sh_perf_event_update(event, &event->hw, event->hw.idx);
 }
 
-static const struct pmu pmu = {
-       .enable         = sh_pmu_enable,
-       .disable        = sh_pmu_disable,
-       .read           = sh_pmu_read,
-};
-
-const struct pmu *hw_perf_event_init(struct perf_event *event)
+static int sh_pmu_event_init(struct perf_event *event)
 {
-       int err = __hw_perf_event_init(event);
+       int err;
+
+       switch (event->attr.type) {
+       case PERF_TYPE_RAW:
+       case PERF_TYPE_HW_CACHE:
+       case PERF_TYPE_HARDWARE:
+               err = __hw_perf_event_init(event);
+               break;
+
+       default:
+               return -ENOENT;
+       }
+
        if (unlikely(err)) {
                if (event->destroy)
                        event->destroy(event);
-               return ERR_PTR(err);
        }
 
-       return &pmu;
+       return err;
+}
+
+static void sh_pmu_enable(struct pmu *pmu)
+{
+       if (!sh_pmu_initialized())
+               return;
+
+       sh_pmu->enable_all();
+}
+
+static void sh_pmu_disable(struct pmu *pmu)
+{
+       if (!sh_pmu_initialized())
+               return;
+
+       sh_pmu->disable_all();
 }
 
+static struct pmu pmu = {
+       .pmu_enable     = sh_pmu_enable,
+       .pmu_disable    = sh_pmu_disable,
+       .event_init     = sh_pmu_event_init,
+       .add            = sh_pmu_add,
+       .del            = sh_pmu_del,
+       .start          = sh_pmu_start,
+       .stop           = sh_pmu_stop,
+       .read           = sh_pmu_read,
+};
+
 static void sh_pmu_setup(int cpu)
 {
        struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
@@ -299,32 +379,17 @@ sh_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
-void hw_perf_enable(void)
-{
-       if (!sh_pmu_initialized())
-               return;
-
-       sh_pmu->enable_all();
-}
-
-void hw_perf_disable(void)
-{
-       if (!sh_pmu_initialized())
-               return;
-
-       sh_pmu->disable_all();
-}
-
-int __cpuinit register_sh_pmu(struct sh_pmu *pmu)
+int __cpuinit register_sh_pmu(struct sh_pmu *_pmu)
 {
        if (sh_pmu)
                return -EBUSY;
-       sh_pmu = pmu;
+       sh_pmu = _pmu;
 
-       pr_info("Performance Events: %s support registered\n", pmu->name);
+       pr_info("Performance Events: %s support registered\n", _pmu->name);
 
-       WARN_ON(pmu->num_events > MAX_HWEVENTS);
+       WARN_ON(_pmu->num_events > MAX_HWEVENTS);
 
+       perf_pmu_register(&pmu);
        perf_cpu_notifier(sh_pmu_notifier);
        return 0;
 }
index d0e249100e98d044b804414b80d725a0ebd7e43d..552bea5113f550c415f2d9d70b86082e905b0814 100644 (file)
@@ -200,7 +200,6 @@ static void __init bootmem_init_one_node(unsigned int nid)
        unsigned long total_pages, paddr;
        unsigned long end_pfn;
        struct pglist_data *p;
-       int i;
 
        p = NODE_DATA(nid);
 
@@ -226,11 +225,12 @@ static void __init bootmem_init_one_node(unsigned int nid)
         * reservations in other nodes.
         */
        if (nid == 0) {
+               struct memblock_region *reg;
+
                /* Reserve the sections we're already using. */
-               for (i = 0; i < memblock.reserved.cnt; i++)
-                       reserve_bootmem(memblock.reserved.region[i].base,
-                                       memblock_size_bytes(&memblock.reserved, i),
-                                       BOOTMEM_DEFAULT);
+               for_each_memblock(reserved, reg) {
+                       reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
+               }
        }
 
        sparse_memory_present_with_active_regions(nid);
@@ -238,13 +238,14 @@ static void __init bootmem_init_one_node(unsigned int nid)
 
 static void __init do_init_bootmem(void)
 {
+       struct memblock_region *reg;
        int i;
 
        /* Add active regions with valid PFNs. */
-       for (i = 0; i < memblock.memory.cnt; i++) {
+       for_each_memblock(memory, reg) {
                unsigned long start_pfn, end_pfn;
-               start_pfn = memblock.memory.region[i].base >> PAGE_SHIFT;
-               end_pfn = start_pfn + memblock_size_pages(&memblock.memory, i);
+               start_pfn = memblock_region_memory_base_pfn(reg);
+               end_pfn = memblock_region_memory_end_pfn(reg);
                __add_active_range(0, start_pfn, end_pfn);
        }
 
index 4886c5c1786c24dbacadccd492a9dbf5fa8bd075..e85aae73e3dcf12a4ef1bb06b344b901efd54c6f 100644 (file)
@@ -6,4 +6,8 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
                oprofilefs.o oprofile_stats.o \
                timer_int.o )
 
+ifeq ($(CONFIG_HW_PERF_EVENTS),y)
+DRIVER_OBJS += $(addprefix ../../../drivers/oprofile/, oprofile_perf.o)
+endif
+
 oprofile-y     := $(DRIVER_OBJS) common.o backtrace.o
index ac604937f3ee16fde018d6f5b0c094a189f4d2b5..e10d89376f9b79140adaa44f7fb63f0681604482 100644 (file)
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/smp.h>
+#include <linux/perf_event.h>
 #include <asm/processor.h>
-#include "op_impl.h"
-
-static struct op_sh_model *model;
-
-static struct op_counter_config ctr[20];
 
+#ifdef CONFIG_HW_PERF_EVENTS
 extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth);
 
-static int op_sh_setup(void)
-{
-       /* Pre-compute the values to stuff in the hardware registers.  */
-       model->reg_setup(ctr);
-
-       /* Configure the registers on all cpus.  */
-       on_each_cpu(model->cpu_setup, NULL, 1);
-
-        return 0;
-}
-
-static int op_sh_create_files(struct super_block *sb, struct dentry *root)
+char *op_name_from_perf_id(void)
 {
-       int i, ret = 0;
+       const char *pmu;
+       char buf[20];
+       int size;
 
-       for (i = 0; i < model->num_counters; i++) {
-               struct dentry *dir;
-               char buf[4];
+       pmu = perf_pmu_name();
+       if (!pmu)
+               return NULL;
 
-               snprintf(buf, sizeof(buf), "%d", i);
-               dir = oprofilefs_mkdir(sb, root, buf);
+       size = snprintf(buf, sizeof(buf), "sh/%s", pmu);
+       if (size > -1 && size < sizeof(buf))
+               return buf;
 
-               ret |= oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
-               ret |= oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
-               ret |= oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
-               ret |= oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
-
-               if (model->create_files)
-                       ret |= model->create_files(sb, dir);
-               else
-                       ret |= oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
-
-               /* Dummy entries */
-               ret |= oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
-       }
-
-       return ret;
+       return NULL;
 }
 
-static int op_sh_start(void)
+int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-       /* Enable performance monitoring for all counters.  */
-       on_each_cpu(model->cpu_start, NULL, 1);
+       ops->backtrace = sh_backtrace;
 
-       return 0;
+       return oprofile_perf_init(ops);
 }
 
-static void op_sh_stop(void)
+void __exit oprofile_arch_exit(void)
 {
-       /* Disable performance monitoring for all counters.  */
-       on_each_cpu(model->cpu_stop, NULL, 1);
+       oprofile_perf_exit();
 }
-
+#else
 int __init oprofile_arch_init(struct oprofile_operations *ops)
 {
-       struct op_sh_model *lmodel = NULL;
-       int ret;
-
-       /*
-        * Always assign the backtrace op. If the counter initialization
-        * fails, we fall back to the timer which will still make use of
-        * this.
-        */
-       ops->backtrace = sh_backtrace;
-
-       /*
-        * XXX
-        *
-        * All of the SH7750/SH-4A counters have been converted to perf,
-        * this infrastructure hook is left for other users until they've
-        * had a chance to convert over, at which point all of this
-        * will be deleted.
-        */
-
-       if (!lmodel)
-               return -ENODEV;
-       if (!(current_cpu_data.flags & CPU_HAS_PERF_COUNTER))
-               return -ENODEV;
-
-       ret = lmodel->init();
-       if (unlikely(ret != 0))
-               return ret;
-
-       model = lmodel;
-
-       ops->setup              = op_sh_setup;
-       ops->create_files       = op_sh_create_files;
-       ops->start              = op_sh_start;
-       ops->stop               = op_sh_stop;
-       ops->cpu_type           = lmodel->cpu_type;
-
-       printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
-              lmodel->cpu_type);
-
-       return 0;
-}
-
-void oprofile_arch_exit(void)
-{
-       if (model && model->exit)
-               model->exit();
+       pr_info("oprofile: hardware counters not available\n");
+       return -ENODEV;
 }
+void __exit oprofile_arch_exit(void) {}
+#endif /* CONFIG_HW_PERF_EVENTS */
diff --git a/arch/sh/oprofile/op_impl.h b/arch/sh/oprofile/op_impl.h
deleted file mode 100644 (file)
index 1244479..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __OP_IMPL_H
-#define __OP_IMPL_H
-
-/* Per-counter configuration as set via oprofilefs.  */
-struct op_counter_config {
-       unsigned long enabled;
-       unsigned long event;
-
-       unsigned long count;
-
-       /* Dummy values for userspace tool compliance */
-       unsigned long kernel;
-       unsigned long user;
-       unsigned long unit_mask;
-};
-
-/* Per-architecture configury and hooks.  */
-struct op_sh_model {
-       void (*reg_setup)(struct op_counter_config *);
-       int (*create_files)(struct super_block *sb, struct dentry *dir);
-       void (*cpu_setup)(void *dummy);
-       int (*init)(void);
-       void (*exit)(void);
-       void (*cpu_start)(void *args);
-       void (*cpu_stop)(void *args);
-       char *cpu_type;
-       unsigned char num_counters;
-};
-
-/* arch/sh/oprofile/common.c */
-extern void sh_backtrace(struct pt_regs * const regs, unsigned int depth);
-
-#endif /* __OP_IMPL_H */
index 491e9d6de1912d56cea2b21f51bf8cfd7980e278..3e9d31401fb24e9dd1b6b3e67add09a4ea7f1468 100644 (file)
@@ -26,10 +26,12 @@ config SPARC
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select RTC_CLASS
        select RTC_DRV_M48T59
+       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
        select HAVE_DMA_ATTRS
        select HAVE_DMA_API_DEBUG
+       select HAVE_ARCH_JUMP_LABEL
 
 config SPARC32
        def_bool !64BIT
@@ -53,6 +55,7 @@ config SPARC64
        select RTC_DRV_BQ4802
        select RTC_DRV_SUN4V
        select RTC_DRV_STARFIRE
+       select HAVE_IRQ_WORK
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
 
index 0fca9d97d44f15bd1a3832de7e02a990e0fa6577..d4d0711de0f9f5031439927d02517d6a5e743509 100644 (file)
@@ -5,33 +5,40 @@
  *
  * This file gets included from lowlevel asm headers too, to provide
  * wrapped versions of the local_irq_*() APIs, based on the
- * raw_local_irq_*() functions from the lowlevel headers.
+ * arch_local_irq_*() functions from the lowlevel headers.
  */
 #ifndef _ASM_IRQFLAGS_H
 #define _ASM_IRQFLAGS_H
 
 #ifndef __ASSEMBLY__
 
-extern void raw_local_irq_restore(unsigned long);
-extern unsigned long __raw_local_irq_save(void);
-extern void raw_local_irq_enable(void);
+#include <linux/types.h>
 
-static inline unsigned long getipl(void)
+extern void arch_local_irq_restore(unsigned long);
+extern unsigned long arch_local_irq_save(void);
+extern void arch_local_irq_enable(void);
+
+static inline unsigned long arch_local_save_flags(void)
 {
-        unsigned long retval;
+       unsigned long flags;
+
+       asm volatile("rd        %%psr, %0" : "=r" (flags));
+       return flags;
+}
 
-        __asm__ __volatile__("rd        %%psr, %0" : "=r" (retval));
-        return retval;
+static inline void arch_local_irq_disable(void)
+{
+       arch_local_irq_save();
 }
 
-#define raw_local_save_flags(flags) ((flags) = getipl())
-#define raw_local_irq_save(flags)   ((flags) = __raw_local_irq_save())
-#define raw_local_irq_disable()     ((void) __raw_local_irq_save())
-#define raw_irqs_disabled()         ((getipl() & PSR_PIL) != 0)
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags & PSR_PIL) != 0;
+}
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline bool arch_irqs_disabled(void)
 {
-        return ((flags & PSR_PIL) != 0);
+       return arch_irqs_disabled_flags(arch_local_save_flags());
 }
 
 #endif /* (__ASSEMBLY__) */
index bfa1ea45b4cdb893ee9814e077c9fafdda3daff8..aab969c82c2b654391089b180d77d45e62416058 100644 (file)
@@ -5,7 +5,7 @@
  *
  * This file gets included from lowlevel asm headers too, to provide
  * wrapped versions of the local_irq_*() APIs, based on the
- * raw_local_irq_*() functions from the lowlevel headers.
+ * arch_local_irq_*() functions from the lowlevel headers.
  */
 #ifndef _ASM_IRQFLAGS_H
 #define _ASM_IRQFLAGS_H
@@ -14,7 +14,7 @@
 
 #ifndef __ASSEMBLY__
 
-static inline unsigned long __raw_local_save_flags(void)
+static inline unsigned long arch_local_save_flags(void)
 {
        unsigned long flags;
 
@@ -26,10 +26,7 @@ static inline unsigned long __raw_local_save_flags(void)
        return flags;
 }
 
-#define raw_local_save_flags(flags) \
-               do { (flags) = __raw_local_save_flags(); } while (0)
-
-static inline void raw_local_irq_restore(unsigned long flags)
+static inline void arch_local_irq_restore(unsigned long flags)
 {
        __asm__ __volatile__(
                "wrpr   %0, %%pil"
@@ -39,7 +36,7 @@ static inline void raw_local_irq_restore(unsigned long flags)
        );
 }
 
-static inline void raw_local_irq_disable(void)
+static inline void arch_local_irq_disable(void)
 {
        __asm__ __volatile__(
                "wrpr   %0, %%pil"
@@ -49,7 +46,7 @@ static inline void raw_local_irq_disable(void)
        );
 }
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_enable(void)
 {
        __asm__ __volatile__(
                "wrpr   0, %%pil"
@@ -59,22 +56,17 @@ static inline void raw_local_irq_enable(void)
        );
 }
 
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline int arch_irqs_disabled_flags(unsigned long flags)
 {
        return (flags > 0);
 }
 
-static inline int raw_irqs_disabled(void)
+static inline int arch_irqs_disabled(void)
 {
-       unsigned long flags = __raw_local_save_flags();
-
-       return raw_irqs_disabled_flags(flags);
+       return arch_irqs_disabled_flags(arch_local_save_flags());
 }
 
-/*
- * For spinlocks, etc:
- */
-static inline unsigned long __raw_local_irq_save(void)
+static inline unsigned long arch_local_irq_save(void)
 {
        unsigned long flags, tmp;
 
@@ -100,9 +92,6 @@ static inline unsigned long __raw_local_irq_save(void)
        return flags;
 }
 
-#define raw_local_irq_save(flags) \
-               do { (flags) = __raw_local_irq_save(); } while (0)
-
 #endif /* (__ASSEMBLY__) */
 
 #endif /* !(_ASM_IRQFLAGS_H) */
diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h
new file mode 100644 (file)
index 0000000..62e66d7
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _ASM_SPARC_JUMP_LABEL_H
+#define _ASM_SPARC_JUMP_LABEL_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <asm/system.h>
+
+#define JUMP_LABEL_NOP_SIZE 4
+
+#define JUMP_LABEL(key, label)                                 \
+       do {                                                    \
+               asm goto("1:\n\t"                               \
+                        "nop\n\t"                              \
+                        "nop\n\t"                              \
+                        ".pushsection __jump_table,  \"a\"\n\t"\
+                        ".word 1b, %l[" #label "], %c0\n\t"    \
+                        ".popsection \n\t"                     \
+                        : :  "i" (key) :  : label);\
+       } while (0)
+
+#endif /* __KERNEL__ */
+
+typedef u32 jump_label_t;
+
+struct jump_entry {
+       jump_label_t code;
+       jump_label_t target;
+       jump_label_t key;
+};
+
+#endif
index f12af880649bcd70a029ca03f7bb59c778cefe13..c67b047ef85e3d23d8db079641e827d668cf7269 100644 (file)
@@ -5,6 +5,4 @@
 
 #define MEMBLOCK_DBG(fmt...) prom_printf(fmt)
 
-#define MEMBLOCK_REAL_LIMIT    0
-
 #endif /* !(_SPARC64_MEMBLOCK_H) */
index 727af70646cbddff92f36e6c47ad782c9018ea11..6e8bfa1786dab1f45d3dff5a1dcacc31a08d4844 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef __ASM_SPARC_PERF_EVENT_H
 #define __ASM_SPARC_PERF_EVENT_H
 
-extern void set_perf_event_pending(void);
-
-#define        PERF_EVENT_INDEX_OFFSET 0
-
 #ifdef CONFIG_PERF_EVENTS
 #include <asm/ptrace.h>
 
index 0c2dc1f24a9a74adb05299a89ee07f8ed2bc1eb9..599398fbbc7cb78fd2f8849400d9092a95ffa786 100644 (file)
@@ -119,3 +119,5 @@ obj-$(CONFIG_COMPAT)    += $(audit--y)
 
 pc--$(CONFIG_PERF_EVENTS) := perf_event.o
 obj-$(CONFIG_SPARC64)  += $(pc--y)
+
+obj-$(CONFIG_SPARC64)  += jump_label.o
index e1af4372832979eb363e3b3f6d2e54a3057d3b29..0116d8d10def21a4ad9c3b73c27a95383ae4cdc2 100644 (file)
@@ -57,7 +57,7 @@
 #define SMP_NOP2
 #define SMP_NOP3
 #endif /* SMP */
-unsigned long __raw_local_irq_save(void)
+unsigned long arch_local_irq_save(void)
 {
        unsigned long retval;
        unsigned long tmp;
@@ -74,8 +74,9 @@ unsigned long __raw_local_irq_save(void)
 
        return retval;
 }
+EXPORT_SYMBOL(arch_local_irq_save);
 
-void raw_local_irq_enable(void)
+void arch_local_irq_enable(void)
 {
        unsigned long tmp;
 
@@ -89,8 +90,9 @@ void raw_local_irq_enable(void)
                : "i" (PSR_PIL)
                : "memory");
 }
+EXPORT_SYMBOL(arch_local_irq_enable);
 
-void raw_local_irq_restore(unsigned long old_psr)
+void arch_local_irq_restore(unsigned long old_psr)
 {
        unsigned long tmp;
 
@@ -105,10 +107,7 @@ void raw_local_irq_restore(unsigned long old_psr)
                : "i" (PSR_PIL), "r" (old_psr)
                : "memory");
 }
-
-EXPORT_SYMBOL(__raw_local_irq_save);
-EXPORT_SYMBOL(raw_local_irq_enable);
-EXPORT_SYMBOL(raw_local_irq_restore);
+EXPORT_SYMBOL(arch_local_irq_restore);
 
 /*
  * Dave Redman (djhr@tadpole.co.uk)
diff --git a/arch/sparc/kernel/jump_label.c b/arch/sparc/kernel/jump_label.c
new file mode 100644 (file)
index 0000000..ea2dafc
--- /dev/null
@@ -0,0 +1,47 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/cpu.h>
+
+#include <linux/jump_label.h>
+#include <linux/memory.h>
+
+#ifdef HAVE_JUMP_LABEL
+
+void arch_jump_label_transform(struct jump_entry *entry,
+                              enum jump_label_type type)
+{
+       u32 val;
+       u32 *insn = (u32 *) (unsigned long) entry->code;
+
+       if (type == JUMP_LABEL_ENABLE) {
+               s32 off = (s32)entry->target - (s32)entry->code;
+
+#ifdef CONFIG_SPARC64
+               /* ba,pt %xcc, . + (off << 2) */
+               val = 0x10680000 | ((u32) off >> 2);
+#else
+               /* ba . + (off << 2) */
+               val = 0x10800000 | ((u32) off >> 2);
+#endif
+       } else {
+               val = 0x01000000;
+       }
+
+       get_online_cpus();
+       mutex_lock(&text_mutex);
+       *insn = val;
+       flushi(insn);
+       mutex_unlock(&text_mutex);
+       put_online_cpus();
+}
+
+void arch_jump_label_text_poke_early(jump_label_t addr)
+{
+       u32 *insn_p = (u32 *) (unsigned long) addr;
+
+       *insn_p = 0x01000000;
+       flushi(insn_p);
+}
+
+#endif
index f848aadf54dc1c2c1feb537752fdf3410efbe9d8..ee3c7dde8d9fbd5af21f5dbf555628eff1c64b9c 100644 (file)
@@ -18,6 +18,9 @@
 #include <asm/spitfire.h>
 
 #ifdef CONFIG_SPARC64
+
+#include <linux/jump_label.h>
+
 static void *module_map(unsigned long size)
 {
        struct vm_struct *area;
@@ -227,6 +230,9 @@ int module_finalize(const Elf_Ehdr *hdr,
                    const Elf_Shdr *sechdrs,
                    struct module *me)
 {
+       /* make jump label nops */
+       jump_label_apply_nops(me);
+
        /* Cheetah's I-cache is fully coherent.  */
        if (tlb_type == spitfire) {
                unsigned long va;
index 548b8ca9c2106d7b7fa88d602db86a125a2a283e..b210416ace7b8f74773768cbc65f5f05f0cb9cc6 100644 (file)
@@ -114,10 +114,10 @@ static void free_msi(struct pci_pbm_info *pbm, int msi_num)
 
 static struct irq_chip msi_irq = {
        .name           = "PCI-MSI",
-       .mask           = mask_msi_irq,
-       .unmask         = unmask_msi_irq,
-       .enable         = unmask_msi_irq,
-       .disable        = mask_msi_irq,
+       .irq_mask       = mask_msi_irq,
+       .irq_unmask     = unmask_msi_irq,
+       .irq_enable     = unmask_msi_irq,
+       .irq_disable    = mask_msi_irq,
        /* XXX affinity XXX */
 };
 
index c4a6a50b4849a64c0f98759921267fbe76c3cfe7..b87873c0e8ea5f72be8ffe784e1035911b05a68c 100644 (file)
@@ -7,7 +7,7 @@
 #include <linux/init.h>
 #include <linux/irq.h>
 
-#include <linux/perf_event.h>
+#include <linux/irq_work.h>
 #include <linux/ftrace.h>
 
 #include <asm/pil.h>
@@ -43,14 +43,14 @@ void __irq_entry deferred_pcr_work_irq(int irq, struct pt_regs *regs)
 
        old_regs = set_irq_regs(regs);
        irq_enter();
-#ifdef CONFIG_PERF_EVENTS
-       perf_event_do_pending();
+#ifdef CONFIG_IRQ_WORK
+       irq_work_run();
 #endif
        irq_exit();
        set_irq_regs(old_regs);
 }
 
-void set_perf_event_pending(void)
+void arch_irq_work_raise(void)
 {
        set_softint(1 << PIL_DEFERRED_PCR_WORK);
 }
index 6318e622cfb065d9da81e40b766c12dc0a6e2e7b..0d6deb55a2ae7e4189b5ab60aec81cd8df28adb6 100644 (file)
@@ -658,13 +658,16 @@ static u64 maybe_change_configuration(struct cpu_hw_events *cpuc, u64 pcr)
 
                enc = perf_event_get_enc(cpuc->events[i]);
                pcr &= ~mask_for_index(idx);
-               pcr |= event_encoding(enc, idx);
+               if (hwc->state & PERF_HES_STOPPED)
+                       pcr |= nop_for_index(idx);
+               else
+                       pcr |= event_encoding(enc, idx);
        }
 out:
        return pcr;
 }
 
-void hw_perf_enable(void)
+static void sparc_pmu_enable(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        u64 pcr;
@@ -691,7 +694,7 @@ void hw_perf_enable(void)
        pcr_ops->write(cpuc->pcr);
 }
 
-void hw_perf_disable(void)
+static void sparc_pmu_disable(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        u64 val;
@@ -710,19 +713,65 @@ void hw_perf_disable(void)
        pcr_ops->write(cpuc->pcr);
 }
 
-static void sparc_pmu_disable(struct perf_event *event)
+static int active_event_index(struct cpu_hw_events *cpuc,
+                             struct perf_event *event)
+{
+       int i;
+
+       for (i = 0; i < cpuc->n_events; i++) {
+               if (cpuc->event[i] == event)
+                       break;
+       }
+       BUG_ON(i == cpuc->n_events);
+       return cpuc->current_idx[i];
+}
+
+static void sparc_pmu_start(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       int idx = active_event_index(cpuc, event);
+
+       if (flags & PERF_EF_RELOAD) {
+               WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+               sparc_perf_event_set_period(event, &event->hw, idx);
+       }
+
+       event->hw.state = 0;
+
+       sparc_pmu_enable_event(cpuc, &event->hw, idx);
+}
+
+static void sparc_pmu_stop(struct perf_event *event, int flags)
+{
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+       int idx = active_event_index(cpuc, event);
+
+       if (!(event->hw.state & PERF_HES_STOPPED)) {
+               sparc_pmu_disable_event(cpuc, &event->hw, idx);
+               event->hw.state |= PERF_HES_STOPPED;
+       }
+
+       if (!(event->hw.state & PERF_HES_UPTODATE) && (flags & PERF_EF_UPDATE)) {
+               sparc_perf_event_update(event, &event->hw, idx);
+               event->hw.state |= PERF_HES_UPTODATE;
+       }
+}
+
+static void sparc_pmu_del(struct perf_event *event, int _flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-       struct hw_perf_event *hwc = &event->hw;
        unsigned long flags;
        int i;
 
        local_irq_save(flags);
-       perf_disable();
+       perf_pmu_disable(event->pmu);
 
        for (i = 0; i < cpuc->n_events; i++) {
                if (event == cpuc->event[i]) {
-                       int idx = cpuc->current_idx[i];
+                       /* Absorb the final count and turn off the
+                        * event.
+                        */
+                       sparc_pmu_stop(event, PERF_EF_UPDATE);
 
                        /* Shift remaining entries down into
                         * the existing slot.
@@ -734,13 +783,6 @@ static void sparc_pmu_disable(struct perf_event *event)
                                        cpuc->current_idx[i];
                        }
 
-                       /* Absorb the final count and turn off the
-                        * event.
-                        */
-                       sparc_pmu_disable_event(cpuc, hwc, idx);
-                       barrier();
-                       sparc_perf_event_update(event, hwc, idx);
-
                        perf_event_update_userpage(event);
 
                        cpuc->n_events--;
@@ -748,23 +790,10 @@ static void sparc_pmu_disable(struct perf_event *event)
                }
        }
 
-       perf_enable();
+       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
 }
 
-static int active_event_index(struct cpu_hw_events *cpuc,
-                             struct perf_event *event)
-{
-       int i;
-
-       for (i = 0; i < cpuc->n_events; i++) {
-               if (cpuc->event[i] == event)
-                       break;
-       }
-       BUG_ON(i == cpuc->n_events);
-       return cpuc->current_idx[i];
-}
-
 static void sparc_pmu_read(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
@@ -774,15 +803,6 @@ static void sparc_pmu_read(struct perf_event *event)
        sparc_perf_event_update(event, hwc, idx);
 }
 
-static void sparc_pmu_unthrottle(struct perf_event *event)
-{
-       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-       int idx = active_event_index(cpuc, event);
-       struct hw_perf_event *hwc = &event->hw;
-
-       sparc_pmu_enable_event(cpuc, hwc, idx);
-}
-
 static atomic_t active_events = ATOMIC_INIT(0);
 static DEFINE_MUTEX(pmc_grab_mutex);
 
@@ -877,7 +897,7 @@ static int sparc_check_constraints(struct perf_event **evts,
        if (!n_ev)
                return 0;
 
-       if (n_ev > perf_max_events)
+       if (n_ev > MAX_HWEVENTS)
                return -1;
 
        msk0 = perf_event_get_msk(events[0]);
@@ -984,23 +1004,27 @@ static int collect_events(struct perf_event *group, int max_count,
        return n;
 }
 
-static int sparc_pmu_enable(struct perf_event *event)
+static int sparc_pmu_add(struct perf_event *event, int ef_flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        int n0, ret = -EAGAIN;
        unsigned long flags;
 
        local_irq_save(flags);
-       perf_disable();
+       perf_pmu_disable(event->pmu);
 
        n0 = cpuc->n_events;
-       if (n0 >= perf_max_events)
+       if (n0 >= MAX_HWEVENTS)
                goto out;
 
        cpuc->event[n0] = event;
        cpuc->events[n0] = event->hw.event_base;
        cpuc->current_idx[n0] = PIC_NO_INDEX;
 
+       event->hw.state = PERF_HES_UPTODATE;
+       if (!(ef_flags & PERF_EF_START))
+               event->hw.state |= PERF_HES_STOPPED;
+
        /*
         * If group events scheduling transaction was started,
         * skip the schedulability test here, it will be peformed
@@ -1020,12 +1044,12 @@ nocheck:
 
        ret = 0;
 out:
-       perf_enable();
+       perf_pmu_enable(event->pmu);
        local_irq_restore(flags);
        return ret;
 }
 
-static int __hw_perf_event_init(struct perf_event *event)
+static int sparc_pmu_event_init(struct perf_event *event)
 {
        struct perf_event_attr *attr = &event->attr;
        struct perf_event *evts[MAX_HWEVENTS];
@@ -1038,22 +1062,33 @@ static int __hw_perf_event_init(struct perf_event *event)
        if (atomic_read(&nmi_active) < 0)
                return -ENODEV;
 
-       pmap = NULL;
-       if (attr->type == PERF_TYPE_HARDWARE) {
+       switch (attr->type) {
+       case PERF_TYPE_HARDWARE:
                if (attr->config >= sparc_pmu->max_events)
                        return -EINVAL;
                pmap = sparc_pmu->event_map(attr->config);
-       } else if (attr->type == PERF_TYPE_HW_CACHE) {
+               break;
+
+       case PERF_TYPE_HW_CACHE:
                pmap = sparc_map_cache_event(attr->config);
                if (IS_ERR(pmap))
                        return PTR_ERR(pmap);
-       } else if (attr->type != PERF_TYPE_RAW)
-               return -EOPNOTSUPP;
+               break;
+
+       case PERF_TYPE_RAW:
+               pmap = NULL;
+               break;
+
+       default:
+               return -ENOENT;
+
+       }
 
        if (pmap) {
                hwc->event_base = perf_event_encode(pmap);
        } else {
-               /* User gives us "(encoding << 16) | pic_mask" for
+               /*
+                * User gives us "(encoding << 16) | pic_mask" for
                 * PERF_TYPE_RAW events.
                 */
                hwc->event_base = attr->config;
@@ -1071,7 +1106,7 @@ static int __hw_perf_event_init(struct perf_event *event)
        n = 0;
        if (event->group_leader != event) {
                n = collect_events(event->group_leader,
-                                  perf_max_events - 1,
+                                  MAX_HWEVENTS - 1,
                                   evts, events, current_idx_dmy);
                if (n < 0)
                        return -EINVAL;
@@ -1107,10 +1142,11 @@ static int __hw_perf_event_init(struct perf_event *event)
  * Set the flag to make pmu::enable() not perform the
  * schedulability test, it will be performed at commit time
  */
-static void sparc_pmu_start_txn(const struct pmu *pmu)
+static void sparc_pmu_start_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 
+       perf_pmu_disable(pmu);
        cpuhw->group_flag |= PERF_EVENT_TXN;
 }
 
@@ -1119,11 +1155,12 @@ static void sparc_pmu_start_txn(const struct pmu *pmu)
  * Clear the flag and pmu::enable() will perform the
  * schedulability test.
  */
-static void sparc_pmu_cancel_txn(const struct pmu *pmu)
+static void sparc_pmu_cancel_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 
        cpuhw->group_flag &= ~PERF_EVENT_TXN;
+       perf_pmu_enable(pmu);
 }
 
 /*
@@ -1131,7 +1168,7 @@ static void sparc_pmu_cancel_txn(const struct pmu *pmu)
  * Perform the group schedulability test as a whole
  * Return 0 if success
  */
-static int sparc_pmu_commit_txn(const struct pmu *pmu)
+static int sparc_pmu_commit_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        int n;
@@ -1147,28 +1184,24 @@ static int sparc_pmu_commit_txn(const struct pmu *pmu)
                return -EAGAIN;
 
        cpuc->group_flag &= ~PERF_EVENT_TXN;
+       perf_pmu_enable(pmu);
        return 0;
 }
 
-static const struct pmu pmu = {
-       .enable         = sparc_pmu_enable,
-       .disable        = sparc_pmu_disable,
+static struct pmu pmu = {
+       .pmu_enable     = sparc_pmu_enable,
+       .pmu_disable    = sparc_pmu_disable,
+       .event_init     = sparc_pmu_event_init,
+       .add            = sparc_pmu_add,
+       .del            = sparc_pmu_del,
+       .start          = sparc_pmu_start,
+       .stop           = sparc_pmu_stop,
        .read           = sparc_pmu_read,
-       .unthrottle     = sparc_pmu_unthrottle,
        .start_txn      = sparc_pmu_start_txn,
        .cancel_txn     = sparc_pmu_cancel_txn,
        .commit_txn     = sparc_pmu_commit_txn,
 };
 
-const struct pmu *hw_perf_event_init(struct perf_event *event)
-{
-       int err = __hw_perf_event_init(event);
-
-       if (err)
-               return ERR_PTR(err);
-       return &pmu;
-}
-
 void perf_event_print_debug(void)
 {
        unsigned long flags;
@@ -1244,7 +1277,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self,
                        continue;
 
                if (perf_event_overflow(event, 1, &data, regs))
-                       sparc_pmu_disable_event(cpuc, hwc, idx);
+                       sparc_pmu_stop(event, 0);
        }
 
        return NOTIFY_STOP;
@@ -1285,28 +1318,21 @@ void __init init_hw_perf_events(void)
 
        pr_cont("Supported PMU type is '%s'\n", sparc_pmu_type);
 
-       /* All sparc64 PMUs currently have 2 events.  */
-       perf_max_events = 2;
-
+       perf_pmu_register(&pmu);
        register_die_notifier(&perf_event_nmi_notifier);
 }
 
-static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip)
-{
-       if (entry->nr < PERF_MAX_STACK_DEPTH)
-               entry->ip[entry->nr++] = ip;
-}
-
-static void perf_callchain_kernel(struct pt_regs *regs,
-                                 struct perf_callchain_entry *entry)
+void perf_callchain_kernel(struct perf_callchain_entry *entry,
+                          struct pt_regs *regs)
 {
        unsigned long ksp, fp;
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        int graph = 0;
 #endif
 
-       callchain_store(entry, PERF_CONTEXT_KERNEL);
-       callchain_store(entry, regs->tpc);
+       stack_trace_flush();
+
+       perf_callchain_store(entry, regs->tpc);
 
        ksp = regs->u_regs[UREG_I6];
        fp = ksp + STACK_BIAS;
@@ -1330,13 +1356,13 @@ static void perf_callchain_kernel(struct pt_regs *regs,
                        pc = sf->callers_pc;
                        fp = (unsigned long)sf->fp + STACK_BIAS;
                }
-               callchain_store(entry, pc);
+               perf_callchain_store(entry, pc);
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
                if ((pc + 8UL) == (unsigned long) &return_to_handler) {
                        int index = current->curr_ret_stack;
                        if (current->ret_stack && index >= graph) {
                                pc = current->ret_stack[index - graph].ret;
-                               callchain_store(entry, pc);
+                               perf_callchain_store(entry, pc);
                                graph++;
                        }
                }
@@ -1344,13 +1370,12 @@ static void perf_callchain_kernel(struct pt_regs *regs,
        } while (entry->nr < PERF_MAX_STACK_DEPTH);
 }
 
-static void perf_callchain_user_64(struct pt_regs *regs,
-                                  struct perf_callchain_entry *entry)
+static void perf_callchain_user_64(struct perf_callchain_entry *entry,
+                                  struct pt_regs *regs)
 {
        unsigned long ufp;
 
-       callchain_store(entry, PERF_CONTEXT_USER);
-       callchain_store(entry, regs->tpc);
+       perf_callchain_store(entry, regs->tpc);
 
        ufp = regs->u_regs[UREG_I6] + STACK_BIAS;
        do {
@@ -1363,17 +1388,16 @@ static void perf_callchain_user_64(struct pt_regs *regs,
 
                pc = sf.callers_pc;
                ufp = (unsigned long)sf.fp + STACK_BIAS;
-               callchain_store(entry, pc);
+               perf_callchain_store(entry, pc);
        } while (entry->nr < PERF_MAX_STACK_DEPTH);
 }
 
-static void perf_callchain_user_32(struct pt_regs *regs,
-                                  struct perf_callchain_entry *entry)
+static void perf_callchain_user_32(struct perf_callchain_entry *entry,
+                                  struct pt_regs *regs)
 {
        unsigned long ufp;
 
-       callchain_store(entry, PERF_CONTEXT_USER);
-       callchain_store(entry, regs->tpc);
+       perf_callchain_store(entry, regs->tpc);
 
        ufp = regs->u_regs[UREG_I6] & 0xffffffffUL;
        do {
@@ -1386,34 +1410,16 @@ static void perf_callchain_user_32(struct pt_regs *regs,
 
                pc = sf.callers_pc;
                ufp = (unsigned long)sf.fp;
-               callchain_store(entry, pc);
+               perf_callchain_store(entry, pc);
        } while (entry->nr < PERF_MAX_STACK_DEPTH);
 }
 
-/* Like powerpc we can't get PMU interrupts within the PMU handler,
- * so no need for separate NMI and IRQ chains as on x86.
- */
-static DEFINE_PER_CPU(struct perf_callchain_entry, callchain);
-
-struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
-       struct perf_callchain_entry *entry = &__get_cpu_var(callchain);
-
-       entry->nr = 0;
-       if (!user_mode(regs)) {
-               stack_trace_flush();
-               perf_callchain_kernel(regs, entry);
-               if (current->mm)
-                       regs = task_pt_regs(current);
-               else
-                       regs = NULL;
-       }
-       if (regs) {
-               flushw_user();
-               if (test_thread_flag(TIF_32BIT))
-                       perf_callchain_user_32(regs, entry);
-               else
-                       perf_callchain_user_64(regs, entry);
-       }
-       return entry;
+       flushw_user();
+       if (test_thread_flag(TIF_32BIT))
+               perf_callchain_user_32(entry, regs);
+       else
+               perf_callchain_user_64(entry, regs);
 }
index f0434513df159301da052662442b281bea30b5c5..4c2572773b55a330868933b633882f9520a155ba 100644 (file)
@@ -785,8 +785,7 @@ static int find_node(unsigned long addr)
        return -1;
 }
 
-static unsigned long long nid_range(unsigned long long start,
-                                   unsigned long long end, int *nid)
+u64 memblock_nid_range(u64 start, u64 end, int *nid)
 {
        *nid = find_node(start);
        start += PAGE_SIZE;
@@ -804,8 +803,7 @@ static unsigned long long nid_range(unsigned long long start,
        return start;
 }
 #else
-static unsigned long long nid_range(unsigned long long start,
-                                   unsigned long long end, int *nid)
+u64 memblock_nid_range(u64 start, u64 end, int *nid)
 {
        *nid = 0;
        return end;
@@ -822,8 +820,7 @@ static void __init allocate_node_data(int nid)
        struct pglist_data *p;
 
 #ifdef CONFIG_NEED_MULTIPLE_NODES
-       paddr = memblock_alloc_nid(sizeof(struct pglist_data),
-                             SMP_CACHE_BYTES, nid, nid_range);
+       paddr = memblock_alloc_try_nid(sizeof(struct pglist_data), SMP_CACHE_BYTES, nid);
        if (!paddr) {
                prom_printf("Cannot allocate pglist_data for nid[%d]\n", nid);
                prom_halt();
@@ -843,8 +840,7 @@ static void __init allocate_node_data(int nid)
        if (p->node_spanned_pages) {
                num_pages = bootmem_bootmap_pages(p->node_spanned_pages);
 
-               paddr = memblock_alloc_nid(num_pages << PAGE_SHIFT, PAGE_SIZE, nid,
-                                     nid_range);
+               paddr = memblock_alloc_try_nid(num_pages << PAGE_SHIFT, PAGE_SIZE, nid);
                if (!paddr) {
                        prom_printf("Cannot allocate bootmap for nid[%d]\n",
                                  nid);
@@ -972,19 +968,19 @@ int of_node_to_nid(struct device_node *dp)
 
 static void __init add_node_ranges(void)
 {
-       int i;
+       struct memblock_region *reg;
 
-       for (i = 0; i < memblock.memory.cnt; i++) {
-               unsigned long size = memblock_size_bytes(&memblock.memory, i);
+       for_each_memblock(memory, reg) {
+               unsigned long size = reg->size;
                unsigned long start, end;
 
-               start = memblock.memory.region[i].base;
+               start = reg->base;
                end = start + size;
                while (start < end) {
                        unsigned long this_end;
                        int nid;
 
-                       this_end = nid_range(start, end, &nid);
+                       this_end = memblock_nid_range(start, end, &nid);
 
                        numadbg("Adding active range nid[%d] "
                                "start[%lx] end[%lx]\n",
@@ -1281,7 +1277,7 @@ static void __init bootmem_init_nonnuma(void)
 {
        unsigned long top_of_ram = memblock_end_of_DRAM();
        unsigned long total_ram = memblock_phys_mem_size();
-       unsigned int i;
+       struct memblock_region *reg;
 
        numadbg("bootmem_init_nonnuma()\n");
 
@@ -1292,15 +1288,14 @@ static void __init bootmem_init_nonnuma(void)
 
        init_node_masks_nonnuma();
 
-       for (i = 0; i < memblock.memory.cnt; i++) {
-               unsigned long size = memblock_size_bytes(&memblock.memory, i);
+       for_each_memblock(memory, reg) {
                unsigned long start_pfn, end_pfn;
 
-               if (!size)
+               if (!reg->size)
                        continue;
 
-               start_pfn = memblock.memory.region[i].base >> PAGE_SHIFT;
-               end_pfn = start_pfn + memblock_size_pages(&memblock.memory, i);
+               start_pfn = memblock_region_memory_base_pfn(reg);
+               end_pfn = memblock_region_memory_end_pfn(reg);
                add_active_range(0, start_pfn, end_pfn);
        }
 
@@ -1318,7 +1313,7 @@ static void __init reserve_range_in_node(int nid, unsigned long start,
                unsigned long this_end;
                int n;
 
-               this_end = nid_range(start, end, &n);
+               this_end = memblock_nid_range(start, end, &n);
                if (n == nid) {
                        numadbg("      MATCH reserving range [%lx:%lx]\n",
                                start, this_end);
@@ -1334,17 +1329,12 @@ static void __init reserve_range_in_node(int nid, unsigned long start,
 
 static void __init trim_reserved_in_node(int nid)
 {
-       int i;
+       struct memblock_region *reg;
 
        numadbg("  trim_reserved_in_node(%d)\n", nid);
 
-       for (i = 0; i < memblock.reserved.cnt; i++) {
-               unsigned long start = memblock.reserved.region[i].base;
-               unsigned long size = memblock_size_bytes(&memblock.reserved, i);
-               unsigned long end = start + size;
-
-               reserve_range_in_node(nid, start, end);
-       }
+       for_each_memblock(reserved, reg)
+               reserve_range_in_node(nid, reg->base, reg->base + reg->size);
 }
 
 static void __init bootmem_init_one_node(int nid)
index fa6e4e219b9ce436db25fcf3aa168d4b9f559ae2..d9850c2b9bf21275fb6e2de0ba69842a6c35b723 100644 (file)
@@ -39,7 +39,7 @@ void p1275_cmd_direct(unsigned long *args)
        unsigned long flags;
 
        raw_local_save_flags(flags);
-       raw_local_irq_restore(PIL_NMI);
+       raw_local_irq_restore((unsigned long)PIL_NMI);
        raw_spin_lock(&prom_entry_lock);
 
        prom_world(1);
index 45cf67c2f2864e195544e21a42b750bb68b82a13..a11d4837ee4d6526137858e8fdd6226deb0a95d0 100644 (file)
@@ -103,55 +103,57 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
 #define INITIAL_INTERRUPTS_ENABLED INT_MASK(INT_MEM_ERROR)
 
 /* Disable interrupts. */
-#define raw_local_irq_disable() \
+#define arch_local_irq_disable() \
        interrupt_mask_set_mask(LINUX_MASKABLE_INTERRUPTS)
 
 /* Disable all interrupts, including NMIs. */
-#define raw_local_irq_disable_all() \
+#define arch_local_irq_disable_all() \
        interrupt_mask_set_mask(-1UL)
 
 /* Re-enable all maskable interrupts. */
-#define raw_local_irq_enable() \
+#define arch_local_irq_enable() \
        interrupt_mask_reset_mask(__get_cpu_var(interrupts_enabled_mask))
 
 /* Disable or enable interrupts based on flag argument. */
-#define raw_local_irq_restore(disabled) do { \
+#define arch_local_irq_restore(disabled) do { \
        if (disabled) \
-               raw_local_irq_disable(); \
+               arch_local_irq_disable(); \
        else \
-               raw_local_irq_enable(); \
+               arch_local_irq_enable(); \
 } while (0)
 
 /* Return true if "flags" argument means interrupts are disabled. */
-#define raw_irqs_disabled_flags(flags) ((flags) != 0)
+#define arch_irqs_disabled_flags(flags) ((flags) != 0)
 
 /* Return true if interrupts are currently disabled. */
-#define raw_irqs_disabled() interrupt_mask_check(INT_MEM_ERROR)
+#define arch_irqs_disabled() interrupt_mask_check(INT_MEM_ERROR)
 
 /* Save whether interrupts are currently disabled. */
-#define raw_local_save_flags(flags) ((flags) = raw_irqs_disabled())
+#define arch_local_save_flags() arch_irqs_disabled()
 
 /* Save whether interrupts are currently disabled, then disable them. */
-#define raw_local_irq_save(flags) \
-       do { raw_local_save_flags(flags); raw_local_irq_disable(); } while (0)
+#define arch_local_irq_save() ({ \
+       unsigned long __flags = arch_local_save_flags(); \
+       arch_local_irq_disable(); \
+       __flags; })
 
 /* Prevent the given interrupt from being enabled next time we enable irqs. */
-#define raw_local_irq_mask(interrupt) \
+#define arch_local_irq_mask(interrupt) \
        (__get_cpu_var(interrupts_enabled_mask) &= ~INT_MASK(interrupt))
 
 /* Prevent the given interrupt from being enabled immediately. */
-#define raw_local_irq_mask_now(interrupt) do { \
-       raw_local_irq_mask(interrupt); \
+#define arch_local_irq_mask_now(interrupt) do { \
+       arch_local_irq_mask(interrupt); \
        interrupt_mask_set(interrupt); \
 } while (0)
 
 /* Allow the given interrupt to be enabled next time we enable irqs. */
-#define raw_local_irq_unmask(interrupt) \
+#define arch_local_irq_unmask(interrupt) \
        (__get_cpu_var(interrupts_enabled_mask) |= INT_MASK(interrupt))
 
 /* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */
-#define raw_local_irq_unmask_now(interrupt) do { \
-       raw_local_irq_unmask(interrupt); \
+#define arch_local_irq_unmask_now(interrupt) do { \
+       arch_local_irq_unmask(interrupt); \
        if (!irqs_disabled()) \
                interrupt_mask_reset(interrupt); \
 } while (0)
index 596c600869305ade6f13025a18a20039193ddd64..9a27d563fc30968ce3efb46ac11ce241e10d8cc0 100644 (file)
@@ -208,7 +208,7 @@ static void tile_irq_chip_eoi(unsigned int irq)
 }
 
 static struct irq_chip tile_irq_chip = {
-       .typename = "tile_irq_chip",
+       .name = "tile_irq_chip",
        .ack = tile_irq_chip_ack,
        .eoi = tile_irq_chip_eoi,
        .mask = tile_irq_chip_mask,
@@ -288,7 +288,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-               seq_printf(p, " %14s", irq_desc[i].chip->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->name);
                seq_printf(p, "  %s", action->name);
 
                for (action = action->next; action; action = action->next)
index a3f0b04d7101ccb1fea64254339328fbec12412f..a746e3037a5bc896462affb2c62ab493a625cc58 100644 (file)
@@ -46,7 +46,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-               seq_printf(p, " %14s", irq_desc[i].chip->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->name);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
@@ -369,7 +369,7 @@ static void dummy(unsigned int irq)
 
 /* This is used for everything else than the timer. */
 static struct irq_chip normal_irq_type = {
-       .typename = "SIGIO",
+       .name = "SIGIO",
        .release = free_irq_by_irq_and_dev,
        .disable = dummy,
        .enable = dummy,
@@ -378,7 +378,7 @@ static struct irq_chip normal_irq_type = {
 };
 
 static struct irq_chip SIGVTALRM_irq_type = {
-       .typename = "SIGVTALRM",
+       .name = "SIGVTALRM",
        .release = free_irq_by_irq_and_dev,
        .shutdown = dummy, /* never called */
        .disable = dummy,
index cea0cd9a316fb987bfa611a1dffa06cdba1f0332..dfabfefc21c48981c456faa683108dd9b6b7a9a8 100644 (file)
@@ -25,14 +25,17 @@ config X86
        select HAVE_IDE
        select HAVE_OPROFILE
        select HAVE_PERF_EVENTS if (!M386 && !M486)
+       select HAVE_IRQ_WORK
        select HAVE_IOREMAP_PROT
        select HAVE_KPROBES
+       select HAVE_MEMBLOCK
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARCH_WANT_FRAME_POINTERS
        select HAVE_DMA_ATTRS
        select HAVE_KRETPROBES
        select HAVE_OPTPROBES
        select HAVE_FTRACE_MCOUNT_RECORD
+       select HAVE_C_RECORDMCOUNT
        select HAVE_DYNAMIC_FTRACE
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_GRAPH_TRACER
@@ -59,6 +62,12 @@ config X86
        select ANON_INODES
        select HAVE_ARCH_KMEMCHECK
        select HAVE_USER_RETURN_NOTIFIER
+       select HAVE_ARCH_JUMP_LABEL
+       select HAVE_TEXT_POKE_SMP
+       select HAVE_GENERIC_HARDIRQS
+       select HAVE_SPARSE_IRQ
+       select GENERIC_IRQ_PROBE
+       select GENERIC_PENDING_IRQ if SMP
 
 config INSTRUCTION_DECODER
        def_bool (KPROBES || PERF_EVENTS)
@@ -193,27 +202,10 @@ config ARCH_SUPPORTS_OPTIMIZED_INLINING
 config ARCH_SUPPORTS_DEBUG_PAGEALLOC
        def_bool y
 
-config HAVE_EARLY_RES
-       def_bool y
-
 config HAVE_INTEL_TXT
        def_bool y
        depends on EXPERIMENTAL && DMAR && ACPI
 
-# Use the generic interrupt handling code in kernel/irq/:
-config GENERIC_HARDIRQS
-       def_bool y
-
-config GENERIC_HARDIRQS_NO__DO_IRQ
-       def_bool y
-
-config GENERIC_IRQ_PROBE
-       def_bool y
-
-config GENERIC_PENDING_IRQ
-       def_bool y
-       depends on GENERIC_HARDIRQS && SMP
-
 config USE_GENERIC_SMP_HELPERS
        def_bool y
        depends on SMP
@@ -296,23 +288,6 @@ config X86_X2APIC
 
          If you don't know what to do here, say N.
 
-config SPARSE_IRQ
-       bool "Support sparse irq numbering"
-       depends on PCI_MSI || HT_IRQ
-       ---help---
-         This enables support for sparse irqs. This is useful for distro
-         kernels that want to define a high CONFIG_NR_CPUS value but still
-         want to have low kernel memory footprint on smaller machines.
-
-         ( Sparse IRQs can also be beneficial on NUMA boxes, as they spread
-           out the irq_desc[] array in a more NUMA-friendly way. )
-
-         If you don't know what to do here, say N.
-
-config NUMA_IRQ_DESC
-       def_bool y
-       depends on SPARSE_IRQ && NUMA
-
 config X86_MPPARSE
        bool "Enable MPS table" if ACPI
        default y
@@ -517,25 +492,6 @@ if PARAVIRT_GUEST
 
 source "arch/x86/xen/Kconfig"
 
-config VMI
-       bool "VMI Guest support (DEPRECATED)"
-       select PARAVIRT
-       depends on X86_32
-       ---help---
-         VMI provides a paravirtualized interface to the VMware ESX server
-         (it could be used by other hypervisors in theory too, but is not
-         at the moment), by linking the kernel to a GPL-ed ROM module
-         provided by the hypervisor.
-
-         As of September 2009, VMware has started a phased retirement
-         of this feature from VMware's products. Please see
-         feature-removal-schedule.txt for details.  If you are
-         planning to enable this option, please note that you cannot
-         live migrate a VMI enabled VM to a future VMware product,
-         which doesn't support VMI. So if you expect your kernel to
-         seamlessly migrate to newer VMware products, keep this
-         disabled.
-
 config KVM_CLOCK
        bool "KVM paravirtualized clock"
        select PARAVIRT
@@ -590,16 +546,7 @@ config PARAVIRT_DEBUG
          a paravirt_op is missing when it is called.
 
 config NO_BOOTMEM
-       default y
-       bool "Disable Bootmem code"
-       ---help---
-         Use early_res directly instead of bootmem before slab is ready.
-               - allocator (buddy) [generic]
-               - early allocator (bootmem) [generic]
-               - very early allocator (reserve_early*()) [x86]
-               - very very early allocator (early brk model) [x86]
-         So reduce one layer between early allocator to final allocator
-
+       def_bool y
 
 config MEMTEST
        bool "Memtest"
@@ -670,7 +617,7 @@ config GART_IOMMU
        bool "GART IOMMU support" if EMBEDDED
        default y
        select SWIOTLB
-       depends on X86_64 && PCI && K8_NB
+       depends on X86_64 && PCI && AMD_NB
        ---help---
          Support for full DMA access of devices with 32bit memory access only
          on systems with more than 3GB. This is usually needed for USB,
@@ -795,6 +742,17 @@ config SCHED_MC
          making when dealing with multi-core CPU chips at a cost of slightly
          increased overhead in some places. If unsure say N here.
 
+config IRQ_TIME_ACCOUNTING
+       bool "Fine granularity task level IRQ time accounting"
+       default n
+       ---help---
+         Select this option to enable fine granularity task irq time
+         accounting. This is done by reading a timestamp on each
+         transitions between softirq and hardirq state, so there can be a
+         small performance impact.
+
+         If in doubt, say N here.
+
 source "kernel/Kconfig.preempt"
 
 config X86_UP_APIC
@@ -1148,6 +1106,9 @@ config X86_PAE
 config ARCH_PHYS_ADDR_T_64BIT
        def_bool X86_64 || X86_PAE
 
+config ARCH_DMA_ADDR_T_64BIT
+       def_bool X86_64 || HIGHMEM64G
+
 config DIRECT_GBPAGES
        bool "Enable 1GB pages for kernel pagetables" if EMBEDDED
        default y
@@ -1326,25 +1287,34 @@ config X86_BOOTPARAM_MEMORY_CORRUPTION_CHECK
          Set whether the default state of memory_corruption_check is
          on or off.
 
-config X86_RESERVE_LOW_64K
-       bool "Reserve low 64K of RAM on AMI/Phoenix BIOSen"
-       default y
+config X86_RESERVE_LOW
+       int "Amount of low memory, in kilobytes, to reserve for the BIOS"
+       default 64
+       range 4 640
        ---help---
-         Reserve the first 64K of physical RAM on BIOSes that are known
-         to potentially corrupt that memory range. A numbers of BIOSes are
-         known to utilize this area during suspend/resume, so it must not
-         be used by the kernel.
+         Specify the amount of low memory to reserve for the BIOS.
+
+         The first page contains BIOS data structures that the kernel
+         must not use, so that page must always be reserved.
+
+         By default we reserve the first 64K of physical RAM, as a
+         number of BIOSes are known to corrupt that memory range
+         during events such as suspend/resume or monitor cable
+         insertion, so it must not be used by the kernel.
 
-         Set this to N if you are absolutely sure that you trust the BIOS
-         to get all its memory reservations and usages right.
+         You can set this to 4 if you are absolutely sure that you
+         trust the BIOS to get all its memory reservations and usages
+         right.  If you know your BIOS have problems beyond the
+         default 64K area, you can set this to 640 to avoid using the
+         entire low memory range.
 
-         If you have doubts about the BIOS (e.g. suspend/resume does not
-         work or there's kernel crashes after certain hardware hotplug
-         events) and it's not AMI or Phoenix, then you might want to enable
-         X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check typical
-         corruption patterns.
+         If you have doubts about the BIOS (e.g. suspend/resume does
+         not work or there's kernel crashes after certain hardware
+         hotplug events) then you might want to enable
+         X86_CHECK_BIOS_CORRUPTION=y to allow the kernel to check
+         typical corruption patterns.
 
-         Say Y if unsure.
+         Leave this to the default value of 64 if you are unsure.
 
 config MATH_EMULATION
        bool
@@ -1900,7 +1870,7 @@ config PCI_GODIRECT
        bool "Direct"
 
 config PCI_GOOLPC
-       bool "OLPC"
+       bool "OLPC XO-1"
        depends on OLPC
 
 config PCI_GOANY
@@ -2061,14 +2031,21 @@ config SCx200HR_TIMER
 config OLPC
        bool "One Laptop Per Child support"
        select GPIOLIB
+       select OLPC_OPENFIRMWARE
        ---help---
          Add support for detecting the unique features of the OLPC
          XO hardware.
 
+config OLPC_XO1
+       tristate "OLPC XO-1 support"
+       depends on OLPC && PCI
+       ---help---
+         Add support for non-essential features of the OLPC XO-1 laptop.
+
 config OLPC_OPENFIRMWARE
        bool "Support for OLPC's Open Firmware"
        depends on !X86_64 && !X86_PAE
-       default y if OLPC
+       default n
        help
          This option adds support for the implementation of Open Firmware
          that is used on the OLPC XO-1 Children's Machine.
@@ -2076,7 +2053,7 @@ config OLPC_OPENFIRMWARE
 
 endif # X86_32
 
-config K8_NB
+config AMD_NB
        def_bool y
        depends on CPU_SUP_AMD && PCI
 
@@ -2125,6 +2102,10 @@ config HAVE_ATOMIC_IOMAP
        def_bool y
        depends on X86_32
 
+config HAVE_TEXT_POKE_SMP
+       bool
+       select STOP_MACHINE if SMP
+
 source "net/Kconfig"
 
 source "drivers/Kconfig"
index 75085080b63e2f74d32d4fa2b4bd2f8972d2b7de..e5bb96b10f1af5bad62466789d7f2d10e389edca 100644 (file)
@@ -43,6 +43,10 @@ config EARLY_PRINTK
          with klogd/syslogd or the X server. You should normally N here,
          unless you want to debug such a crash.
 
+config EARLY_PRINTK_MRST
+       bool "Early printk for MRST platform support"
+       depends on EARLY_PRINTK && X86_MRST
+
 config EARLY_PRINTK_DBGP
        bool "Early printk via EHCI debug port"
        depends on EARLY_PRINTK && PCI
index e8c8881351b3a5a0b17429851732e0b12405d7c6..b02e509072a790b1fbea3387f8749b5326beb822 100644 (file)
@@ -96,8 +96,12 @@ cfi := $(call as-instr,.cfi_startproc\n.cfi_rel_offset $(sp-y)$(comma)0\n.cfi_en
 # is .cfi_signal_frame supported too?
 cfi-sigframe := $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1)
 cfi-sections := $(call as-instr,.cfi_sections .debug_frame,-DCONFIG_AS_CFI_SECTIONS=1)
-KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections)
-KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections)
+
+# does binutils support specific instructions?
+asinstr := $(call as-instr,fxsaveq (%rax),-DCONFIG_AS_FXSAVEQ=1)
+
+KBUILD_AFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr)
+KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr)
 
 LDFLAGS := -m elf_$(UTS_MACHINE)
 
index bc6abb7bc7ee3084aa8b5d87ae19244715469990..76561d20ea2f27f0edfd0eee6d043b98c6aa6e90 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <linux/stringify.h>
+#include <linux/jump_label.h>
 #include <asm/asm.h>
 
 /*
@@ -160,6 +161,8 @@ static inline void apply_paravirt(struct paravirt_patch_site *start,
 #define __parainstructions_end NULL
 #endif
 
+extern void *text_poke_early(void *addr, const void *opcode, size_t len);
+
 /*
  * Clear and restore the kernel write-protection flag on the local CPU.
  * Allows the kernel to edit read-only pages.
@@ -180,4 +183,12 @@ static inline void apply_paravirt(struct paravirt_patch_site *start,
 extern void *text_poke(void *addr, const void *opcode, size_t len);
 extern void *text_poke_smp(void *addr, const void *opcode, size_t len);
 
+#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
+#define IDEAL_NOP_SIZE_5 5
+extern unsigned char ideal_nop5[IDEAL_NOP_SIZE_5];
+extern void arch_init_ideal_nop5(void);
+#else
+static inline void arch_init_ideal_nop5(void) {}
+#endif
+
 #endif /* _ASM_X86_ALTERNATIVE_H */
index 5af2982133b5435b492372c447eef8c849b0eac4..a6863a2dec1f6883b6be0b3fd68ca7f6d8982d83 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
  * Author: Joerg Roedel <joerg.roedel@amd.com>
  *         Leo Duran <leo.duran@amd.com>
  *
 
 #ifdef CONFIG_AMD_IOMMU
 
-extern void amd_iommu_detect(void);
+extern int amd_iommu_detect(void);
 
 #else
 
-static inline void amd_iommu_detect(void) { }
+static inline int amd_iommu_detect(void) { return -ENODEV; }
 
 #endif
 
index cb030374b90aeb526ad7f985527def42643bc1a9..916bc8111a01fa5de3a5df9f35ce3b8b60113342 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Advanced Micro Devices, Inc.
+ * Copyright (C) 2009-2010 Advanced Micro Devices, Inc.
  * Author: Joerg Roedel <joerg.roedel@amd.com>
  *
  * This program is free software; you can redistribute it and/or modify it
index 08616180deaf5b1e94bfe9ad0079cec7e9c619a3..e3509fc303bf5a54069e5b9b6b6edbc9ec390a49 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
  * Author: Joerg Roedel <joerg.roedel@amd.com>
  *         Leo Duran <leo.duran@amd.com>
  *
@@ -416,13 +416,22 @@ struct amd_iommu {
        struct dma_ops_domain *default_dom;
 
        /*
-        * This array is required to work around a potential BIOS bug.
-        * The BIOS may miss to restore parts of the PCI configuration
-        * space when the system resumes from S3. The result is that the
-        * IOMMU does not execute commands anymore which leads to system
-        * failure.
+        * We can't rely on the BIOS to restore all values on reinit, so we
+        * need to stash them
         */
-       u32 cache_cfg[4];
+
+       /* The iommu BAR */
+       u32 stored_addr_lo;
+       u32 stored_addr_hi;
+
+       /*
+        * Each iommu has 6 l1s, each of which is documented as having 0x12
+        * registers
+        */
+       u32 stored_l1[6][0x12];
+
+       /* The l2 indirect registers */
+       u32 stored_l2[0x83];
 };
 
 /*
similarity index 61%
rename from arch/x86/include/asm/k8.h
rename to arch/x86/include/asm/amd_nb.h
index af00bd1d208934941f00ba7e911c20dd868a3f2b..c8517f81b21e73f9f2c428a26f2fb8995f73011f 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef _ASM_X86_K8_H
-#define _ASM_X86_K8_H
+#ifndef _ASM_X86_AMD_NB_H
+#define _ASM_X86_AMD_NB_H
 
 #include <linux/pci.h>
 
@@ -7,24 +7,27 @@ extern struct pci_device_id k8_nb_ids[];
 struct bootnode;
 
 extern int early_is_k8_nb(u32 value);
-extern struct pci_dev **k8_northbridges;
-extern int num_k8_northbridges;
 extern int cache_k8_northbridges(void);
 extern void k8_flush_garts(void);
 extern int k8_get_nodes(struct bootnode *nodes);
 extern int k8_numa_init(unsigned long start_pfn, unsigned long end_pfn);
 extern int k8_scan_nodes(void);
 
-#ifdef CONFIG_K8_NB
-extern int num_k8_northbridges;
+struct k8_northbridge_info {
+       u16 num;
+       u8 gart_supported;
+       struct pci_dev **nb_misc;
+};
+extern struct k8_northbridge_info k8_northbridges;
+
+#ifdef CONFIG_AMD_NB
 
 static inline struct pci_dev *node_to_k8_nb_misc(int node)
 {
-       return (node < num_k8_northbridges) ? k8_northbridges[node] : NULL;
+       return (node < k8_northbridges.num) ? k8_northbridges.nb_misc[node] : NULL;
 }
 
 #else
-#define num_k8_northbridges 0
 
 static inline struct pci_dev *node_to_k8_nb_misc(int node)
 {
@@ -33,4 +36,4 @@ static inline struct pci_dev *node_to_k8_nb_misc(int node)
 #endif
 
 
-#endif /* _ASM_X86_K8_H */
+#endif /* _ASM_X86_AMD_NB_H */
index a69b1ac9eaf82d639fd0ae51459d2dfdc79fbd1b..2fefa501d3ba64ee5db2e3541555a28ebe27598e 100644 (file)
@@ -54,7 +54,6 @@ extern struct clock_event_device *global_clock_event;
 extern unsigned long apbt_quick_calibrate(void);
 extern int arch_setup_apbt_irqs(int irq, int trigger, int mask, int cpu);
 extern void apbt_setup_secondary_clock(void);
-extern unsigned int boot_cpu_id;
 
 extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint);
 extern void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr);
index 1fa03e04ae4475e9bdc342aa117d9048a4e93105..286de34b0ed6773c6ccb2b7b052023394b93396f 100644 (file)
@@ -252,9 +252,7 @@ static inline int apic_is_clustered_box(void)
 }
 #endif
 
-extern u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask);
-extern u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask);
-
+extern int setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask);
 
 #else /* !CONFIG_X86_LOCAL_APIC */
 static inline void lapic_shutdown(void) { }
index 7fe3b3060f08cc8e57f18d3e4ff04519f358d00e..a859ca461fb0432585f952e08337610b1165a204 100644 (file)
 #define APIC_EILVTn(n) (0x500 + 0x10 * n)
 #define                APIC_EILVT_NR_AMD_K8    1       /* # of extended interrupts */
 #define                APIC_EILVT_NR_AMD_10H   4
+#define                APIC_EILVT_NR_MAX       APIC_EILVT_NR_AMD_10H
 #define                APIC_EILVT_LVTOFF(x)    (((x) >> 4) & 0xF)
 #define                APIC_EILVT_MSG_FIX      0x0
 #define                APIC_EILVT_MSG_SMI      0x2
index 0918654305af5975bdef505fe7c3003cbc49ef73..0d467b33883544121860305ab7bb7459b98112eb 100644 (file)
@@ -62,9 +62,9 @@ struct cal_chipset_ops {
 extern int use_calgary;
 
 #ifdef CONFIG_CALGARY_IOMMU
-extern void detect_calgary(void);
+extern int detect_calgary(void);
 #else
-static inline void detect_calgary(void) { return; }
+static inline int detect_calgary(void) { return -ENODEV; }
 #endif
 
 #endif /* _ASM_X86_CALGARY_H */
index b185091bf19ce39f67a325ecd6aafb7c13f8cd23..4fab24de26b18404069994b908c79d3e4e481c50 100644 (file)
@@ -32,6 +32,5 @@ extern void arch_unregister_cpu(int);
 
 DECLARE_PER_CPU(int, cpu_state);
 
-extern unsigned int boot_cpu_id;
 
 #endif /* _ASM_X86_CPU_H */
index 3f76523589afa8b9f30abcb6841962b6344d603e..220e2ea08e80b3b2f40b33771913c4d80e2d815e 100644 (file)
 #define X86_FEATURE_3DNOWPREFETCH (6*32+ 8) /* 3DNow prefetch instructions */
 #define X86_FEATURE_OSVW       (6*32+ 9) /* OS Visible Workaround */
 #define X86_FEATURE_IBS                (6*32+10) /* Instruction Based Sampling */
-#define X86_FEATURE_SSE5       (6*32+11) /* SSE-5 */
+#define X86_FEATURE_XOP                (6*32+11) /* extended AVX instructions */
 #define X86_FEATURE_SKINIT     (6*32+12) /* SKINIT/STGI instructions */
 #define X86_FEATURE_WDT                (6*32+13) /* Watchdog timer */
+#define X86_FEATURE_LWP                (6*32+15) /* Light Weight Profiling */
+#define X86_FEATURE_FMA4       (6*32+16) /* 4 operands MAC instructions */
 #define X86_FEATURE_NODEID_MSR (6*32+19) /* NodeId MSR */
+#define X86_FEATURE_TBM                (6*32+21) /* trailing bit manipulations */
+#define X86_FEATURE_TOPOEXT    (6*32+22) /* topology extensions CPUID leafs */
 
 /*
  * Auxiliary flags: Linux defined - For features scattered in various
 #define X86_FEATURE_LBRV       (8*32+ 6) /* AMD LBR Virtualization support */
 #define X86_FEATURE_SVML       (8*32+ 7) /* "svm_lock" AMD SVM locking MSR */
 #define X86_FEATURE_NRIPS      (8*32+ 8) /* "nrip_save" AMD SVM next_rip save */
+#define X86_FEATURE_TSCRATEMSR  (8*32+ 9) /* "tsc_scale" AMD TSC scaling support */
+#define X86_FEATURE_VMCBCLEAN   (8*32+10) /* "vmcb_clean" AMD VMCB clean bits support */
+#define X86_FEATURE_FLUSHBYASID (8*32+11) /* AMD flush-by-ASID support */
+#define X86_FEATURE_DECODEASSISTS (8*32+12) /* AMD Decode Assists support */
+#define X86_FEATURE_PAUSEFILTER (8*32+13) /* AMD filtered pause intercept */
+#define X86_FEATURE_PFTHRESHOLD (8*32+14) /* AMD pause filter threshold */
+
 
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
 #define X86_FEATURE_FSGSBASE   (9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
index 733f7e91e7a99f45435a6b46c831ff3e6e9c05da..326099199318c4ce1066a03a04220c08914ca890 100644 (file)
        CFI_ADJUST_CFA_OFFSET -8
        .endm
 
+       .macro pushfq_cfi
+       pushfq
+       CFI_ADJUST_CFA_OFFSET 8
+       .endm
+
+       .macro popfq_cfi
+       popfq
+       CFI_ADJUST_CFA_OFFSET -8
+       .endm
+
        .macro movq_cfi reg offset=0
        movq %\reg, \offset(%rsp)
        CFI_REL_OFFSET \reg, \offset
        CFI_ADJUST_CFA_OFFSET -4
        .endm
 
+       .macro pushfl_cfi
+       pushfl
+       CFI_ADJUST_CFA_OFFSET 4
+       .endm
+
+       .macro popfl_cfi
+       popfl
+       CFI_ADJUST_CFA_OFFSET -4
+       .endm
+
        .macro movl_cfi reg offset=0
        movl %\reg, \offset(%esp)
        CFI_REL_OFFSET \reg, \offset
index ec8a52d14ab179e4ef086e9c65c5a28917cdfd70..5be1542fbfaf73bfccd03a101e94a1cca47d36b0 100644 (file)
@@ -112,23 +112,13 @@ static inline void early_memtest(unsigned long start, unsigned long end)
 }
 #endif
 
-extern unsigned long end_user_pfn;
-
-extern u64 find_e820_area(u64 start, u64 end, u64 size, u64 align);
-extern u64 find_e820_area_size(u64 start, u64 *sizep, u64 align);
-extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);
-#include <linux/early_res.h>
-
 extern unsigned long e820_end_of_ram_pfn(void);
 extern unsigned long e820_end_of_low_ram_pfn(void);
-extern int e820_find_active_region(const struct e820entry *ei,
-                                 unsigned long start_pfn,
-                                 unsigned long last_pfn,
-                                 unsigned long *ei_startpfn,
-                                 unsigned long *ei_endpfn);
-extern void e820_register_active_regions(int nid, unsigned long start_pfn,
-                                        unsigned long end_pfn);
-extern u64 e820_hole_size(u64 start, u64 end);
+extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align);
+
+void memblock_x86_fill(void);
+void memblock_find_dma_reserve(void);
+
 extern void finish_e820_parsing(void);
 extern void e820_reserve_resources(void);
 extern void e820_reserve_resources_late(void);
index 8406ed7f99269f97c469bc9b03e0cb8d00276f84..8e4a16508d4e89641919cd39979c14532459af96 100644 (file)
@@ -90,7 +90,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
 #endif /* CONFIG_X86_32 */
 
 extern int add_efi_memmap;
-extern void efi_reserve_early(void);
+extern void efi_memblock_x86_reserve_range(void);
 extern void efi_call_phys_prelog(void);
 extern void efi_call_phys_epilog(void);
 
index 8e8ec663a98fab4b771123fa1bfd6f7aef2f5931..b8e96a18676b872e751c4635921fb479f615c74e 100644 (file)
@@ -49,8 +49,8 @@ BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)
 BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR)
 BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR)
 
-#ifdef CONFIG_PERF_EVENTS
-BUILD_INTERRUPT(perf_pending_interrupt, LOCAL_PENDING_VECTOR)
+#ifdef CONFIG_IRQ_WORK
+BUILD_INTERRUPT(irq_work_interrupt, IRQ_WORK_VECTOR)
 #endif
 
 #ifdef CONFIG_X86_THERMAL_VECTOR
index d07b44f7d1dc014b3d1cb77e49138ef5f97f5d24..4d293dced62f4c178cd19e6cb2eae882678afb33 100644 (file)
@@ -214,5 +214,20 @@ static inline unsigned long virt_to_fix(const unsigned long vaddr)
        BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
        return __virt_to_fix(vaddr);
 }
+
+/* Return an pointer with offset calculated */
+static inline unsigned long __set_fixmap_offset(enum fixed_addresses idx,
+                               phys_addr_t phys, pgprot_t flags)
+{
+       __set_fixmap(idx, phys, flags);
+       return fix_to_virt(idx) + (phys & (PAGE_SIZE - 1));
+}
+
+#define set_fixmap_offset(idx, phys)                   \
+       __set_fixmap_offset(idx, phys, PAGE_KERNEL)
+
+#define set_fixmap_offset_nocache(idx, phys)                   \
+       __set_fixmap_offset(idx, phys, PAGE_KERNEL_NOCACHE)
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASM_X86_FIXMAP_H */
index 4ac5b0f33fc1017b3760eb01b1a4ed7f7155dbce..43085bfc99c30f963b929a9c7afdcff932ad9236 100644 (file)
@@ -17,6 +17,7 @@ extern int fix_aperture;
 #define GARTEN         (1<<0)
 #define DISGARTCPU     (1<<4)
 #define DISGARTIO      (1<<5)
+#define DISTLBWALKPRB  (1<<6)
 
 /* GART cache control register bits. */
 #define INVGART                (1<<0)
@@ -27,7 +28,6 @@ extern int fix_aperture;
 #define AMD64_GARTAPERTUREBASE 0x94
 #define AMD64_GARTTABLEBASE    0x98
 #define AMD64_GARTCACHECTL     0x9c
-#define AMD64_GARTEN           (1<<0)
 
 #ifdef CONFIG_GART_IOMMU
 extern int gart_iommu_aperture;
@@ -37,7 +37,7 @@ extern int gart_iommu_aperture_disabled;
 extern void early_gart_iommu_check(void);
 extern int gart_iommu_init(void);
 extern void __init gart_parse_options(char *);
-extern void gart_iommu_hole_init(void);
+extern int gart_iommu_hole_init(void);
 
 #else
 #define gart_iommu_aperture            0
@@ -50,13 +50,27 @@ static inline void early_gart_iommu_check(void)
 static inline void gart_parse_options(char *options)
 {
 }
-static inline void gart_iommu_hole_init(void)
+static inline int gart_iommu_hole_init(void)
 {
+       return -ENODEV;
 }
 #endif
 
 extern int agp_amd64_init(void);
 
+static inline void gart_set_size_and_enable(struct pci_dev *dev, u32 order)
+{
+       u32 ctl;
+
+       /*
+        * Don't enable translation but enable GART IO and CPU accesses.
+        * Also, set DISTLBWALKPRB since GART tables memory is UC.
+        */
+       ctl = DISTLBWALKPRB | order << 1;
+
+       pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, ctl);
+}
+
 static inline void enable_gart_translation(struct pci_dev *dev, u64 addr)
 {
        u32 tmp, ctl;
index aeab29aee617240fbf479d2945572879be4525ec..55e4de613f0ee72471fd3cfaf28dee21150b276c 100644 (file)
@@ -14,7 +14,7 @@ typedef struct {
 #endif
        unsigned int x86_platform_ipis; /* arch dependent */
        unsigned int apic_perf_irqs;
-       unsigned int apic_pending_irqs;
+       unsigned int apic_irq_work_irqs;
 #ifdef CONFIG_SMP
        unsigned int irq_resched_count;
        unsigned int irq_call_count;
index 1d5c08a1bdfdb5b61c72cb286dfb0ac382c17e76..2c392d663dcee3f899d28c195b05fb92d63930cf 100644 (file)
@@ -74,10 +74,12 @@ extern void hpet_disable(void);
 extern unsigned int hpet_readl(unsigned int a);
 extern void force_hpet_resume(void);
 
-extern void hpet_msi_unmask(unsigned int irq);
-extern void hpet_msi_mask(unsigned int irq);
-extern void hpet_msi_write(unsigned int irq, struct msi_msg *msg);
-extern void hpet_msi_read(unsigned int irq, struct msi_msg *msg);
+struct irq_data;
+extern void hpet_msi_unmask(struct irq_data *data);
+extern void hpet_msi_mask(struct irq_data *data);
+struct hpet_dev;
+extern void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg);
+extern void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg);
 
 #ifdef CONFIG_PCI_MSI
 extern int arch_setup_hpet_msi(unsigned int irq, unsigned int id);
index 46c0fe05f230112b5aa5e176d4292e56526f8279..0274ec5a7e6285c18bbdd9908bc04d4b829fd9cc 100644 (file)
@@ -29,7 +29,7 @@
 extern void apic_timer_interrupt(void);
 extern void x86_platform_ipi(void);
 extern void error_interrupt(void);
-extern void perf_pending_interrupt(void);
+extern void irq_work_interrupt(void);
 
 extern void spurious_interrupt(void);
 extern void thermal_interrupt(void);
@@ -78,6 +78,13 @@ static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
        irq_attr->polarity      = polarity;
 }
 
+struct irq_2_iommu {
+       struct intel_iommu *iommu;
+       u16 irte_index;
+       u16 sub_handle;
+       u8  irte_mask;
+};
+
 /*
  * This is performance-critical, we want to do it O(1)
  *
@@ -89,15 +96,17 @@ struct irq_cfg {
        cpumask_var_t           old_domain;
        u8                      vector;
        u8                      move_in_progress : 1;
+#ifdef CONFIG_INTR_REMAP
+       struct irq_2_iommu      irq_2_iommu;
+#endif
 };
 
-extern struct irq_cfg *irq_cfg(unsigned int);
 extern int assign_irq_vector(int, struct irq_cfg *, const struct cpumask *);
 extern void send_cleanup_vector(struct irq_cfg *);
 
-struct irq_desc;
-extern unsigned int set_desc_affinity(struct irq_desc *, const struct cpumask *,
-                                     unsigned int *dest_id);
+struct irq_data;
+int __ioapic_set_affinity(struct irq_data *, const struct cpumask *,
+                         unsigned int *dest_id);
 extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin, struct io_apic_irq_attr *irq_attr);
 extern void setup_ioapic_dest(void);
 
index a73a8d5a5e6963e6fef9b52c28666e913a74160c..4aa2bb3b242ab76733e0f7e5ba95454471297c1a 100644 (file)
@@ -55,6 +55,12 @@ extern int save_i387_xstate_ia32(void __user *buf);
 extern int restore_i387_xstate_ia32(void __user *buf);
 #endif
 
+#ifdef CONFIG_MATH_EMULATION
+extern void finit_soft_fpu(struct i387_soft_struct *soft);
+#else
+static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
+#endif
+
 #define X87_FSW_ES (1 << 7)    /* Exception Summary */
 
 static __always_inline __pure bool use_xsaveopt(void)
@@ -67,6 +73,11 @@ static __always_inline __pure bool use_xsave(void)
        return static_cpu_has(X86_FEATURE_XSAVE);
 }
 
+static __always_inline __pure bool use_fxsr(void)
+{
+        return static_cpu_has(X86_FEATURE_FXSR);
+}
+
 extern void __sanitize_i387_state(struct task_struct *);
 
 static inline void sanitize_i387_state(struct task_struct *tsk)
@@ -77,19 +88,11 @@ static inline void sanitize_i387_state(struct task_struct *tsk)
 }
 
 #ifdef CONFIG_X86_64
-
-/* Ignore delayed exceptions from user space */
-static inline void tolerant_fwait(void)
-{
-       asm volatile("1: fwait\n"
-                    "2:\n"
-                    _ASM_EXTABLE(1b, 2b));
-}
-
 static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
 {
        int err;
 
+       /* See comment in fxsave() below. */
        asm volatile("1:  rex64/fxrstor (%[fx])\n\t"
                     "2:\n"
                     ".section .fixup,\"ax\"\n"
@@ -98,44 +101,10 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
                     ".previous\n"
                     _ASM_EXTABLE(1b, 3b)
                     : [err] "=r" (err)
-#if 0 /* See comment in fxsave() below. */
-                    : [fx] "r" (fx), "m" (*fx), "0" (0));
-#else
-                    : [fx] "cdaSDb" (fx), "m" (*fx), "0" (0));
-#endif
+                    : [fx] "R" (fx), "m" (*fx), "0" (0));
        return err;
 }
 
-/* AMD CPUs don't save/restore FDP/FIP/FOP unless an exception
-   is pending. Clear the x87 state here by setting it to fixed
-   values. The kernel data segment can be sometimes 0 and sometimes
-   new user value. Both should be ok.
-   Use the PDA as safe address because it should be already in L1. */
-static inline void fpu_clear(struct fpu *fpu)
-{
-       struct xsave_struct *xstate = &fpu->state->xsave;
-       struct i387_fxsave_struct *fx = &fpu->state->fxsave;
-
-       /*
-        * xsave header may indicate the init state of the FP.
-        */
-       if (use_xsave() &&
-           !(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
-               return;
-
-       if (unlikely(fx->swd & X87_FSW_ES))
-               asm volatile("fnclex");
-       alternative_input(ASM_NOP8 ASM_NOP2,
-                         "    emms\n"          /* clear stack tags */
-                         "    fildl %%gs:0",   /* load to clear state */
-                         X86_FEATURE_FXSAVE_LEAK);
-}
-
-static inline void clear_fpu_state(struct task_struct *tsk)
-{
-       fpu_clear(&tsk->thread.fpu);
-}
-
 static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
 {
        int err;
@@ -149,6 +118,7 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
        if (unlikely(err))
                return -EFAULT;
 
+       /* See comment in fxsave() below. */
        asm volatile("1:  rex64/fxsave (%[fx])\n\t"
                     "2:\n"
                     ".section .fixup,\"ax\"\n"
@@ -157,11 +127,7 @@ static inline int fxsave_user(struct i387_fxsave_struct __user *fx)
                     ".previous\n"
                     _ASM_EXTABLE(1b, 3b)
                     : [err] "=r" (err), "=m" (*fx)
-#if 0 /* See comment in fxsave() below. */
-                    : [fx] "r" (fx), "0" (0));
-#else
-                    : [fx] "cdaSDb" (fx), "0" (0));
-#endif
+                    : [fx] "R" (fx), "0" (0));
        if (unlikely(err) &&
            __clear_user(fx, sizeof(struct i387_fxsave_struct)))
                err = -EFAULT;
@@ -175,56 +141,29 @@ static inline void fpu_fxsave(struct fpu *fpu)
           uses any extended registers for addressing, a second REX prefix
           will be generated (to the assembler, rex64 followed by semicolon
           is a separate instruction), and hence the 64-bitness is lost. */
-#if 0
+
+#ifdef CONFIG_AS_FXSAVEQ
        /* Using "fxsaveq %0" would be the ideal choice, but is only supported
           starting with gas 2.16. */
        __asm__ __volatile__("fxsaveq %0"
                             : "=m" (fpu->state->fxsave));
-#elif 0
+#else
        /* Using, as a workaround, the properly prefixed form below isn't
           accepted by any binutils version so far released, complaining that
           the same type of prefix is used twice if an extended register is
-          needed for addressing (fix submitted to mainline 2005-11-21). */
-       __asm__ __volatile__("rex64/fxsave %0"
-                            : "=m" (fpu->state->fxsave));
-#else
-       /* This, however, we can work around by forcing the compiler to select
+          needed for addressing (fix submitted to mainline 2005-11-21).
+       asm volatile("rex64/fxsave %0"
+                    : "=m" (fpu->state->fxsave));
+          This, however, we can work around by forcing the compiler to select
           an addressing mode that doesn't require extended registers. */
-       __asm__ __volatile__("rex64/fxsave (%1)"
-                            : "=m" (fpu->state->fxsave)
-                            : "cdaSDb" (&fpu->state->fxsave));
+       asm volatile("rex64/fxsave (%[fx])"
+                    : "=m" (fpu->state->fxsave)
+                    : [fx] "R" (&fpu->state->fxsave));
 #endif
 }
 
-static inline void fpu_save_init(struct fpu *fpu)
-{
-       if (use_xsave())
-               fpu_xsave(fpu);
-       else
-               fpu_fxsave(fpu);
-
-       fpu_clear(fpu);
-}
-
-static inline void __save_init_fpu(struct task_struct *tsk)
-{
-       fpu_save_init(&tsk->thread.fpu);
-       task_thread_info(tsk)->status &= ~TS_USEDFPU;
-}
-
 #else  /* CONFIG_X86_32 */
 
-#ifdef CONFIG_MATH_EMULATION
-extern void finit_soft_fpu(struct i387_soft_struct *soft);
-#else
-static inline void finit_soft_fpu(struct i387_soft_struct *soft) {}
-#endif
-
-static inline void tolerant_fwait(void)
-{
-       asm volatile("fnclex ; fwait");
-}
-
 /* perform fxrstor iff the processor has extended states, otherwise frstor */
 static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
 {
@@ -241,6 +180,14 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
        return 0;
 }
 
+static inline void fpu_fxsave(struct fpu *fpu)
+{
+       asm volatile("fxsave %[fx]"
+                    : [fx] "=m" (fpu->state->fxsave));
+}
+
+#endif /* CONFIG_X86_64 */
+
 /* We need a safe address that is cheap to find and that is already
    in L1 during context switch. The best choices are unfortunately
    different for UP and SMP */
@@ -256,47 +203,33 @@ static inline int fxrstor_checking(struct i387_fxsave_struct *fx)
 static inline void fpu_save_init(struct fpu *fpu)
 {
        if (use_xsave()) {
-               struct xsave_struct *xstate = &fpu->state->xsave;
-               struct i387_fxsave_struct *fx = &fpu->state->fxsave;
-
                fpu_xsave(fpu);
 
                /*
                 * xsave header may indicate the init state of the FP.
                 */
-               if (!(xstate->xsave_hdr.xstate_bv & XSTATE_FP))
-                       goto end;
-
-               if (unlikely(fx->swd & X87_FSW_ES))
-                       asm volatile("fnclex");
-
-               /*
-                * we can do a simple return here or be paranoid :)
-                */
-               goto clear_state;
+               if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP))
+                       return;
+       } else if (use_fxsr()) {
+               fpu_fxsave(fpu);
+       } else {
+               asm volatile("fsave %[fx]; fwait"
+                            : [fx] "=m" (fpu->state->fsave));
+               return;
        }
 
-       /* Use more nops than strictly needed in case the compiler
-          varies code */
-       alternative_input(
-               "fnsave %[fx] ;fwait;" GENERIC_NOP8 GENERIC_NOP4,
-               "fxsave %[fx]\n"
-               "bt $7,%[fsw] ; jnc 1f ; fnclex\n1:",
-               X86_FEATURE_FXSR,
-               [fx] "m" (fpu->state->fxsave),
-               [fsw] "m" (fpu->state->fxsave.swd) : "memory");
-clear_state:
+       if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES))
+               asm volatile("fnclex");
+
        /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception
           is pending.  Clear the x87 state here by setting it to fixed
           values. safe_address is a random variable that should be in L1 */
        alternative_input(
-               GENERIC_NOP8 GENERIC_NOP2,
+               ASM_NOP8 ASM_NOP2,
                "emms\n\t"              /* clear stack tags */
-               "fildl %[addr]",        /* set F?P to defined value */
+               "fildl %P[addr]",       /* set F?P to defined value */
                X86_FEATURE_FXSAVE_LEAK,
                [addr] "m" (safe_address));
-end:
-       ;
 }
 
 static inline void __save_init_fpu(struct task_struct *tsk)
@@ -305,9 +238,6 @@ static inline void __save_init_fpu(struct task_struct *tsk)
        task_thread_info(tsk)->status &= ~TS_USEDFPU;
 }
 
-
-#endif /* CONFIG_X86_64 */
-
 static inline int fpu_fxrstor_checking(struct fpu *fpu)
 {
        return fxrstor_checking(&fpu->state->fxsave);
@@ -344,7 +274,10 @@ static inline void __unlazy_fpu(struct task_struct *tsk)
 static inline void __clear_fpu(struct task_struct *tsk)
 {
        if (task_thread_info(tsk)->status & TS_USEDFPU) {
-               tolerant_fwait();
+               /* Ignore delayed exceptions from user space */
+               asm volatile("1: fwait\n"
+                            "2:\n"
+                            _ASM_EXTABLE(1b, 2b));
                task_thread_info(tsk)->status &= ~TS_USEDFPU;
                stts();
        }
@@ -405,19 +338,6 @@ static inline void irq_ts_restore(int TS_state)
                stts();
 }
 
-#ifdef CONFIG_X86_64
-
-static inline void save_init_fpu(struct task_struct *tsk)
-{
-       __save_init_fpu(tsk);
-       stts();
-}
-
-#define unlazy_fpu     __unlazy_fpu
-#define clear_fpu      __clear_fpu
-
-#else  /* CONFIG_X86_32 */
-
 /*
  * These disable preemption on their own and are safe
  */
@@ -443,8 +363,6 @@ static inline void clear_fpu(struct task_struct *tsk)
        preempt_enable();
 }
 
-#endif /* CONFIG_X86_64 */
-
 /*
  * i387 state interaction
  */
@@ -508,7 +426,4 @@ extern void fpu_finit(struct fpu *fpu);
 
 #endif /* __ASSEMBLY__ */
 
-#define PSHUFB_XMM5_XMM0 .byte 0x66, 0x0f, 0x38, 0x00, 0xc5
-#define PSHUFB_XMM5_XMM6 .byte 0x66, 0x0f, 0x38, 0x00, 0xf5
-
 #endif /* _ASM_X86_I387_H */
index 1655147646aa61e820ef38c76546e07a5c149e2e..a20365953bf8a7727285029f3c6d84ba56f941a0 100644 (file)
@@ -55,6 +55,8 @@ extern struct irq_chip i8259A_chip;
 struct legacy_pic {
        int nr_legacy_irqs;
        struct irq_chip *chip;
+       void (*mask)(unsigned int irq);
+       void (*unmask)(unsigned int irq);
        void (*mask_all)(void);
        void (*restore_mask)(void);
        void (*init)(int auto_eoi);
index 30a3e977612306033c9647487dde3298b31a4f73..f0203f4791a8924a94a31d92fe78c298c3f3dd64 100644 (file)
@@ -206,6 +206,7 @@ static inline void __iomem *ioremap(resource_size_t offset, unsigned long size)
 
 extern void iounmap(volatile void __iomem *addr);
 
+extern void set_iounmap_nonlazy(void);
 
 #ifdef __KERNEL__
 
@@ -348,6 +349,7 @@ extern void __iomem *early_memremap(resource_size_t phys_addr,
                                    unsigned long size);
 extern void early_iounmap(void __iomem *addr, unsigned long size);
 extern void fixup_early_ioremap(void);
+extern bool is_early_ioremap_ptep(pte_t *ptep);
 
 #define IO_SPACE_LIMIT 0xffff
 
index 9cb2edb87c2f718780fb00cc61ebc1bfa5ad0228..c8be4566c3d28143af7d7868eeee0801dae0a5cf 100644 (file)
@@ -170,12 +170,6 @@ extern int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
 
 extern void probe_nr_irqs_gsi(void);
 
-extern int setup_ioapic_entry(int apic, int irq,
-                             struct IO_APIC_route_entry *entry,
-                             unsigned int destination, int trigger,
-                             int polarity, int vector, int pin);
-extern void ioapic_write_entry(int apic, int pin,
-                              struct IO_APIC_route_entry e);
 extern void setup_ioapic_ids_from_mpc(void);
 
 struct mp_ioapic_gsi{
diff --git a/arch/x86/include/asm/iommu_table.h b/arch/x86/include/asm/iommu_table.h
new file mode 100644 (file)
index 0000000..f229b13
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef _ASM_X86_IOMMU_TABLE_H
+#define _ASM_X86_IOMMU_TABLE_H
+
+#include <asm/swiotlb.h>
+
+/*
+ * History lesson:
+ * The execution chain of IOMMUs in 2.6.36 looks as so:
+ *
+ *            [xen-swiotlb]
+ *                 |
+ *         +----[swiotlb *]--+
+ *        /         |         \
+ *       /          |          \
+ *    [GART]     [Calgary]  [Intel VT-d]
+ *     /
+ *    /
+ * [AMD-Vi]
+ *
+ * *: if SWIOTLB detected 'iommu=soft'/'swiotlb=force' it would skip
+ * over the rest of IOMMUs and unconditionally initialize the SWIOTLB.
+ * Also it would surreptitiously initialize set the swiotlb=1 if there were
+ * more than 4GB and if the user did not pass in 'iommu=off'. The swiotlb
+ * flag would be turned off by all IOMMUs except the Calgary one.
+ *
+ * The IOMMU_INIT* macros allow a similar tree (or more complex if desired)
+ * to be built by defining who we depend on.
+ *
+ * And all that needs to be done is to use one of the macros in the IOMMU
+ * and the pci-dma.c will take care of the rest.
+ */
+
+struct iommu_table_entry {
+       initcall_t      detect;
+       initcall_t      depend;
+       void            (*early_init)(void); /* No memory allocate available. */
+       void            (*late_init)(void); /* Yes, can allocate memory. */
+#define IOMMU_FINISH_IF_DETECTED (1<<0)
+#define IOMMU_DETECTED          (1<<1)
+       int             flags;
+};
+/*
+ * Macro fills out an entry in the .iommu_table that is equivalent
+ * to the fields that 'struct iommu_table_entry' has. The entries
+ * that are put in the .iommu_table section are not put in any order
+ * hence during boot-time we will have to resort them based on
+ * dependency. */
+
+
+#define __IOMMU_INIT(_detect, _depend, _early_init, _late_init, _finish)\
+       static const struct iommu_table_entry const                     \
+               __iommu_entry_##_detect __used                          \
+       __attribute__ ((unused, __section__(".iommu_table"),            \
+                       aligned((sizeof(void *)))))     \
+       = {_detect, _depend, _early_init, _late_init,                   \
+          _finish ? IOMMU_FINISH_IF_DETECTED : 0}
+/*
+ * The simplest IOMMU definition. Provide the detection routine
+ * and it will be run after the SWIOTLB and the other IOMMUs
+ * that utilize this macro. If the IOMMU is detected (ie, the
+ * detect routine returns a positive value), the other IOMMUs
+ * are also checked. You can use IOMMU_INIT_POST_FINISH if you prefer
+ * to stop detecting the other IOMMUs after yours has been detected.
+ */
+#define IOMMU_INIT_POST(_detect)                                       \
+       __IOMMU_INIT(_detect, pci_swiotlb_detect_4gb,  0, 0, 0)
+
+#define IOMMU_INIT_POST_FINISH(detect)                                 \
+       __IOMMU_INIT(_detect, pci_swiotlb_detect_4gb,  0, 0, 1)
+
+/*
+ * A more sophisticated version of IOMMU_INIT. This variant requires:
+ *  a). A detection routine function.
+ *  b). The name of the detection routine we depend on to get called
+ *      before us.
+ *  c). The init routine which gets called if the detection routine
+ *      returns a positive value from the pci_iommu_alloc. This means
+ *      no presence of a memory allocator.
+ *  d). Similar to the 'init', except that this gets called from pci_iommu_init
+ *      where we do have a memory allocator.
+ *
+ * The standard vs the _FINISH differs in that the _FINISH variant will
+ * continue detecting other IOMMUs in the call list after the
+ * the detection routine returns a positive number. The _FINISH will
+ * stop the execution chain. Both will still call the 'init' and
+ * 'late_init' functions if they are set.
+ */
+#define IOMMU_INIT_FINISH(_detect, _depend, _init, _late_init)         \
+       __IOMMU_INIT(_detect, _depend, _init, _late_init, 1)
+
+#define IOMMU_INIT(_detect, _depend, _init, _late_init)                        \
+       __IOMMU_INIT(_detect, _depend, _init, _late_init, 0)
+
+void sort_iommu_table(struct iommu_table_entry *start,
+                     struct iommu_table_entry *finish);
+
+void check_iommu_entries(struct iommu_table_entry *start,
+                        struct iommu_table_entry *finish);
+
+#endif /* _ASM_X86_IOMMU_TABLE_H */
index f275e2244505b98308ca72e66e26c250d29c61a8..1c23360fb2d8effec9b2ffbba102c9b30b0f63c8 100644 (file)
@@ -3,4 +3,39 @@
 
 #define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8)
 
+#ifdef CONFIG_INTR_REMAP
+static inline void prepare_irte(struct irte *irte, int vector,
+                               unsigned int dest)
+{
+       memset(irte, 0, sizeof(*irte));
+
+       irte->present = 1;
+       irte->dst_mode = apic->irq_dest_mode;
+       /*
+        * Trigger mode in the IRTE will always be edge, and for IO-APIC, the
+        * actual level or edge trigger will be setup in the IO-APIC
+        * RTE. This will help simplify level triggered irq migration.
+        * For more details, see the comments (in io_apic.c) explainig IO-APIC
+        * irq migration in the presence of interrupt-remapping.
+       */
+       irte->trigger_mode = 0;
+       irte->dlvry_mode = apic->irq_delivery_mode;
+       irte->vector = vector;
+       irte->dest_id = IRTE_DEST(dest);
+       irte->redir_hint = 1;
+}
+static inline bool irq_remapped(struct irq_cfg *cfg)
+{
+       return cfg->irq_2_iommu.iommu != NULL;
+}
+#else
+static void prepare_irte(struct irte *irte, int vector, unsigned int dest)
+{
+}
+static inline bool irq_remapped(struct irq_cfg *cfg)
+{
+       return false;
+}
+#endif
+
 #endif /* _ASM_X86_IRQ_REMAPPING_H */
index e2ca3009255706910d1ddc407232f4d09f011f24..6af0894dafb445cdaedceb1630249c47e955633f 100644 (file)
 #define X86_PLATFORM_IPI_VECTOR                0xed
 
 /*
- * Performance monitoring pending work vector:
+ * IRQ work vector:
  */
-#define LOCAL_PENDING_VECTOR           0xec
+#define IRQ_WORK_VECTOR                        0xec
 
 #define UV_BAU_MESSAGE                 0xea
 
index 9e2b952f810a601d16125dcfb1c2764d914d960c..5745ce8bf1089cd2399415641d1a0c25f39cf6c1 100644 (file)
@@ -61,22 +61,22 @@ static inline void native_halt(void)
 #else
 #ifndef __ASSEMBLY__
 
-static inline unsigned long __raw_local_save_flags(void)
+static inline unsigned long arch_local_save_flags(void)
 {
        return native_save_fl();
 }
 
-static inline void raw_local_irq_restore(unsigned long flags)
+static inline void arch_local_irq_restore(unsigned long flags)
 {
        native_restore_fl(flags);
 }
 
-static inline void raw_local_irq_disable(void)
+static inline void arch_local_irq_disable(void)
 {
        native_irq_disable();
 }
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_enable(void)
 {
        native_irq_enable();
 }
@@ -85,7 +85,7 @@ static inline void raw_local_irq_enable(void)
  * Used in the idle loop; sti takes one instruction cycle
  * to complete:
  */
-static inline void raw_safe_halt(void)
+static inline void arch_safe_halt(void)
 {
        native_safe_halt();
 }
@@ -102,12 +102,10 @@ static inline void halt(void)
 /*
  * For spinlocks, etc:
  */
-static inline unsigned long __raw_local_irq_save(void)
+static inline unsigned long arch_local_irq_save(void)
 {
-       unsigned long flags = __raw_local_save_flags();
-
-       raw_local_irq_disable();
-
+       unsigned long flags = arch_local_save_flags();
+       arch_local_irq_disable();
        return flags;
 }
 #else
@@ -153,22 +151,16 @@ static inline unsigned long __raw_local_irq_save(void)
 #endif /* CONFIG_PARAVIRT */
 
 #ifndef __ASSEMBLY__
-#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)
-
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+static inline int arch_irqs_disabled_flags(unsigned long flags)
 {
        return !(flags & X86_EFLAGS_IF);
 }
 
-static inline int raw_irqs_disabled(void)
+static inline int arch_irqs_disabled(void)
 {
-       unsigned long flags = __raw_local_save_flags();
+       unsigned long flags = arch_local_save_flags();
 
-       return raw_irqs_disabled_flags(flags);
+       return arch_irqs_disabled_flags(flags);
 }
 
 #else
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
new file mode 100644 (file)
index 0000000..f52d42e
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _ASM_X86_JUMP_LABEL_H
+#define _ASM_X86_JUMP_LABEL_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <asm/nops.h>
+
+#define JUMP_LABEL_NOP_SIZE 5
+
+# define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t"
+
+# define JUMP_LABEL(key, label)                                        \
+       do {                                                    \
+               asm goto("1:"                                   \
+                       JUMP_LABEL_INITIAL_NOP                  \
+                       ".pushsection __jump_table,  \"a\" \n\t"\
+                       _ASM_PTR "1b, %l[" #label "], %c0 \n\t" \
+                       ".popsection \n\t"                      \
+                       : :  "i" (key) :  : label);             \
+       } while (0)
+
+#endif /* __KERNEL__ */
+
+#ifdef CONFIG_X86_64
+typedef u64 jump_label_t;
+#else
+typedef u32 jump_label_t;
+#endif
+
+struct jump_entry {
+       jump_label_t code;
+       jump_label_t target;
+       jump_label_t key;
+};
+
+#endif
index 502e53f999cf28a25cc2b00f1766bd1ffb2f9ed2..c52e2eb40a1e254339658481621be634b427a8f0 100644 (file)
@@ -652,20 +652,6 @@ static inline struct kvm_mmu_page *page_header(hpa_t shadow_page)
        return (struct kvm_mmu_page *)page_private(page);
 }
 
-static inline u16 kvm_read_fs(void)
-{
-       u16 seg;
-       asm("mov %%fs, %0" : "=g"(seg));
-       return seg;
-}
-
-static inline u16 kvm_read_gs(void)
-{
-       u16 seg;
-       asm("mov %%gs, %0" : "=g"(seg));
-       return seg;
-}
-
 static inline u16 kvm_read_ldt(void)
 {
        u16 ldt;
@@ -673,16 +659,6 @@ static inline u16 kvm_read_ldt(void)
        return ldt;
 }
 
-static inline void kvm_load_fs(u16 sel)
-{
-       asm("mov %0, %%fs" : : "rm"(sel));
-}
-
-static inline void kvm_load_gs(u16 sel)
-{
-       asm("mov %0, %%gs" : : "rm"(sel));
-}
-
 static inline void kvm_load_ldt(u16 sel)
 {
        asm("lldt %0" : : "rm"(sel));
diff --git a/arch/x86/include/asm/memblock.h b/arch/x86/include/asm/memblock.h
new file mode 100644 (file)
index 0000000..19ae14b
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _X86_MEMBLOCK_H
+#define _X86_MEMBLOCK_H
+
+#define ARCH_DISCARD_MEMBLOCK
+
+u64 memblock_x86_find_in_range_size(u64 start, u64 *sizep, u64 align);
+void memblock_x86_to_bootmem(u64 start, u64 end);
+
+void memblock_x86_reserve_range(u64 start, u64 end, char *name);
+void memblock_x86_free_range(u64 start, u64 end);
+struct range;
+int __get_free_all_memory_range(struct range **range, int nodeid,
+                        unsigned long start_pfn, unsigned long end_pfn);
+int get_free_all_memory_range(struct range **rangep, int nodeid);
+
+void memblock_x86_register_active_regions(int nid, unsigned long start_pfn,
+                                        unsigned long last_pfn);
+u64 memblock_x86_hole_size(u64 start, u64 end);
+u64 memblock_x86_find_in_range_node(int nid, u64 start, u64 end, u64 size, u64 align);
+u64 memblock_x86_free_memory_in_range(u64 addr, u64 limit);
+u64 memblock_x86_memory_in_range(u64 addr, u64 limit);
+
+#endif
index 16350740edf600436d4990fec8a5fc9ce62abafc..4a711a684b174435bd5aae838515a836101eb389 100644 (file)
@@ -10,6 +10,9 @@
  */
 #ifndef _ASM_X86_MRST_H
 #define _ASM_X86_MRST_H
+
+#include <linux/sfi.h>
+
 extern int pci_mrst_init(void);
 int __init sfi_parse_mrtc(struct sfi_table_header *table);
 
@@ -26,7 +29,7 @@ enum mrst_cpu_type {
 };
 
 extern enum mrst_cpu_type __mrst_cpu_chip;
-static enum mrst_cpu_type mrst_identify_cpu(void)
+static inline enum mrst_cpu_type mrst_identify_cpu(void)
 {
        return __mrst_cpu_chip;
 }
@@ -42,4 +45,9 @@ extern enum mrst_timer_options mrst_timer_options;
 #define SFI_MTMR_MAX_NUM 8
 #define SFI_MRTC_MAX   8
 
+extern struct console early_mrst_console;
+extern void mrst_early_console_init(void);
+
+extern struct console early_hsu_console;
+extern void hsu_early_console_init(void);
 #endif /* _ASM_X86_MRST_H */
index 986f7790fdb2880c4f9efda864a489a0edb83892..91ba8e6b630a74bf76c5fca502a3ca6fe2ef6569 100644 (file)
 #define MSR_AMD64_IBSDCLINAD           0xc0011038
 #define MSR_AMD64_IBSDCPHYSAD          0xc0011039
 #define MSR_AMD64_IBSCTL               0xc001103a
+#define MSR_AMD64_IBSBRTARGET          0xc001103b
 
 /* Fam 10h MSRs */
 #define MSR_FAM10H_MMIO_CONF_BASE      0xc0010058
diff --git a/arch/x86/include/asm/mwait.h b/arch/x86/include/asm/mwait.h
new file mode 100644 (file)
index 0000000..bcdff99
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _ASM_X86_MWAIT_H
+#define _ASM_X86_MWAIT_H
+
+#define MWAIT_SUBSTATE_MASK            0xf
+#define MWAIT_CSTATE_MASK              0xf
+#define MWAIT_SUBSTATE_SIZE            4
+#define MWAIT_MAX_NUM_CSTATES          8
+
+#define CPUID_MWAIT_LEAF               5
+#define CPUID5_ECX_EXTENSIONS_SUPPORTED 0x1
+#define CPUID5_ECX_INTERRUPT_BREAK     0x2
+
+#define MWAIT_ECX_INTERRUPT_BREAK      0x1
+
+#endif /* _ASM_X86_MWAIT_H */
index 08fde475cb3b38fcf75e2c41ba3f14ced47dc8a9..2a8478140bb38b205e32624b7bda5118c43e8133 100644 (file)
@@ -21,10 +21,14 @@ extern void olpc_ofw_detect(void);
 /* install OFW's pde permanently into the kernel's pgtable */
 extern void setup_olpc_ofw_pgd(void);
 
+/* check if OFW was detected during boot */
+extern bool olpc_ofw_present(void);
+
 #else /* !CONFIG_OLPC_OPENFIRMWARE */
 
 static inline void olpc_ofw_detect(void) { }
 static inline void setup_olpc_ofw_pgd(void) { }
+static inline bool olpc_ofw_present(void) { return false; }
 
 #endif /* !CONFIG_OLPC_OPENFIRMWARE */
 
index a667f24c72549e6c8171892fc6fbf63ac54006d0..1df66211fd1b53d4d6233cc1e481e88009622aab 100644 (file)
@@ -8,7 +8,7 @@
 #define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~(PAGE_SIZE-1))
 
-#define __PHYSICAL_MASK                ((phys_addr_t)(1ULL << __PHYSICAL_MASK_SHIFT) - 1)
+#define __PHYSICAL_MASK                ((phys_addr_t)((1ULL << __PHYSICAL_MASK_SHIFT) - 1))
 #define __VIRTUAL_MASK         ((1UL << __VIRTUAL_MASK_SHIFT) - 1)
 
 /* Cast PAGE_MASK to a signed type so that it is sign-extended if
index 5653f43d90e534670974735f5d4578afdb4fc900..18e3b8a8709f9def52af32b8f27b05afbdd7a4ae 100644 (file)
@@ -105,7 +105,7 @@ static inline void write_cr8(unsigned long x)
 }
 #endif
 
-static inline void raw_safe_halt(void)
+static inline void arch_safe_halt(void)
 {
        PVOP_VCALL0(pv_irq_ops.safe_halt);
 }
@@ -416,11 +416,6 @@ static inline void paravirt_alloc_pmd(struct mm_struct *mm, unsigned long pfn)
        PVOP_VCALL2(pv_mmu_ops.alloc_pmd, mm, pfn);
 }
 
-static inline void paravirt_alloc_pmd_clone(unsigned long pfn, unsigned long clonepfn,
-                                           unsigned long start, unsigned long count)
-{
-       PVOP_VCALL4(pv_mmu_ops.alloc_pmd_clone, pfn, clonepfn, start, count);
-}
 static inline void paravirt_release_pmd(unsigned long pfn)
 {
        PVOP_VCALL1(pv_mmu_ops.release_pmd, pfn);
@@ -829,32 +824,32 @@ static __always_inline void arch_spin_unlock(struct arch_spinlock *lock)
 #define __PV_IS_CALLEE_SAVE(func)                      \
        ((struct paravirt_callee_save) { func })
 
-static inline unsigned long __raw_local_save_flags(void)
+static inline unsigned long arch_local_save_flags(void)
 {
        return PVOP_CALLEE0(unsigned long, pv_irq_ops.save_fl);
 }
 
-static inline void raw_local_irq_restore(unsigned long f)
+static inline void arch_local_irq_restore(unsigned long f)
 {
        PVOP_VCALLEE1(pv_irq_ops.restore_fl, f);
 }
 
-static inline void raw_local_irq_disable(void)
+static inline void arch_local_irq_disable(void)
 {
        PVOP_VCALLEE0(pv_irq_ops.irq_disable);
 }
 
-static inline void raw_local_irq_enable(void)
+static inline void arch_local_irq_enable(void)
 {
        PVOP_VCALLEE0(pv_irq_ops.irq_enable);
 }
 
-static inline unsigned long __raw_local_irq_save(void)
+static inline unsigned long arch_local_irq_save(void)
 {
        unsigned long f;
 
-       f = __raw_local_save_flags();
-       raw_local_irq_disable();
+       f = arch_local_save_flags();
+       arch_local_irq_disable();
        return f;
 }
 
index db9ef55323417812190eafd454cff45e136aec29..b82bac975250e53ac53363c2a04b724a32ea9929 100644 (file)
@@ -255,7 +255,6 @@ struct pv_mmu_ops {
         */
        void (*alloc_pte)(struct mm_struct *mm, unsigned long pfn);
        void (*alloc_pmd)(struct mm_struct *mm, unsigned long pfn);
-       void (*alloc_pmd_clone)(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count);
        void (*alloc_pud)(struct mm_struct *mm, unsigned long pfn);
        void (*release_pte)(unsigned long pfn);
        void (*release_pmd)(unsigned long pfn);
index 6e742cc4251b49b2474830107da0378951c874be..550e26b1dbb3593f324910f0197402966ae91299 100644 (file)
@@ -111,17 +111,18 @@ union cpuid10_edx {
 #define X86_PMC_IDX_FIXED_BTS                          (X86_PMC_IDX_FIXED + 16)
 
 /* IbsFetchCtl bits/masks */
-#define IBS_FETCH_RAND_EN              (1ULL<<57)
-#define IBS_FETCH_VAL                  (1ULL<<49)
-#define IBS_FETCH_ENABLE               (1ULL<<48)
-#define IBS_FETCH_CNT                  0xFFFF0000ULL
-#define IBS_FETCH_MAX_CNT              0x0000FFFFULL
+#define IBS_FETCH_RAND_EN      (1ULL<<57)
+#define IBS_FETCH_VAL          (1ULL<<49)
+#define IBS_FETCH_ENABLE       (1ULL<<48)
+#define IBS_FETCH_CNT          0xFFFF0000ULL
+#define IBS_FETCH_MAX_CNT      0x0000FFFFULL
 
 /* IbsOpCtl bits */
-#define IBS_OP_CNT_CTL                 (1ULL<<19)
-#define IBS_OP_VAL                     (1ULL<<18)
-#define IBS_OP_ENABLE                  (1ULL<<17)
-#define IBS_OP_MAX_CNT                 0x0000FFFFULL
+#define IBS_OP_CNT_CTL         (1ULL<<19)
+#define IBS_OP_VAL             (1ULL<<18)
+#define IBS_OP_ENABLE          (1ULL<<17)
+#define IBS_OP_MAX_CNT         0x0000FFFFULL
+#define IBS_OP_MAX_CNT_EXT     0x007FFFFFULL   /* not a register bit mask */
 
 #ifdef CONFIG_PERF_EVENTS
 extern void init_hw_perf_events(void);
index def500776b16a3b63d34da569021722e4d82f18a..a70cd216be5d729db1f364340f911d632819f18d 100644 (file)
 #define P4_ESCR_EMASK(v)       ((v) << P4_ESCR_EVENTMASK_SHIFT)
 #define P4_ESCR_TAG(v)         ((v) << P4_ESCR_TAG_SHIFT)
 
-/* Non HT mask */
-#define P4_ESCR_MASK                   \
-       (P4_ESCR_EVENT_MASK     |       \
-       P4_ESCR_EVENTMASK_MASK  |       \
-       P4_ESCR_TAG_MASK        |       \
-       P4_ESCR_TAG_ENABLE      |       \
-       P4_ESCR_T0_OS           |       \
-       P4_ESCR_T0_USR)
-
-/* HT mask */
-#define P4_ESCR_MASK_HT                        \
-       (P4_ESCR_MASK | P4_ESCR_T1_OS | P4_ESCR_T1_USR)
-
 #define P4_CCCR_OVF                    0x80000000U
 #define P4_CCCR_CASCADE                        0x40000000U
 #define P4_CCCR_OVF_PMI_T0             0x04000000U
 #define P4_CCCR_THRESHOLD(v)           ((v) << P4_CCCR_THRESHOLD_SHIFT)
 #define P4_CCCR_ESEL(v)                        ((v) << P4_CCCR_ESCR_SELECT_SHIFT)
 
-/* Non HT mask */
-#define P4_CCCR_MASK                           \
-       (P4_CCCR_OVF                    |       \
-       P4_CCCR_CASCADE                 |       \
-       P4_CCCR_OVF_PMI_T0              |       \
-       P4_CCCR_FORCE_OVF               |       \
-       P4_CCCR_EDGE                    |       \
-       P4_CCCR_THRESHOLD_MASK          |       \
-       P4_CCCR_COMPLEMENT              |       \
-       P4_CCCR_COMPARE                 |       \
-       P4_CCCR_ESCR_SELECT_MASK        |       \
-       P4_CCCR_ENABLE)
-
-/* HT mask */
-#define P4_CCCR_MASK_HT                                \
-       (P4_CCCR_MASK | P4_CCCR_OVF_PMI_T1 | P4_CCCR_THREAD_ANY)
-
 #define P4_GEN_ESCR_EMASK(class, name, bit)    \
        class##__##name = ((1 << bit) << P4_ESCR_EVENTMASK_SHIFT)
 #define P4_ESCR_EMASK_BIT(class, name)         class##__##name
 #define P4_CONFIG_HT_SHIFT             63
 #define P4_CONFIG_HT                   (1ULL << P4_CONFIG_HT_SHIFT)
 
+/*
+ * The bits we allow to pass for RAW events
+ */
+#define P4_CONFIG_MASK_ESCR            \
+       P4_ESCR_EVENT_MASK      |       \
+       P4_ESCR_EVENTMASK_MASK  |       \
+       P4_ESCR_TAG_MASK        |       \
+       P4_ESCR_TAG_ENABLE
+
+#define P4_CONFIG_MASK_CCCR            \
+       P4_CCCR_EDGE            |       \
+       P4_CCCR_THRESHOLD_MASK  |       \
+       P4_CCCR_COMPLEMENT      |       \
+       P4_CCCR_COMPARE         |       \
+       P4_CCCR_THREAD_ANY      |       \
+       P4_CCCR_RESERVED
+
+/* some dangerous bits are reserved for kernel internals */
+#define P4_CONFIG_MASK                                   \
+       (p4_config_pack_escr(P4_CONFIG_MASK_ESCR))      | \
+       (p4_config_pack_cccr(P4_CONFIG_MASK_CCCR))
+
 static inline bool p4_is_event_cascaded(u64 config)
 {
        u32 cccr = p4_config_unpack_cccr(config);
index a34c785c5a63b88ecd9fb3f07ee26c8fd3b4a7df..ada823a13c7c9460a06e330e00de2456cab9e66f 100644 (file)
@@ -28,6 +28,8 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
 extern spinlock_t pgd_lock;
 extern struct list_head pgd_list;
 
+extern struct mm_struct *pgd_page_get_mm(struct page *page);
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else  /* !CONFIG_PARAVIRT */
@@ -603,6 +605,8 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm,
        pte_update(mm, addr, ptep);
 }
 
+#define flush_tlb_fix_spurious_fault(vma, address)
+
 /*
  * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
  *
index 076052cd62bef2d08af47a725ad3b187cd735be6..f96ac9bedf75db0ca247326ab580301832761d82 100644 (file)
@@ -102,6 +102,8 @@ static inline void native_pgd_clear(pgd_t *pgd)
        native_set_pgd(pgd, native_make_pgd(0));
 }
 
+extern void sync_global_pgds(unsigned long start, unsigned long end);
+
 /*
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
index 325b7bdbebaa9494b3e3e4c08a314aed72f88dc4..cae9c3cb95cf160e4e00f8c0b1c29fac298bb48f 100644 (file)
@@ -110,6 +110,8 @@ struct cpuinfo_x86 {
        u16                     phys_proc_id;
        /* Core id: */
        u16                     cpu_core_id;
+       /* Compute unit id */
+       u8                      compute_unit_id;
        /* Index into per_cpu list: */
        u16                     cpu_index;
 #endif
@@ -602,7 +604,7 @@ extern unsigned long                mmu_cr4_features;
 
 static inline void set_in_cr4(unsigned long mask)
 {
-       unsigned cr4;
+       unsigned long cr4;
 
        mmu_cr4_features |= mask;
        cr4 = read_cr4();
@@ -612,7 +614,7 @@ static inline void set_in_cr4(unsigned long mask)
 
 static inline void clear_in_cr4(unsigned long mask)
 {
-       unsigned cr4;
+       unsigned long cr4;
 
        mmu_cr4_features &= ~mask;
        cr4 = read_cr4();
@@ -764,29 +766,6 @@ extern unsigned long               idle_halt;
 extern unsigned long           idle_nomwait;
 extern bool                    c1e_detected;
 
-/*
- * on systems with caches, caches must be flashed as the absolute
- * last instruction before going into a suspended halt.  Otherwise,
- * dirty data can linger in the cache and become stale on resume,
- * leading to strange errors.
- *
- * perform a variety of operations to guarantee that the compiler
- * will not reorder instructions.  wbinvd itself is serializing
- * so the processor will not reorder.
- *
- * Systems without cache can just go into halt.
- */
-static inline void wbinvd_halt(void)
-{
-       mb();
-       /* check for clflush to determine if wbinvd is legal */
-       if (cpu_has_clflush)
-               asm volatile("cli; wbinvd; 1: hlt; jmp 1b" : : : "memory");
-       else
-               while (1)
-                       halt();
-}
-
 extern void enable_sep_cpu(void);
 extern int sysenter_setup(void);
 
index ef292c792d742cb35b1a48ac7f18f97a6546860c..d6763b139a844243b9fbb8dc620e633fe7b5825a 100644 (file)
@@ -93,6 +93,11 @@ void *extend_brk(size_t size, size_t align);
                        : : "i" (sz));                                  \
        }
 
+/* Helper for reserving space for arrays of things */
+#define RESERVE_BRK_ARRAY(type, name, entries)         \
+       type *name;                                     \
+       RESERVE_BRK(name, sizeof(type) * entries)
+
 #ifdef __i386__
 
 void __init i386_start_kernel(void);
index 8085277e1b8b62747f8d8e57dc1ce16d91214e8c..977f1761a25d51b25737d84436a3a80dd3f60810 100644 (file)
@@ -5,17 +5,26 @@
 
 #ifdef CONFIG_SWIOTLB
 extern int swiotlb;
-extern int __init pci_swiotlb_detect(void);
+extern int __init pci_swiotlb_detect_override(void);
+extern int __init pci_swiotlb_detect_4gb(void);
 extern void __init pci_swiotlb_init(void);
+extern void __init pci_swiotlb_late_init(void);
 #else
 #define swiotlb 0
-static inline int pci_swiotlb_detect(void)
+static inline int pci_swiotlb_detect_override(void)
+{
+       return 0;
+}
+static inline int pci_swiotlb_detect_4gb(void)
 {
        return 0;
 }
 static inline void pci_swiotlb_init(void)
 {
 }
+static inline void pci_swiotlb_late_init(void)
+{
+}
 #endif
 
 static inline void dma_mark_clean(void *addr, size_t size) {}
diff --git a/arch/x86/include/asm/vmi.h b/arch/x86/include/asm/vmi.h
deleted file mode 100644 (file)
index 61e08c0..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * VMI interface definition
- *
- * Copyright (C) 2005, VMware, 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, GOOD TITLE or
- * NON INFRINGEMENT.  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.
- *
- * Maintained by: Zachary Amsden zach@vmware.com
- *
- */
-#include <linux/types.h>
-
-/*
- *---------------------------------------------------------------------
- *
- *  VMI Option ROM API
- *
- *---------------------------------------------------------------------
- */
-#define VMI_SIGNATURE 0x696d5663   /* "cVmi" */
-
-#define PCI_VENDOR_ID_VMWARE            0x15AD
-#define PCI_DEVICE_ID_VMWARE_VMI        0x0801
-
-/*
- * We use two version numbers for compatibility, with the major
- * number signifying interface breakages, and the minor number
- * interface extensions.
- */
-#define VMI_API_REV_MAJOR       3
-#define VMI_API_REV_MINOR       0
-
-#define VMI_CALL_CPUID                 0
-#define VMI_CALL_WRMSR                 1
-#define VMI_CALL_RDMSR                 2
-#define VMI_CALL_SetGDT                        3
-#define VMI_CALL_SetLDT                        4
-#define VMI_CALL_SetIDT                        5
-#define VMI_CALL_SetTR                 6
-#define VMI_CALL_GetGDT                        7
-#define VMI_CALL_GetLDT                        8
-#define VMI_CALL_GetIDT                        9
-#define VMI_CALL_GetTR                 10
-#define VMI_CALL_WriteGDTEntry         11
-#define VMI_CALL_WriteLDTEntry         12
-#define VMI_CALL_WriteIDTEntry         13
-#define VMI_CALL_UpdateKernelStack     14
-#define VMI_CALL_SetCR0                        15
-#define VMI_CALL_SetCR2                        16
-#define VMI_CALL_SetCR3                        17
-#define VMI_CALL_SetCR4                        18
-#define VMI_CALL_GetCR0                        19
-#define VMI_CALL_GetCR2                        20
-#define VMI_CALL_GetCR3                        21
-#define VMI_CALL_GetCR4                        22
-#define VMI_CALL_WBINVD                        23
-#define VMI_CALL_SetDR                 24
-#define VMI_CALL_GetDR                 25
-#define VMI_CALL_RDPMC                 26
-#define VMI_CALL_RDTSC                 27
-#define VMI_CALL_CLTS                  28
-#define VMI_CALL_EnableInterrupts      29
-#define VMI_CALL_DisableInterrupts     30
-#define VMI_CALL_GetInterruptMask      31
-#define VMI_CALL_SetInterruptMask      32
-#define VMI_CALL_IRET                  33
-#define VMI_CALL_SYSEXIT               34
-#define VMI_CALL_Halt                  35
-#define VMI_CALL_Reboot                        36
-#define VMI_CALL_Shutdown              37
-#define VMI_CALL_SetPxE                        38
-#define VMI_CALL_SetPxELong            39
-#define VMI_CALL_UpdatePxE             40
-#define VMI_CALL_UpdatePxELong         41
-#define VMI_CALL_MachineToPhysical     42
-#define VMI_CALL_PhysicalToMachine     43
-#define VMI_CALL_AllocatePage          44
-#define VMI_CALL_ReleasePage           45
-#define VMI_CALL_InvalPage             46
-#define VMI_CALL_FlushTLB              47
-#define VMI_CALL_SetLinearMapping      48
-
-#define VMI_CALL_SetIOPLMask           61
-#define VMI_CALL_SetInitialAPState     62
-#define VMI_CALL_APICWrite             63
-#define VMI_CALL_APICRead              64
-#define VMI_CALL_IODelay               65
-#define VMI_CALL_SetLazyMode           73
-
-/*
- *---------------------------------------------------------------------
- *
- * MMU operation flags
- *
- *---------------------------------------------------------------------
- */
-
-/* Flags used by VMI_{Allocate|Release}Page call */
-#define VMI_PAGE_PAE             0x10  /* Allocate PAE shadow */
-#define VMI_PAGE_CLONE           0x20  /* Clone from another shadow */
-#define VMI_PAGE_ZEROED          0x40  /* Page is pre-zeroed */
-
-
-/* Flags shared by Allocate|Release Page and PTE updates */
-#define VMI_PAGE_PT              0x01
-#define VMI_PAGE_PD              0x02
-#define VMI_PAGE_PDP             0x04
-#define VMI_PAGE_PML4            0x08
-
-#define VMI_PAGE_NORMAL          0x00 /* for debugging */
-
-/* Flags used by PTE updates */
-#define VMI_PAGE_CURRENT_AS      0x10 /* implies VMI_PAGE_VA_MASK is valid */
-#define VMI_PAGE_DEFER           0x20 /* may queue update until TLB inval */
-#define VMI_PAGE_VA_MASK         0xfffff000
-
-#ifdef CONFIG_X86_PAE
-#define VMI_PAGE_L1            (VMI_PAGE_PT | VMI_PAGE_PAE | VMI_PAGE_ZEROED)
-#define VMI_PAGE_L2            (VMI_PAGE_PD | VMI_PAGE_PAE | VMI_PAGE_ZEROED)
-#else
-#define VMI_PAGE_L1            (VMI_PAGE_PT | VMI_PAGE_ZEROED)
-#define VMI_PAGE_L2            (VMI_PAGE_PD | VMI_PAGE_ZEROED)
-#endif
-
-/* Flags used by VMI_FlushTLB call */
-#define VMI_FLUSH_TLB            0x01
-#define VMI_FLUSH_GLOBAL         0x02
-
-/*
- *---------------------------------------------------------------------
- *
- *  VMI relocation definitions for ROM call get_reloc
- *
- *---------------------------------------------------------------------
- */
-
-/* VMI Relocation types */
-#define VMI_RELOCATION_NONE     0
-#define VMI_RELOCATION_CALL_REL 1
-#define VMI_RELOCATION_JUMP_REL 2
-#define VMI_RELOCATION_NOP     3
-
-#ifndef __ASSEMBLY__
-struct vmi_relocation_info {
-       unsigned char           *eip;
-       unsigned char           type;
-       unsigned char           reserved[3];
-};
-#endif
-
-
-/*
- *---------------------------------------------------------------------
- *
- *  Generic ROM structures and definitions
- *
- *---------------------------------------------------------------------
- */
-
-#ifndef __ASSEMBLY__
-
-struct vrom_header {
-       u16     rom_signature;  /* option ROM signature */
-       u8      rom_length;     /* ROM length in 512 byte chunks */
-       u8      rom_entry[4];   /* 16-bit code entry point */
-       u8      rom_pad0;       /* 4-byte align pad */
-       u32     vrom_signature; /* VROM identification signature */
-       u8      api_version_min;/* Minor version of API */
-       u8      api_version_maj;/* Major version of API */
-       u8      jump_slots;     /* Number of jump slots */
-       u8      reserved1;      /* Reserved for expansion */
-       u32     virtual_top;    /* Hypervisor virtual address start */
-       u16     reserved2;      /* Reserved for expansion */
-       u16     license_offs;   /* Offset to License string */
-       u16     pci_header_offs;/* Offset to PCI OPROM header */
-       u16     pnp_header_offs;/* Offset to PnP OPROM header */
-       u32     rom_pad3;       /* PnP reserverd / VMI reserved */
-       u8      reserved[96];   /* Reserved for headers */
-       char    vmi_init[8];    /* VMI_Init jump point */
-       char    get_reloc[8];   /* VMI_GetRelocationInfo jump point */
-} __attribute__((packed));
-
-struct pnp_header {
-       char sig[4];
-       char rev;
-       char size;
-       short next;
-       short res;
-       long devID;
-       unsigned short manufacturer_offset;
-       unsigned short product_offset;
-} __attribute__((packed));
-
-struct pci_header {
-       char sig[4];
-       short vendorID;
-       short deviceID;
-       short vpdData;
-       short size;
-       char rev;
-       char class;
-       char subclass;
-       char interface;
-       short chunks;
-       char rom_version_min;
-       char rom_version_maj;
-       char codetype;
-       char lastRom;
-       short reserved;
-} __attribute__((packed));
-
-/* Function prototypes for bootstrapping */
-#ifdef CONFIG_VMI
-extern void vmi_init(void);
-extern void vmi_activate(void);
-extern void vmi_bringup(void);
-#else
-static inline void vmi_init(void) {}
-static inline void vmi_activate(void) {}
-static inline void vmi_bringup(void) {}
-#endif
-
-/* State needed to start an application processor in an SMP system. */
-struct vmi_ap_state {
-       u32 cr0;
-       u32 cr2;
-       u32 cr3;
-       u32 cr4;
-
-       u64 efer;
-
-       u32 eip;
-       u32 eflags;
-       u32 eax;
-       u32 ebx;
-       u32 ecx;
-       u32 edx;
-       u32 esp;
-       u32 ebp;
-       u32 esi;
-       u32 edi;
-       u16 cs;
-       u16 ss;
-       u16 ds;
-       u16 es;
-       u16 fs;
-       u16 gs;
-       u16 ldtr;
-
-       u16 gdtr_limit;
-       u32 gdtr_base;
-       u32 idtr_base;
-       u16 idtr_limit;
-};
-
-#endif
diff --git a/arch/x86/include/asm/vmi_time.h b/arch/x86/include/asm/vmi_time.h
deleted file mode 100644 (file)
index c6e0bee..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * VMI Time wrappers
- *
- * Copyright (C) 2006, VMware, 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, GOOD TITLE or
- * NON INFRINGEMENT.  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.
- *
- * Send feedback to dhecht@vmware.com
- *
- */
-
-#ifndef _ASM_X86_VMI_TIME_H
-#define _ASM_X86_VMI_TIME_H
-
-/*
- * Raw VMI call indices for timer functions
- */
-#define VMI_CALL_GetCycleFrequency     66
-#define VMI_CALL_GetCycleCounter       67
-#define VMI_CALL_SetAlarm              68
-#define VMI_CALL_CancelAlarm           69
-#define VMI_CALL_GetWallclockTime      70
-#define VMI_CALL_WallclockUpdated      71
-
-/* Cached VMI timer operations */
-extern struct vmi_timer_ops {
-       u64 (*get_cycle_frequency)(void);
-       u64 (*get_cycle_counter)(int);
-       u64 (*get_wallclock)(void);
-       int (*wallclock_updated)(void);
-       void (*set_alarm)(u32 flags, u64 expiry, u64 period);
-       void (*cancel_alarm)(u32 flags);
-} vmi_timer_ops;
-
-/* Prototypes */
-extern void __init vmi_time_init(void);
-extern unsigned long vmi_get_wallclock(void);
-extern int vmi_set_wallclock(unsigned long now);
-extern unsigned long long vmi_sched_clock(void);
-extern unsigned long vmi_tsc_khz(void);
-
-#ifdef CONFIG_X86_LOCAL_APIC
-extern void __devinit vmi_time_bsp_init(void);
-extern void __devinit vmi_time_ap_init(void);
-#endif
-
-/*
- * When run under a hypervisor, a vcpu is always in one of three states:
- * running, halted, or ready.  The vcpu is in the 'running' state if it
- * is executing.  When the vcpu executes the halt interface, the vcpu
- * enters the 'halted' state and remains halted until there is some work
- * pending for the vcpu (e.g. an alarm expires, host I/O completes on
- * behalf of virtual I/O).  At this point, the vcpu enters the 'ready'
- * state (waiting for the hypervisor to reschedule it).  Finally, at any
- * time when the vcpu is not in the 'running' state nor the 'halted'
- * state, it is in the 'ready' state.
- *
- * Real time is advances while the vcpu is 'running', 'ready', or
- * 'halted'.  Stolen time is the time in which the vcpu is in the
- * 'ready' state.  Available time is the remaining time -- the vcpu is
- * either 'running' or 'halted'.
- *
- * All three views of time are accessible through the VMI cycle
- * counters.
- */
-
-/* The cycle counters. */
-#define VMI_CYCLES_REAL         0
-#define VMI_CYCLES_AVAILABLE    1
-#define VMI_CYCLES_STOLEN       2
-
-/* The alarm interface 'flags' bits */
-#define VMI_ALARM_COUNTERS      2
-
-#define VMI_ALARM_COUNTER_MASK  0x000000ff
-
-#define VMI_ALARM_WIRED_IRQ0    0x00000000
-#define VMI_ALARM_WIRED_LVTT    0x00010000
-
-#define VMI_ALARM_IS_ONESHOT    0x00000000
-#define VMI_ALARM_IS_PERIODIC   0x00000100
-
-#define CONFIG_VMI_ALARM_HZ    100
-
-#endif /* _ASM_X86_VMI_TIME_H */
index fedf32a8c3ecdd7a1aaed41b2884d2c9b10bf033..2c833d8c41418c0583ee2da48231918dd1a6c176 100644 (file)
@@ -34,7 +34,8 @@ GCOV_PROFILE_paravirt.o               := n
 obj-y                  := process_$(BITS).o signal.o entry_$(BITS).o
 obj-y                  += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
 obj-y                  += time.o ioport.o ldt.o dumpstack.o
-obj-y                  += setup.o x86_init.o i8259.o irqinit.o
+obj-y                  += setup.o x86_init.o i8259.o irqinit.o jump_label.o
+obj-$(CONFIG_IRQ_WORK)  += irq_work.o
 obj-$(CONFIG_X86_VISWS)        += visws_quirks.o
 obj-$(CONFIG_X86_32)   += probe_roms_32.o
 obj-$(CONFIG_X86_32)   += sys_i386_32.o i386_ksyms_32.o
@@ -44,6 +45,7 @@ obj-y                 += bootflag.o e820.o
 obj-y                  += pci-dma.o quirks.o i8237.o topology.o kdebugfs.o
 obj-y                  += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
 obj-y                  += tsc.o io_delay.o rtc.o
+obj-y                  += pci-iommu_table.o
 
 obj-$(CONFIG_X86_TRAMPOLINE)   += trampoline.o
 obj-y                          += process.o
@@ -85,15 +87,15 @@ obj-$(CONFIG_DOUBLEFAULT)   += doublefault_32.o
 obj-$(CONFIG_KGDB)             += kgdb.o
 obj-$(CONFIG_VM86)             += vm86_32.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
+obj-$(CONFIG_EARLY_PRINTK_MRST)        += early_printk_mrst.o
 
 obj-$(CONFIG_HPET_TIMER)       += hpet.o
 obj-$(CONFIG_APB_TIMER)                += apb_timer.o
 
-obj-$(CONFIG_K8_NB)            += k8.o
+obj-$(CONFIG_AMD_NB)           += amd_nb.o
 obj-$(CONFIG_DEBUG_RODATA_TEST)        += test_rodata.o
 obj-$(CONFIG_DEBUG_NX_TEST)    += test_nx.o
 
-obj-$(CONFIG_VMI)              += vmi_32.o vmiclock_32.o
 obj-$(CONFIG_KVM_GUEST)                += kvm.o
 obj-$(CONFIG_KVM_CLOCK)                += kvmclock.o
 obj-$(CONFIG_PARAVIRT)         += paravirt.o paravirt_patch_$(BITS).o
@@ -106,6 +108,7 @@ obj-$(CONFIG_SCx200)                += scx200.o
 scx200-y                       += scx200_32.o
 
 obj-$(CONFIG_OLPC)             += olpc.o
+obj-$(CONFIG_OLPC_XO1)         += olpc-xo1.o
 obj-$(CONFIG_OLPC_OPENFIRMWARE)        += olpc_ofw.o
 obj-$(CONFIG_X86_MRST)         += mrst.o
 
@@ -122,7 +125,6 @@ obj-$(CONFIG_SWIOTLB)                       += pci-swiotlb.o
 # 64 bit specific files
 ifeq ($(CONFIG_X86_64),y)
        obj-$(CONFIG_X86_UV)            += tlb_uv.o bios_uv.o uv_irq.o uv_sysfs.o uv_time.o
-       obj-$(CONFIG_X86_PM_TIMER)      += pmtimer_64.o
        obj-$(CONFIG_AUDIT)             += audit_64.o
 
        obj-$(CONFIG_GART_IOMMU)        += pci-gart_64.o aperture_64.o
index fb16f17e59bea7dcde91e6ad6275c7bad5bbdfb8..5812404a0d4ce5e3eb815675f591f18b95762329 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <acpi/processor.h>
 #include <asm/acpi.h>
+#include <asm/mwait.h>
 
 /*
  * Initialize bm_flags based on the CPU cache properties
@@ -65,16 +66,6 @@ static struct cstate_entry __percpu *cpu_cstate_entry;       /* per CPU ptr */
 
 static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
 
-#define MWAIT_SUBSTATE_MASK    (0xf)
-#define MWAIT_CSTATE_MASK      (0xf)
-#define MWAIT_SUBSTATE_SIZE    (4)
-
-#define CPUID_MWAIT_LEAF (5)
-#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
-#define CPUID5_ECX_INTERRUPT_BREAK     (0x2)
-
-#define MWAIT_ECX_INTERRUPT_BREAK      (0x1)
-
 #define NATIVE_CSTATE_BEYOND_HALT      (2)
 
 static long acpi_processor_ffh_cstate_probe_cpu(void *_cx)
index 33cec152070df4f9c5dc30d47a6274524d097225..e1252074ea4077306d5673c41eed846daabec90c 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/acpi.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/dmi.h>
 #include <linux/cpumask.h>
 #include <asm/segment.h>
@@ -125,7 +126,7 @@ void acpi_restore_state_mem(void)
  */
 void __init acpi_reserve_wakeup_memory(void)
 {
-       unsigned long mem;
+       phys_addr_t mem;
 
        if ((&wakeup_code_end - &wakeup_code_start) > WAKEUP_SIZE) {
                printk(KERN_ERR
@@ -133,15 +134,15 @@ void __init acpi_reserve_wakeup_memory(void)
                return;
        }
 
-       mem = find_e820_area(0, 1<<20, WAKEUP_SIZE, PAGE_SIZE);
+       mem = memblock_find_in_range(0, 1<<20, WAKEUP_SIZE, PAGE_SIZE);
 
-       if (mem == -1L) {
+       if (mem == MEMBLOCK_ERROR) {
                printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n");
                return;
        }
        acpi_realmode = (unsigned long) phys_to_virt(mem);
        acpi_wakeup_address = mem;
-       reserve_early(mem, mem + WAKEUP_SIZE, "ACPI WAKEUP");
+       memblock_x86_reserve_range(mem, mem + WAKEUP_SIZE, "ACPI WAKEUP");
 }
 
 
index f65ab8b014c4f42421d77200243c39c7fd252165..a36bb90aef5383d68bcf4af0b0c33749d572163a 100644 (file)
@@ -195,7 +195,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len)
 
 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
 extern s32 __smp_locks[], __smp_locks_end[];
-static void *text_poke_early(void *addr, const void *opcode, size_t len);
+void *text_poke_early(void *addr, const void *opcode, size_t len);
 
 /* Replace instructions with better alternatives for this CPU type.
    This runs before SMP is initialized to avoid SMP problems with
@@ -522,7 +522,7 @@ void __init alternative_instructions(void)
  * instructions. And on the local CPU you need to be protected again NMI or MCE
  * handlers seeing an inconsistent instruction while you patch.
  */
-static void *__init_or_module text_poke_early(void *addr, const void *opcode,
+void *__init_or_module text_poke_early(void *addr, const void *opcode,
                                              size_t len)
 {
        unsigned long flags;
@@ -637,7 +637,72 @@ void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len)
        tpp.len = len;
        atomic_set(&stop_machine_first, 1);
        wrote_text = 0;
-       stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
+       /* Use __stop_machine() because the caller already got online_cpus. */
+       __stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
        return addr;
 }
 
+#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
+
+unsigned char ideal_nop5[IDEAL_NOP_SIZE_5];
+
+void __init arch_init_ideal_nop5(void)
+{
+       extern const unsigned char ftrace_test_p6nop[];
+       extern const unsigned char ftrace_test_nop5[];
+       extern const unsigned char ftrace_test_jmp[];
+       int faulted = 0;
+
+       /*
+        * There is no good nop for all x86 archs.
+        * We will default to using the P6_NOP5, but first we
+        * will test to make sure that the nop will actually
+        * work on this CPU. If it faults, we will then
+        * go to a lesser efficient 5 byte nop. If that fails
+        * we then just use a jmp as our nop. This isn't the most
+        * efficient nop, but we can not use a multi part nop
+        * since we would then risk being preempted in the middle
+        * of that nop, and if we enabled tracing then, it might
+        * cause a system crash.
+        *
+        * TODO: check the cpuid to determine the best nop.
+        */
+       asm volatile (
+               "ftrace_test_jmp:"
+               "jmp ftrace_test_p6nop\n"
+               "nop\n"
+               "nop\n"
+               "nop\n"  /* 2 byte jmp + 3 bytes */
+               "ftrace_test_p6nop:"
+               P6_NOP5
+               "jmp 1f\n"
+               "ftrace_test_nop5:"
+               ".byte 0x66,0x66,0x66,0x66,0x90\n"
+               "1:"
+               ".section .fixup, \"ax\"\n"
+               "2:     movl $1, %0\n"
+               "       jmp ftrace_test_nop5\n"
+               "3:     movl $2, %0\n"
+               "       jmp 1b\n"
+               ".previous\n"
+               _ASM_EXTABLE(ftrace_test_p6nop, 2b)
+               _ASM_EXTABLE(ftrace_test_nop5, 3b)
+               : "=r"(faulted) : "0" (faulted));
+
+       switch (faulted) {
+       case 0:
+               pr_info("converting mcount calls to 0f 1f 44 00 00\n");
+               memcpy(ideal_nop5, ftrace_test_p6nop, IDEAL_NOP_SIZE_5);
+               break;
+       case 1:
+               pr_info("converting mcount calls to 66 66 66 66 90\n");
+               memcpy(ideal_nop5, ftrace_test_nop5, IDEAL_NOP_SIZE_5);
+               break;
+       case 2:
+               pr_info("converting mcount calls to jmp . + 5\n");
+               memcpy(ideal_nop5, ftrace_test_jmp, IDEAL_NOP_SIZE_5);
+               break;
+       }
+
+}
+#endif
index 679b6450382b9c8bafa2d71e2677fcd5ae075b95..d2fdb0826df25654fa94cc7ee307c23e235c5c91 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
  * Author: Joerg Roedel <joerg.roedel@amd.com>
  *         Leo Duran <leo.duran@amd.com>
  *
index 5a170cbbbed86aa1376eb19336a5329aacc96e91..6e11c8134158e62837deab38e350037e462730f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 Advanced Micro Devices, Inc.
+ * Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
  * Author: Joerg Roedel <joerg.roedel@amd.com>
  *         Leo Duran <leo.duran@amd.com>
  *
@@ -31,7 +31,7 @@
 #include <asm/iommu.h>
 #include <asm/gart.h>
 #include <asm/x86_init.h>
-
+#include <asm/iommu_table.h>
 /*
  * definitions for the ACPI scanning code
  */
@@ -194,6 +194,39 @@ static inline unsigned long tbl_size(int entry_size)
        return 1UL << shift;
 }
 
+/* Access to l1 and l2 indexed register spaces */
+
+static u32 iommu_read_l1(struct amd_iommu *iommu, u16 l1, u8 address)
+{
+       u32 val;
+
+       pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16));
+       pci_read_config_dword(iommu->dev, 0xfc, &val);
+       return val;
+}
+
+static void iommu_write_l1(struct amd_iommu *iommu, u16 l1, u8 address, u32 val)
+{
+       pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16 | 1 << 31));
+       pci_write_config_dword(iommu->dev, 0xfc, val);
+       pci_write_config_dword(iommu->dev, 0xf8, (address | l1 << 16));
+}
+
+static u32 iommu_read_l2(struct amd_iommu *iommu, u8 address)
+{
+       u32 val;
+
+       pci_write_config_dword(iommu->dev, 0xf0, address);
+       pci_read_config_dword(iommu->dev, 0xf4, &val);
+       return val;
+}
+
+static void iommu_write_l2(struct amd_iommu *iommu, u8 address, u32 val)
+{
+       pci_write_config_dword(iommu->dev, 0xf0, (address | 1 << 8));
+       pci_write_config_dword(iommu->dev, 0xf4, val);
+}
+
 /****************************************************************************
  *
  * AMD IOMMU MMIO register space handling functions
@@ -619,6 +652,7 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu)
 {
        int cap_ptr = iommu->cap_ptr;
        u32 range, misc;
+       int i, j;
 
        pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET,
                              &iommu->cap);
@@ -633,12 +667,29 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu)
                                        MMIO_GET_LD(range));
        iommu->evt_msi_num = MMIO_MSI_NUM(misc);
 
-       if (is_rd890_iommu(iommu->dev)) {
-               pci_read_config_dword(iommu->dev, 0xf0, &iommu->cache_cfg[0]);
-               pci_read_config_dword(iommu->dev, 0xf4, &iommu->cache_cfg[1]);
-               pci_read_config_dword(iommu->dev, 0xf8, &iommu->cache_cfg[2]);
-               pci_read_config_dword(iommu->dev, 0xfc, &iommu->cache_cfg[3]);
-       }
+       if (!is_rd890_iommu(iommu->dev))
+               return;
+
+       /*
+        * Some rd890 systems may not be fully reconfigured by the BIOS, so
+        * it's necessary for us to store this information so it can be
+        * reprogrammed on resume
+        */
+
+       pci_read_config_dword(iommu->dev, iommu->cap_ptr + 4,
+                             &iommu->stored_addr_lo);
+       pci_read_config_dword(iommu->dev, iommu->cap_ptr + 8,
+                             &iommu->stored_addr_hi);
+
+       /* Low bit locks writes to configuration space */
+       iommu->stored_addr_lo &= ~1;
+
+       for (i = 0; i < 6; i++)
+               for (j = 0; j < 0x12; j++)
+                       iommu->stored_l1[i][j] = iommu_read_l1(iommu, i, j);
+
+       for (i = 0; i < 0x83; i++)
+               iommu->stored_l2[i] = iommu_read_l2(iommu, i);
 }
 
 /*
@@ -1127,14 +1178,53 @@ static void iommu_init_flags(struct amd_iommu *iommu)
        iommu_feature_enable(iommu, CONTROL_COHERENT_EN);
 }
 
-static void iommu_apply_quirks(struct amd_iommu *iommu)
+static void iommu_apply_resume_quirks(struct amd_iommu *iommu)
 {
-       if (is_rd890_iommu(iommu->dev)) {
-               pci_write_config_dword(iommu->dev, 0xf0, iommu->cache_cfg[0]);
-               pci_write_config_dword(iommu->dev, 0xf4, iommu->cache_cfg[1]);
-               pci_write_config_dword(iommu->dev, 0xf8, iommu->cache_cfg[2]);
-               pci_write_config_dword(iommu->dev, 0xfc, iommu->cache_cfg[3]);
-       }
+       int i, j;
+       u32 ioc_feature_control;
+       struct pci_dev *pdev = NULL;
+
+       /* RD890 BIOSes may not have completely reconfigured the iommu */
+       if (!is_rd890_iommu(iommu->dev))
+               return;
+
+       /*
+        * First, we need to ensure that the iommu is enabled. This is
+        * controlled by a register in the northbridge
+        */
+       pdev = pci_get_bus_and_slot(iommu->dev->bus->number, PCI_DEVFN(0, 0));
+
+       if (!pdev)
+               return;
+
+       /* Select Northbridge indirect register 0x75 and enable writing */
+       pci_write_config_dword(pdev, 0x60, 0x75 | (1 << 7));
+       pci_read_config_dword(pdev, 0x64, &ioc_feature_control);
+
+       /* Enable the iommu */
+       if (!(ioc_feature_control & 0x1))
+               pci_write_config_dword(pdev, 0x64, ioc_feature_control | 1);
+
+       pci_dev_put(pdev);
+
+       /* Restore the iommu BAR */
+       pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4,
+                              iommu->stored_addr_lo);
+       pci_write_config_dword(iommu->dev, iommu->cap_ptr + 8,
+                              iommu->stored_addr_hi);
+
+       /* Restore the l1 indirect regs for each of the 6 l1s */
+       for (i = 0; i < 6; i++)
+               for (j = 0; j < 0x12; j++)
+                       iommu_write_l1(iommu, i, j, iommu->stored_l1[i][j]);
+
+       /* Restore the l2 indirect regs */
+       for (i = 0; i < 0x83; i++)
+               iommu_write_l2(iommu, i, iommu->stored_l2[i]);
+
+       /* Lock PCI setup registers */
+       pci_write_config_dword(iommu->dev, iommu->cap_ptr + 4,
+                              iommu->stored_addr_lo | 1);
 }
 
 /*
@@ -1147,7 +1237,6 @@ static void enable_iommus(void)
 
        for_each_iommu(iommu) {
                iommu_disable(iommu);
-               iommu_apply_quirks(iommu);
                iommu_init_flags(iommu);
                iommu_set_device_table(iommu);
                iommu_enable_command_buffer(iommu);
@@ -1173,6 +1262,11 @@ static void disable_iommus(void)
 
 static int amd_iommu_resume(struct sys_device *dev)
 {
+       struct amd_iommu *iommu;
+
+       for_each_iommu(iommu)
+               iommu_apply_resume_quirks(iommu);
+
        /* re-load the hardware */
        enable_iommus();
 
@@ -1405,13 +1499,13 @@ static int __init early_amd_iommu_detect(struct acpi_table_header *table)
        return 0;
 }
 
-void __init amd_iommu_detect(void)
+int __init amd_iommu_detect(void)
 {
        if (no_iommu || (iommu_detected && !gart_iommu_aperture))
-               return;
+               return -ENODEV;
 
        if (amd_iommu_disabled)
-               return;
+               return -ENODEV;
 
        if (acpi_table_parse("IVRS", early_amd_iommu_detect) == 0) {
                iommu_detected = 1;
@@ -1420,7 +1514,9 @@ void __init amd_iommu_detect(void)
 
                /* Make sure ACS will be enabled */
                pci_request_acs();
+               return 1;
        }
+       return -ENODEV;
 }
 
 /****************************************************************************
@@ -1451,3 +1547,8 @@ static int __init parse_amd_iommu_options(char *str)
 
 __setup("amd_iommu_dump", parse_amd_iommu_dump);
 __setup("amd_iommu=", parse_amd_iommu_options);
+
+IOMMU_INIT_FINISH(amd_iommu_detect,
+                 gart_iommu_hole_init,
+                 0,
+                 0);
similarity index 66%
rename from arch/x86/kernel/k8.c
rename to arch/x86/kernel/amd_nb.c
index 0f7bc20cfcdedd58f66b6b036bfb7d824e599e37..8f6463d8ed0de1ebfece6cb1138a15697f657197 100644 (file)
@@ -8,21 +8,19 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
-#include <asm/k8.h>
-
-int num_k8_northbridges;
-EXPORT_SYMBOL(num_k8_northbridges);
+#include <asm/amd_nb.h>
 
 static u32 *flush_words;
 
 struct pci_device_id k8_nb_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_MISC) },
        {}
 };
 EXPORT_SYMBOL(k8_nb_ids);
 
-struct pci_dev **k8_northbridges;
+struct k8_northbridge_info k8_northbridges;
 EXPORT_SYMBOL(k8_northbridges);
 
 static struct pci_dev *next_k8_northbridge(struct pci_dev *dev)
@@ -40,36 +38,45 @@ int cache_k8_northbridges(void)
        int i;
        struct pci_dev *dev;
 
-       if (num_k8_northbridges)
+       if (k8_northbridges.num)
                return 0;
 
        dev = NULL;
        while ((dev = next_k8_northbridge(dev)) != NULL)
-               num_k8_northbridges++;
+               k8_northbridges.num++;
+
+       /* some CPU families (e.g. family 0x11) do not support GART */
+       if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10 ||
+           boot_cpu_data.x86 == 0x15)
+               k8_northbridges.gart_supported = 1;
 
-       k8_northbridges = kmalloc((num_k8_northbridges + 1) * sizeof(void *),
-                                 GFP_KERNEL);
-       if (!k8_northbridges)
+       k8_northbridges.nb_misc = kmalloc((k8_northbridges.num + 1) *
+                                         sizeof(void *), GFP_KERNEL);
+       if (!k8_northbridges.nb_misc)
                return -ENOMEM;
 
-       if (!num_k8_northbridges) {
-               k8_northbridges[0] = NULL;
+       if (!k8_northbridges.num) {
+               k8_northbridges.nb_misc[0] = NULL;
                return 0;
        }
 
-       flush_words = kmalloc(num_k8_northbridges * sizeof(u32), GFP_KERNEL);
-       if (!flush_words) {
-               kfree(k8_northbridges);
-               return -ENOMEM;
+       if (k8_northbridges.gart_supported) {
+               flush_words = kmalloc(k8_northbridges.num * sizeof(u32),
+                                     GFP_KERNEL);
+               if (!flush_words) {
+                       kfree(k8_northbridges.nb_misc);
+                       return -ENOMEM;
+               }
        }
 
        dev = NULL;
        i = 0;
        while ((dev = next_k8_northbridge(dev)) != NULL) {
-               k8_northbridges[i] = dev;
-               pci_read_config_dword(dev, 0x9c, &flush_words[i++]);
+               k8_northbridges.nb_misc[i] = dev;
+               if (k8_northbridges.gart_supported)
+                       pci_read_config_dword(dev, 0x9c, &flush_words[i++]);
        }
-       k8_northbridges[i] = NULL;
+       k8_northbridges.nb_misc[i] = NULL;
        return 0;
 }
 EXPORT_SYMBOL_GPL(cache_k8_northbridges);
@@ -93,22 +100,25 @@ void k8_flush_garts(void)
        unsigned long flags;
        static DEFINE_SPINLOCK(gart_lock);
 
+       if (!k8_northbridges.gart_supported)
+               return;
+
        /* Avoid races between AGP and IOMMU. In theory it's not needed
           but I'm not sure if the hardware won't lose flush requests
           when another is pending. This whole thing is so expensive anyways
           that it doesn't matter to serialize more. -AK */
        spin_lock_irqsave(&gart_lock, flags);
        flushed = 0;
-       for (i = 0; i < num_k8_northbridges; i++) {
-               pci_write_config_dword(k8_northbridges[i], 0x9c,
+       for (i = 0; i < k8_northbridges.num; i++) {
+               pci_write_config_dword(k8_northbridges.nb_misc[i], 0x9c,
                                       flush_words[i]|1);
                flushed++;
        }
-       for (i = 0; i < num_k8_northbridges; i++) {
+       for (i = 0; i < k8_northbridges.num; i++) {
                u32 w;
                /* Make sure the hardware actually executed the flush*/
                for (;;) {
-                       pci_read_config_dword(k8_northbridges[i],
+                       pci_read_config_dword(k8_northbridges.nb_misc[i],
                                              0x9c, &w);
                        if (!(w & 1))
                                break;
index 8dd77800ff5d7b444742ae02cc5168ccf8855fcd..92543c73cf8ed8d085dc581fe8171b3bbb6f939e 100644 (file)
@@ -231,34 +231,6 @@ static void apbt_restart_clocksource(struct clocksource *cs)
        apbt_start_counter(phy_cs_timer_id);
 }
 
-/* Setup IRQ routing via IOAPIC */
-#ifdef CONFIG_SMP
-static void apbt_setup_irq(struct apbt_dev *adev)
-{
-       struct irq_chip *chip;
-       struct irq_desc *desc;
-
-       /* timer0 irq has been setup early */
-       if (adev->irq == 0)
-               return;
-       desc = irq_to_desc(adev->irq);
-       chip = get_irq_chip(adev->irq);
-       disable_irq(adev->irq);
-       desc->status |= IRQ_MOVE_PCNTXT;
-       irq_set_affinity(adev->irq, cpumask_of(adev->cpu));
-       /* APB timer irqs are set up as mp_irqs, timer is edge triggerred */
-       set_irq_chip_and_handler_name(adev->irq, chip, handle_edge_irq, "edge");
-       enable_irq(adev->irq);
-       if (system_state == SYSTEM_BOOTING)
-               if (request_irq(adev->irq, apbt_interrupt_handler,
-                               IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING,
-                               adev->name, adev)) {
-                       printk(KERN_ERR "Failed request IRQ for APBT%d\n",
-                              adev->num);
-               }
-}
-#endif
-
 static void apbt_enable_int(int n)
 {
        unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL);
@@ -334,6 +306,27 @@ static int __init apbt_clockevent_register(void)
 }
 
 #ifdef CONFIG_SMP
+
+static void apbt_setup_irq(struct apbt_dev *adev)
+{
+       /* timer0 irq has been setup early */
+       if (adev->irq == 0)
+               return;
+
+       if (system_state == SYSTEM_BOOTING) {
+               irq_modify_status(adev->irq, 0, IRQ_MOVE_PCNTXT);
+               /* APB timer irqs are set up as mp_irqs, timer is edge type */
+               __set_irq_handler(adev->irq, handle_edge_irq, 0, "edge");
+               if (request_irq(adev->irq, apbt_interrupt_handler,
+                               IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING,
+                               adev->name, adev)) {
+                       printk(KERN_ERR "Failed request IRQ for APBT%d\n",
+                              adev->num);
+               }
+       } else
+               enable_irq(adev->irq);
+}
+
 /* Should be called with per cpu */
 void apbt_setup_secondary_clock(void)
 {
@@ -343,7 +336,7 @@ void apbt_setup_secondary_clock(void)
 
        /* Don't register boot CPU clockevent */
        cpu = smp_processor_id();
-       if (cpu == boot_cpu_id)
+       if (!cpu)
                return;
        /*
         * We need to calculate the scaled math multiplication factor for
@@ -389,16 +382,17 @@ static int apbt_cpuhp_notify(struct notifier_block *n,
 
        switch (action & 0xf) {
        case CPU_DEAD:
+               disable_irq(adev->irq);
                apbt_disable_int(cpu);
-               if (system_state == SYSTEM_RUNNING)
+               if (system_state == SYSTEM_RUNNING) {
                        pr_debug("skipping APBT CPU %lu offline\n", cpu);
-               else if (adev) {
+               else if (adev) {
                        pr_debug("APBT clockevent for cpu %lu offline\n", cpu);
                        free_irq(adev->irq, adev);
                }
                break;
        default:
-               pr_debug(KERN_INFO "APBT notified %lu, no action\n", action);
+               pr_debug("APBT notified %lu, no action\n", action);
        }
        return NOTIFY_OK;
 }
@@ -552,7 +546,7 @@ bad_count:
                pr_debug("APB CS going back %lx:%lx:%lx ",
                         t2, last_read, t2 - last_read);
 bad_count_x3:
-               pr_debug(KERN_INFO "tripple check enforced\n");
+               pr_debug("triple check enforced\n");
                t0 = apbt_readl(phy_cs_timer_id,
                                APBTMR_N_CURRENT_VALUE);
                udelay(1);
index a2e0caf26e172c8f7b18231e4f4a072161ed66fe..b3a16e8f0703d47f50a354223bfe8c6e9382126e 100644 (file)
@@ -27,7 +27,7 @@
 #include <asm/gart.h>
 #include <asm/pci-direct.h>
 #include <asm/dma.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 #include <asm/x86_init.h>
 
 int gart_iommu_aperture;
@@ -307,7 +307,7 @@ void __init early_gart_iommu_check(void)
                                continue;
 
                        ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
-                       aper_enabled = ctl & AMD64_GARTEN;
+                       aper_enabled = ctl & GARTEN;
                        aper_order = (ctl >> 1) & 7;
                        aper_size = (32 * 1024 * 1024) << aper_order;
                        aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff;
@@ -362,7 +362,7 @@ void __init early_gart_iommu_check(void)
                                continue;
 
                        ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
-                       ctl &= ~AMD64_GARTEN;
+                       ctl &= ~GARTEN;
                        write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
                }
        }
@@ -371,7 +371,7 @@ void __init early_gart_iommu_check(void)
 
 static int __initdata printed_gart_size_msg;
 
-void __init gart_iommu_hole_init(void)
+int __init gart_iommu_hole_init(void)
 {
        u32 agp_aper_base = 0, agp_aper_order = 0;
        u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
@@ -381,7 +381,7 @@ void __init gart_iommu_hole_init(void)
 
        if (gart_iommu_aperture_disabled || !fix_aperture ||
            !early_pci_allowed())
-               return;
+               return -ENODEV;
 
        printk(KERN_INFO  "Checking aperture...\n");
 
@@ -463,8 +463,9 @@ out:
                        unsigned long n = (32 * 1024 * 1024) << last_aper_order;
 
                        insert_aperture_resource((u32)last_aper_base, n);
+                       return 1;
                }
-               return;
+               return 0;
        }
 
        if (!fallback_aper_force) {
@@ -500,13 +501,18 @@ out:
                        panic("Not enough memory for aperture");
                }
        } else {
-               return;
+               return 0;
        }
 
        /* Fix up the north bridges */
        for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) {
-               int bus;
-               int dev_base, dev_limit;
+               int bus, dev_base, dev_limit;
+
+               /*
+                * Don't enable translation yet but enable GART IO and CPU
+                * accesses and set DISTLBWALKPRB since GART table memory is UC.
+                */
+               u32 ctl = DISTLBWALKPRB | aper_order << 1;
 
                bus = bus_dev_ranges[i].bus;
                dev_base = bus_dev_ranges[i].dev_base;
@@ -515,13 +521,12 @@ out:
                        if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00)))
                                continue;
 
-                       /* Don't enable translation yet. That is done later.
-                          Assume this BIOS didn't initialise the GART so
-                          just overwrite all previous bits */
-                       write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, aper_order << 1);
+                       write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
                        write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25);
                }
        }
 
        set_up_gart_resume(aper_order, aper_alloc);
+
+       return 1;
 }
index e3b534cda49a8097dde55400083d7eeb8f9c694c..850657d1b0ed573e23552913d7aae230df30fe9a 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/mce.h>
 #include <asm/kvm_para.h>
 #include <asm/tsc.h>
+#include <asm/atomic.h>
 
 unsigned int num_processors;
 
@@ -370,38 +371,87 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen)
 }
 
 /*
- * Setup extended LVT, AMD specific (K8, family 10h)
+ * Setup extended LVT, AMD specific
  *
- * Vector mappings are hard coded. On K8 only offset 0 (APIC500) and
- * MCE interrupts are supported. Thus MCE offset must be set to 0.
+ * Software should use the LVT offsets the BIOS provides.  The offsets
+ * are determined by the subsystems using it like those for MCE
+ * threshold or IBS.  On K8 only offset 0 (APIC500) and MCE interrupts
+ * are supported. Beginning with family 10h at least 4 offsets are
+ * available.
  *
- * If mask=1, the LVT entry does not generate interrupts while mask=0
- * enables the vector. See also the BKDGs.
+ * Since the offsets must be consistent for all cores, we keep track
+ * of the LVT offsets in software and reserve the offset for the same
+ * vector also to be used on other cores. An offset is freed by
+ * setting the entry to APIC_EILVT_MASKED.
+ *
+ * If the BIOS is right, there should be no conflicts. Otherwise a
+ * "[Firmware Bug]: ..." error message is generated. However, if
+ * software does not properly determines the offsets, it is not
+ * necessarily a BIOS bug.
  */
 
-#define APIC_EILVT_LVTOFF_MCE 0
-#define APIC_EILVT_LVTOFF_IBS 1
+static atomic_t eilvt_offsets[APIC_EILVT_NR_MAX];
 
-static void setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask)
+static inline int eilvt_entry_is_changeable(unsigned int old, unsigned int new)
 {
-       unsigned long reg = (lvt_off << 4) + APIC_EILVTn(0);
-       unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
-
-       apic_write(reg, v);
+       return (old & APIC_EILVT_MASKED)
+               || (new == APIC_EILVT_MASKED)
+               || ((new & ~APIC_EILVT_MASKED) == old);
 }
 
-u8 setup_APIC_eilvt_mce(u8 vector, u8 msg_type, u8 mask)
+static unsigned int reserve_eilvt_offset(int offset, unsigned int new)
 {
-       setup_APIC_eilvt(APIC_EILVT_LVTOFF_MCE, vector, msg_type, mask);
-       return APIC_EILVT_LVTOFF_MCE;
+       unsigned int rsvd;                      /* 0: uninitialized */
+
+       if (offset >= APIC_EILVT_NR_MAX)
+               return ~0;
+
+       rsvd = atomic_read(&eilvt_offsets[offset]) & ~APIC_EILVT_MASKED;
+       do {
+               if (rsvd &&
+                   !eilvt_entry_is_changeable(rsvd, new))
+                       /* may not change if vectors are different */
+                       return rsvd;
+               rsvd = atomic_cmpxchg(&eilvt_offsets[offset], rsvd, new);
+       } while (rsvd != new);
+
+       return new;
 }
 
-u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask)
+/*
+ * If mask=1, the LVT entry does not generate interrupts while mask=0
+ * enables the vector. See also the BKDGs.
+ */
+
+int setup_APIC_eilvt(u8 offset, u8 vector, u8 msg_type, u8 mask)
 {
-       setup_APIC_eilvt(APIC_EILVT_LVTOFF_IBS, vector, msg_type, mask);
-       return APIC_EILVT_LVTOFF_IBS;
+       unsigned long reg = APIC_EILVTn(offset);
+       unsigned int new, old, reserved;
+
+       new = (mask << 16) | (msg_type << 8) | vector;
+       old = apic_read(reg);
+       reserved = reserve_eilvt_offset(offset, new);
+
+       if (reserved != new) {
+               pr_err(FW_BUG "cpu %d, try to setup vector 0x%x, but "
+                      "vector 0x%x was already reserved by another core, "
+                      "APIC%lX=0x%x\n",
+                      smp_processor_id(), new, reserved, reg, old);
+               return -EINVAL;
+       }
+
+       if (!eilvt_entry_is_changeable(old, new)) {
+               pr_err(FW_BUG "cpu %d, try to setup vector 0x%x but "
+                      "register already in use, APIC%lX=0x%x\n",
+                      smp_processor_id(), new, reg, old);
+               return -EBUSY;
+       }
+
+       apic_write(reg, new);
+
+       return 0;
 }
-EXPORT_SYMBOL_GPL(setup_APIC_eilvt_ibs);
+EXPORT_SYMBOL_GPL(setup_APIC_eilvt);
 
 /*
  * Program the next event, relative to now
@@ -1665,10 +1715,7 @@ int __init APIC_init_uniprocessor(void)
        }
 #endif
 
-#ifndef CONFIG_SMP
-       enable_IR_x2apic();
        default_setup_apic_routing();
-#endif
 
        verify_local_APIC();
        connect_bsp_APIC();
index 5c5b8f3dddb58686ba4afc8b314237c0c318370b..8ae808d110f445f352ca686faf3a29d9d93bfa50 100644 (file)
@@ -131,13 +131,9 @@ struct irq_pin_list {
        struct irq_pin_list *next;
 };
 
-static struct irq_pin_list *get_one_free_irq_2_pin(int node)
+static struct irq_pin_list *alloc_irq_pin_list(int node)
 {
-       struct irq_pin_list *pin;
-
-       pin = kzalloc_node(sizeof(*pin), GFP_ATOMIC, node);
-
-       return pin;
+       return kzalloc_node(sizeof(struct irq_pin_list), GFP_KERNEL, node);
 }
 
 /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
@@ -150,10 +146,7 @@ static struct irq_cfg irq_cfgx[NR_IRQS];
 int __init arch_early_irq_init(void)
 {
        struct irq_cfg *cfg;
-       struct irq_desc *desc;
-       int count;
-       int node;
-       int i;
+       int count, node, i;
 
        if (!legacy_pic->nr_legacy_irqs) {
                nr_irqs_gsi = 0;
@@ -162,13 +155,15 @@ int __init arch_early_irq_init(void)
 
        cfg = irq_cfgx;
        count = ARRAY_SIZE(irq_cfgx);
-       node= cpu_to_node(boot_cpu_id);
+       node = cpu_to_node(0);
+
+       /* Make sure the legacy interrupts are marked in the bitmap */
+       irq_reserve_irqs(0, legacy_pic->nr_legacy_irqs);
 
        for (i = 0; i < count; i++) {
-               desc = irq_to_desc(i);
-               desc->chip_data = &cfg[i];
-               zalloc_cpumask_var_node(&cfg[i].domain, GFP_NOWAIT, node);
-               zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_NOWAIT, node);
+               set_irq_chip_data(i, &cfg[i]);
+               zalloc_cpumask_var_node(&cfg[i].domain, GFP_KERNEL, node);
+               zalloc_cpumask_var_node(&cfg[i].old_domain, GFP_KERNEL, node);
                /*
                 * For legacy IRQ's, start with assigning irq0 to irq15 to
                 * IRQ0_VECTOR to IRQ15_VECTOR on cpu 0.
@@ -183,170 +178,88 @@ int __init arch_early_irq_init(void)
 }
 
 #ifdef CONFIG_SPARSE_IRQ
-struct irq_cfg *irq_cfg(unsigned int irq)
+static struct irq_cfg *irq_cfg(unsigned int irq)
 {
-       struct irq_cfg *cfg = NULL;
-       struct irq_desc *desc;
-
-       desc = irq_to_desc(irq);
-       if (desc)
-               cfg = desc->chip_data;
-
-       return cfg;
+       return get_irq_chip_data(irq);
 }
 
-static struct irq_cfg *get_one_free_irq_cfg(int node)
+static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
 {
        struct irq_cfg *cfg;
 
-       cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node);
-       if (cfg) {
-               if (!zalloc_cpumask_var_node(&cfg->domain, GFP_ATOMIC, node)) {
-                       kfree(cfg);
-                       cfg = NULL;
-               } else if (!zalloc_cpumask_var_node(&cfg->old_domain,
-                                                         GFP_ATOMIC, node)) {
-                       free_cpumask_var(cfg->domain);
-                       kfree(cfg);
-                       cfg = NULL;
-               }
-       }
-
+       cfg = kzalloc_node(sizeof(*cfg), GFP_KERNEL, node);
+       if (!cfg)
+               return NULL;
+       if (!zalloc_cpumask_var_node(&cfg->domain, GFP_KERNEL, node))
+               goto out_cfg;
+       if (!zalloc_cpumask_var_node(&cfg->old_domain, GFP_KERNEL, node))
+               goto out_domain;
        return cfg;
+out_domain:
+       free_cpumask_var(cfg->domain);
+out_cfg:
+       kfree(cfg);
+       return NULL;
 }
 
-int arch_init_chip_data(struct irq_desc *desc, int node)
-{
-       struct irq_cfg *cfg;
-
-       cfg = desc->chip_data;
-       if (!cfg) {
-               desc->chip_data = get_one_free_irq_cfg(node);
-               if (!desc->chip_data) {
-                       printk(KERN_ERR "can not alloc irq_cfg\n");
-                       BUG_ON(1);
-               }
-       }
-
-       return 0;
-}
-
-/* for move_irq_desc */
-static void
-init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int node)
+static void free_irq_cfg(unsigned int at, struct irq_cfg *cfg)
 {
-       struct irq_pin_list *old_entry, *head, *tail, *entry;
-
-       cfg->irq_2_pin = NULL;
-       old_entry = old_cfg->irq_2_pin;
-       if (!old_entry)
-               return;
-
-       entry = get_one_free_irq_2_pin(node);
-       if (!entry)
+       if (!cfg)
                return;
+       set_irq_chip_data(at, NULL);
+       free_cpumask_var(cfg->domain);
+       free_cpumask_var(cfg->old_domain);
+       kfree(cfg);
+}
 
-       entry->apic     = old_entry->apic;
-       entry->pin      = old_entry->pin;
-       head            = entry;
-       tail            = entry;
-       old_entry       = old_entry->next;
-       while (old_entry) {
-               entry = get_one_free_irq_2_pin(node);
-               if (!entry) {
-                       entry = head;
-                       while (entry) {
-                               head = entry->next;
-                               kfree(entry);
-                               entry = head;
-                       }
-                       /* still use the old one */
-                       return;
-               }
-               entry->apic     = old_entry->apic;
-               entry->pin      = old_entry->pin;
-               tail->next      = entry;
-               tail            = entry;
-               old_entry       = old_entry->next;
-       }
+#else
 
-       tail->next = NULL;
-       cfg->irq_2_pin = head;
+struct irq_cfg *irq_cfg(unsigned int irq)
+{
+       return irq < nr_irqs ? irq_cfgx + irq : NULL;
 }
 
-static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg)
+static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
 {
-       struct irq_pin_list *entry, *next;
-
-       if (old_cfg->irq_2_pin == cfg->irq_2_pin)
-               return;
+       return irq_cfgx + irq;
+}
 
-       entry = old_cfg->irq_2_pin;
+static inline void free_irq_cfg(unsigned int at, struct irq_cfg *cfg) { }
 
-       while (entry) {
-               next = entry->next;
-               kfree(entry);
-               entry = next;
-       }
-       old_cfg->irq_2_pin = NULL;
-}
+#endif
 
-void arch_init_copy_chip_data(struct irq_desc *old_desc,
-                                struct irq_desc *desc, int node)
+static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)
 {
+       int res = irq_alloc_desc_at(at, node);
        struct irq_cfg *cfg;
-       struct irq_cfg *old_cfg;
-
-       cfg = get_one_free_irq_cfg(node);
 
-       if (!cfg)
-               return;
-
-       desc->chip_data = cfg;
-
-       old_cfg = old_desc->chip_data;
-
-       cfg->vector = old_cfg->vector;
-       cfg->move_in_progress = old_cfg->move_in_progress;
-       cpumask_copy(cfg->domain, old_cfg->domain);
-       cpumask_copy(cfg->old_domain, old_cfg->old_domain);
-
-       init_copy_irq_2_pin(old_cfg, cfg, node);
-}
+       if (res < 0) {
+               if (res != -EEXIST)
+                       return NULL;
+               cfg = get_irq_chip_data(at);
+               if (cfg)
+                       return cfg;
+       }
 
-static void free_irq_cfg(struct irq_cfg *cfg)
-{
-       free_cpumask_var(cfg->domain);
-       free_cpumask_var(cfg->old_domain);
-       kfree(cfg);
+       cfg = alloc_irq_cfg(at, node);
+       if (cfg)
+               set_irq_chip_data(at, cfg);
+       else
+               irq_free_desc(at);
+       return cfg;
 }
 
-void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
+static int alloc_irq_from(unsigned int from, int node)
 {
-       struct irq_cfg *old_cfg, *cfg;
-
-       old_cfg = old_desc->chip_data;
-       cfg = desc->chip_data;
-
-       if (old_cfg == cfg)
-               return;
-
-       if (old_cfg) {
-               free_irq_2_pin(old_cfg, cfg);
-               free_irq_cfg(old_cfg);
-               old_desc->chip_data = NULL;
-       }
+       return irq_alloc_desc_from(from, node);
 }
-/* end for move_irq_desc */
 
-#else
-struct irq_cfg *irq_cfg(unsigned int irq)
+static void free_irq_at(unsigned int at, struct irq_cfg *cfg)
 {
-       return irq < nr_irqs ? irq_cfgx + irq : NULL;
+       free_irq_cfg(at, cfg);
+       irq_free_desc(at);
 }
 
-#endif
-
 struct io_apic {
        unsigned int index;
        unsigned int unused[3];
@@ -451,7 +364,7 @@ __ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
        io_apic_write(apic, 0x10 + 2*pin, eu.w1);
 }
 
-void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
+static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
 {
        unsigned long flags;
        raw_spin_lock_irqsave(&ioapic_lock, flags);
@@ -481,7 +394,7 @@ static void ioapic_mask_entry(int apic, int pin)
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
 static int
-add_pin_to_irq_node_nopanic(struct irq_cfg *cfg, int node, int apic, int pin)
+__add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
 {
        struct irq_pin_list **last, *entry;
 
@@ -493,7 +406,7 @@ add_pin_to_irq_node_nopanic(struct irq_cfg *cfg, int node, int apic, int pin)
                last = &entry->next;
        }
 
-       entry = get_one_free_irq_2_pin(node);
+       entry = alloc_irq_pin_list(node);
        if (!entry) {
                printk(KERN_ERR "can not alloc irq_pin_list (%d,%d,%d)\n",
                                node, apic, pin);
@@ -508,7 +421,7 @@ add_pin_to_irq_node_nopanic(struct irq_cfg *cfg, int node, int apic, int pin)
 
 static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
 {
-       if (add_pin_to_irq_node_nopanic(cfg, node, apic, pin))
+       if (__add_pin_to_irq_node(cfg, node, apic, pin))
                panic("IO-APIC: failed to add irq-pin. Can not proceed\n");
 }
 
@@ -571,11 +484,6 @@ static void __unmask_and_level_IO_APIC_irq(struct irq_pin_list *entry)
                             IO_APIC_REDIR_LEVEL_TRIGGER, NULL);
 }
 
-static void __unmask_IO_APIC_irq(struct irq_cfg *cfg)
-{
-       io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL);
-}
-
 static void io_apic_sync(struct irq_pin_list *entry)
 {
        /*
@@ -587,44 +495,37 @@ static void io_apic_sync(struct irq_pin_list *entry)
        readl(&io_apic->data);
 }
 
-static void __mask_IO_APIC_irq(struct irq_cfg *cfg)
+static void mask_ioapic(struct irq_cfg *cfg)
 {
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&ioapic_lock, flags);
        io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
+       raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void mask_IO_APIC_irq_desc(struct irq_desc *desc)
+static void mask_ioapic_irq(struct irq_data *data)
 {
-       struct irq_cfg *cfg = desc->chip_data;
-       unsigned long flags;
-
-       BUG_ON(!cfg);
+       mask_ioapic(data->chip_data);
+}
 
-       raw_spin_lock_irqsave(&ioapic_lock, flags);
-       __mask_IO_APIC_irq(cfg);
-       raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+static void __unmask_ioapic(struct irq_cfg *cfg)
+{
+       io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL);
 }
 
-static void unmask_IO_APIC_irq_desc(struct irq_desc *desc)
+static void unmask_ioapic(struct irq_cfg *cfg)
 {
-       struct irq_cfg *cfg = desc->chip_data;
        unsigned long flags;
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
-       __unmask_IO_APIC_irq(cfg);
+       __unmask_ioapic(cfg);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void mask_IO_APIC_irq(unsigned int irq)
+static void unmask_ioapic_irq(struct irq_data *data)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       mask_IO_APIC_irq_desc(desc);
-}
-static void unmask_IO_APIC_irq(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       unmask_IO_APIC_irq_desc(desc);
+       unmask_ioapic(data->chip_data);
 }
 
 static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
@@ -694,14 +595,14 @@ struct IO_APIC_route_entry **alloc_ioapic_entries(void)
        struct IO_APIC_route_entry **ioapic_entries;
 
        ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
-                               GFP_ATOMIC);
+                               GFP_KERNEL);
        if (!ioapic_entries)
                return 0;
 
        for (apic = 0; apic < nr_ioapics; apic++) {
                ioapic_entries[apic] =
                        kzalloc(sizeof(struct IO_APIC_route_entry) *
-                               nr_ioapic_registers[apic], GFP_ATOMIC);
+                               nr_ioapic_registers[apic], GFP_KERNEL);
                if (!ioapic_entries[apic])
                        goto nomem;
        }
@@ -1259,7 +1160,6 @@ void __setup_vector_irq(int cpu)
        /* Initialize vector_irq on a new cpu */
        int irq, vector;
        struct irq_cfg *cfg;
-       struct irq_desc *desc;
 
        /*
         * vector_lock will make sure that we don't run into irq vector
@@ -1268,9 +1168,10 @@ void __setup_vector_irq(int cpu)
         */
        raw_spin_lock(&vector_lock);
        /* Mark the inuse vectors */
-       for_each_irq_desc(irq, desc) {
-               cfg = desc->chip_data;
-
+       for_each_active_irq(irq) {
+               cfg = get_irq_chip_data(irq);
+               if (!cfg)
+                       continue;
                /*
                 * If it is a legacy IRQ handled by the legacy PIC, this cpu
                 * will be part of the irq_cfg's domain.
@@ -1327,17 +1228,17 @@ static inline int IO_APIC_irq_trigger(int irq)
 }
 #endif
 
-static void ioapic_register_intr(int irq, struct irq_desc *desc, unsigned long trigger)
+static void ioapic_register_intr(unsigned int irq, unsigned long trigger)
 {
 
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
            trigger == IOAPIC_LEVEL)
-               desc->status |= IRQ_LEVEL;
+               irq_set_status_flags(irq, IRQ_LEVEL);
        else
-               desc->status &= ~IRQ_LEVEL;
+               irq_clear_status_flags(irq, IRQ_LEVEL);
 
-       if (irq_remapped(irq)) {
-               desc->status |= IRQ_MOVE_PCNTXT;
+       if (irq_remapped(get_irq_chip_data(irq))) {
+               irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
                if (trigger)
                        set_irq_chip_and_handler_name(irq, &ir_ioapic_chip,
                                                      handle_fasteoi_irq,
@@ -1358,10 +1259,10 @@ static void ioapic_register_intr(int irq, struct irq_desc *desc, unsigned long t
                                              handle_edge_irq, "edge");
 }
 
-int setup_ioapic_entry(int apic_id, int irq,
-                      struct IO_APIC_route_entry *entry,
-                      unsigned int destination, int trigger,
-                      int polarity, int vector, int pin)
+static int setup_ioapic_entry(int apic_id, int irq,
+                             struct IO_APIC_route_entry *entry,
+                             unsigned int destination, int trigger,
+                             int polarity, int vector, int pin)
 {
        /*
         * add it to the IO-APIC irq-routing table:
@@ -1382,21 +1283,7 @@ int setup_ioapic_entry(int apic_id, int irq,
                if (index < 0)
                        panic("Failed to allocate IRTE for ioapic %d\n", apic_id);
 
-               memset(&irte, 0, sizeof(irte));
-
-               irte.present = 1;
-               irte.dst_mode = apic->irq_dest_mode;
-               /*
-                * Trigger mode in the IRTE will always be edge, and the
-                * actual level or edge trigger will be setup in the IO-APIC
-                * RTE. This will help simplify level triggered irq migration.
-                * For more details, see the comments above explainig IO-APIC
-                * irq migration in the presence of interrupt-remapping.
-                */
-               irte.trigger_mode = 0;
-               irte.dlvry_mode = apic->irq_delivery_mode;
-               irte.vector = vector;
-               irte.dest_id = IRTE_DEST(destination);
+               prepare_irte(&irte, vector, destination);
 
                /* Set source-id of interrupt request */
                set_ioapic_sid(&irte, apic_id);
@@ -1431,18 +1318,14 @@ int setup_ioapic_entry(int apic_id, int irq,
        return 0;
 }
 
-static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq_desc *desc,
-                             int trigger, int polarity)
+static void setup_ioapic_irq(int apic_id, int pin, unsigned int irq,
+                            struct irq_cfg *cfg, int trigger, int polarity)
 {
-       struct irq_cfg *cfg;
        struct IO_APIC_route_entry entry;
        unsigned int dest;
 
        if (!IO_APIC_IRQ(irq))
                return;
-
-       cfg = desc->chip_data;
-
        /*
         * For legacy irqs, cfg->domain starts with cpu 0 for legacy
         * controllers like 8259. Now that IO-APIC can handle this irq, update
@@ -1471,9 +1354,9 @@ static void setup_IO_APIC_irq(int apic_id, int pin, unsigned int irq, struct irq
                return;
        }
 
-       ioapic_register_intr(irq, desc, trigger);
+       ioapic_register_intr(irq, trigger);
        if (irq < legacy_pic->nr_legacy_irqs)
-               legacy_pic->chip->mask(irq);
+               legacy_pic->mask(irq);
 
        ioapic_write_entry(apic_id, pin, entry);
 }
@@ -1484,11 +1367,9 @@ static struct {
 
 static void __init setup_IO_APIC_irqs(void)
 {
-       int apic_id, pin, idx, irq;
-       int notcon = 0;
-       struct irq_desc *desc;
+       int apic_id, pin, idx, irq, notcon = 0;
+       int node = cpu_to_node(0);
        struct irq_cfg *cfg;
-       int node = cpu_to_node(boot_cpu_id);
 
        apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
 
@@ -1525,19 +1406,17 @@ static void __init setup_IO_APIC_irqs(void)
                                apic->multi_timer_check(apic_id, irq))
                        continue;
 
-               desc = irq_to_desc_alloc_node(irq, node);
-               if (!desc) {
-                       printk(KERN_INFO "can not get irq_desc for %d\n", irq);
+               cfg = alloc_irq_and_cfg_at(irq, node);
+               if (!cfg)
                        continue;
-               }
-               cfg = desc->chip_data;
+
                add_pin_to_irq_node(cfg, node, apic_id, pin);
                /*
                 * don't mark it in pin_programmed, so later acpi could
                 * set it correctly when irq < 16
                 */
-               setup_IO_APIC_irq(apic_id, pin, irq, desc,
-                               irq_trigger(idx), irq_polarity(idx));
+               setup_ioapic_irq(apic_id, pin, irq, cfg, irq_trigger(idx),
+                                 irq_polarity(idx));
        }
 
        if (notcon)
@@ -1552,9 +1431,7 @@ static void __init setup_IO_APIC_irqs(void)
  */
 void setup_IO_APIC_irq_extra(u32 gsi)
 {
-       int apic_id = 0, pin, idx, irq;
-       int node = cpu_to_node(boot_cpu_id);
-       struct irq_desc *desc;
+       int apic_id = 0, pin, idx, irq, node = cpu_to_node(0);
        struct irq_cfg *cfg;
 
        /*
@@ -1570,18 +1447,15 @@ void setup_IO_APIC_irq_extra(u32 gsi)
                return;
 
        irq = pin_2_irq(idx, apic_id, pin);
-#ifdef CONFIG_SPARSE_IRQ
-       desc = irq_to_desc(irq);
-       if (desc)
+
+       /* Only handle the non legacy irqs on secondary ioapics */
+       if (apic_id == 0 || irq < NR_IRQS_LEGACY)
                return;
-#endif
-       desc = irq_to_desc_alloc_node(irq, node);
-       if (!desc) {
-               printk(KERN_INFO "can not get irq_desc for %d\n", irq);
+
+       cfg = alloc_irq_and_cfg_at(irq, node);
+       if (!cfg)
                return;
-       }
 
-       cfg = desc->chip_data;
        add_pin_to_irq_node(cfg, node, apic_id, pin);
 
        if (test_bit(pin, mp_ioapic_routing[apic_id].pin_programmed)) {
@@ -1591,7 +1465,7 @@ void setup_IO_APIC_irq_extra(u32 gsi)
        }
        set_bit(pin, mp_ioapic_routing[apic_id].pin_programmed);
 
-       setup_IO_APIC_irq(apic_id, pin, irq, desc,
+       setup_ioapic_irq(apic_id, pin, irq, cfg,
                        irq_trigger(idx), irq_polarity(idx));
 }
 
@@ -1642,7 +1516,6 @@ __apicdebuginit(void) print_IO_APIC(void)
        union IO_APIC_reg_03 reg_03;
        unsigned long flags;
        struct irq_cfg *cfg;
-       struct irq_desc *desc;
        unsigned int irq;
 
        printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
@@ -1729,10 +1602,10 @@ __apicdebuginit(void) print_IO_APIC(void)
        }
        }
        printk(KERN_DEBUG "IRQ to pin mappings:\n");
-       for_each_irq_desc(irq, desc) {
+       for_each_active_irq(irq) {
                struct irq_pin_list *entry;
 
-               cfg = desc->chip_data;
+               cfg = get_irq_chip_data(irq);
                if (!cfg)
                        continue;
                entry = cfg->irq_2_pin;
@@ -2239,29 +2112,26 @@ static int __init timer_irq_works(void)
  * an edge even if it isn't on the 8259A...
  */
 
-static unsigned int startup_ioapic_irq(unsigned int irq)
+static unsigned int startup_ioapic_irq(struct irq_data *data)
 {
-       int was_pending = 0;
+       int was_pending = 0, irq = data->irq;
        unsigned long flags;
-       struct irq_cfg *cfg;
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
        if (irq < legacy_pic->nr_legacy_irqs) {
-               legacy_pic->chip->mask(irq);
+               legacy_pic->mask(irq);
                if (legacy_pic->irq_pending(irq))
                        was_pending = 1;
        }
-       cfg = irq_cfg(irq);
-       __unmask_IO_APIC_irq(cfg);
+       __unmask_ioapic(data->chip_data);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 
        return was_pending;
 }
 
-static int ioapic_retrigger_irq(unsigned int irq)
+static int ioapic_retrigger_irq(struct irq_data *data)
 {
-
-       struct irq_cfg *cfg = irq_cfg(irq);
+       struct irq_cfg *cfg = data->chip_data;
        unsigned long flags;
 
        raw_spin_lock_irqsave(&vector_lock, flags);
@@ -2312,7 +2182,7 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq
                 * With interrupt-remapping, destination information comes
                 * from interrupt-remapping table entry.
                 */
-               if (!irq_remapped(irq))
+               if (!irq_remapped(cfg))
                        io_apic_write(apic, 0x11 + pin*2, dest);
                reg = io_apic_read(apic, 0x10 + pin*2);
                reg &= ~IO_APIC_REDIR_VECTOR_MASK;
@@ -2322,65 +2192,46 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq
 }
 
 /*
- * Either sets desc->affinity to a valid value, and returns
+ * Either sets data->affinity to a valid value, and returns
  * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
- * leaves desc->affinity untouched.
+ * leaves data->affinity untouched.
  */
-unsigned int
-set_desc_affinity(struct irq_desc *desc, const struct cpumask *mask,
-                 unsigned int *dest_id)
+int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+                         unsigned int *dest_id)
 {
-       struct irq_cfg *cfg;
-       unsigned int irq;
+       struct irq_cfg *cfg = data->chip_data;
 
        if (!cpumask_intersects(mask, cpu_online_mask))
                return -1;
 
-       irq = desc->irq;
-       cfg = desc->chip_data;
-       if (assign_irq_vector(irq, cfg, mask))
+       if (assign_irq_vector(data->irq, data->chip_data, mask))
                return -1;
 
-       cpumask_copy(desc->affinity, mask);
+       cpumask_copy(data->affinity, mask);
 
-       *dest_id = apic->cpu_mask_to_apicid_and(desc->affinity, cfg->domain);
+       *dest_id = apic->cpu_mask_to_apicid_and(mask, cfg->domain);
        return 0;
 }
 
 static int
-set_ioapic_affinity_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
+ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+                   bool force)
 {
-       struct irq_cfg *cfg;
+       unsigned int dest, irq = data->irq;
        unsigned long flags;
-       unsigned int dest;
-       unsigned int irq;
-       int ret = -1;
-
-       irq = desc->irq;
-       cfg = desc->chip_data;
+       int ret;
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
-       ret = set_desc_affinity(desc, mask, &dest);
+       ret = __ioapic_set_affinity(data, mask, &dest);
        if (!ret) {
                /* Only the high 8 bits are valid. */
                dest = SET_APIC_LOGICAL_ID(dest);
-               __target_IO_APIC_irq(irq, dest, cfg);
+               __target_IO_APIC_irq(irq, dest, data->chip_data);
        }
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
-
        return ret;
 }
 
-static int
-set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask)
-{
-       struct irq_desc *desc;
-
-       desc = irq_to_desc(irq);
-
-       return set_ioapic_affinity_irq_desc(desc, mask);
-}
-
 #ifdef CONFIG_INTR_REMAP
 
 /*
@@ -2395,24 +2246,21 @@ set_ioapic_affinity_irq(unsigned int irq, const struct cpumask *mask)
  * the interrupt-remapping table entry.
  */
 static int
-migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
+ir_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+                      bool force)
 {
-       struct irq_cfg *cfg;
+       struct irq_cfg *cfg = data->chip_data;
+       unsigned int dest, irq = data->irq;
        struct irte irte;
-       unsigned int dest;
-       unsigned int irq;
-       int ret = -1;
 
        if (!cpumask_intersects(mask, cpu_online_mask))
-               return ret;
+               return -EINVAL;
 
-       irq = desc->irq;
        if (get_irte(irq, &irte))
-               return ret;
+               return -EBUSY;
 
-       cfg = desc->chip_data;
        if (assign_irq_vector(irq, cfg, mask))
-               return ret;
+               return -EBUSY;
 
        dest = apic->cpu_mask_to_apicid_and(cfg->domain, mask);
 
@@ -2427,29 +2275,14 @@ migrate_ioapic_irq_desc(struct irq_desc *desc, const struct cpumask *mask)
        if (cfg->move_in_progress)
                send_cleanup_vector(cfg);
 
-       cpumask_copy(desc->affinity, mask);
-
+       cpumask_copy(data->affinity, mask);
        return 0;
 }
 
-/*
- * Migrates the IRQ destination in the process context.
- */
-static int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
-                                           const struct cpumask *mask)
-{
-       return migrate_ioapic_irq_desc(desc, mask);
-}
-static int set_ir_ioapic_affinity_irq(unsigned int irq,
-                                      const struct cpumask *mask)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       return set_ir_ioapic_affinity_irq_desc(desc, mask);
-}
 #else
-static inline int set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc,
-                                                  const struct cpumask *mask)
+static inline int
+ir_ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
+                      bool force)
 {
        return 0;
 }
@@ -2511,10 +2344,8 @@ unlock:
        irq_exit();
 }
 
-static void __irq_complete_move(struct irq_desc **descp, unsigned vector)
+static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
 {
-       struct irq_desc *desc = *descp;
-       struct irq_cfg *cfg = desc->chip_data;
        unsigned me;
 
        if (likely(!cfg->move_in_progress))
@@ -2526,31 +2357,28 @@ static void __irq_complete_move(struct irq_desc **descp, unsigned vector)
                send_cleanup_vector(cfg);
 }
 
-static void irq_complete_move(struct irq_desc **descp)
+static void irq_complete_move(struct irq_cfg *cfg)
 {
-       __irq_complete_move(descp, ~get_irq_regs()->orig_ax);
+       __irq_complete_move(cfg, ~get_irq_regs()->orig_ax);
 }
 
 void irq_force_complete_move(int irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_cfg *cfg = desc->chip_data;
+       struct irq_cfg *cfg = get_irq_chip_data(irq);
 
        if (!cfg)
                return;
 
-       __irq_complete_move(&desc, cfg->vector);
+       __irq_complete_move(cfg, cfg->vector);
 }
 #else
-static inline void irq_complete_move(struct irq_desc **descp) {}
+static inline void irq_complete_move(struct irq_cfg *cfg) { }
 #endif
 
-static void ack_apic_edge(unsigned int irq)
+static void ack_apic_edge(struct irq_data *data)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       irq_complete_move(&desc);
-       move_native_irq(irq);
+       irq_complete_move(data->chip_data);
+       move_native_irq(data->irq);
        ack_APIC_irq();
 }
 
@@ -2572,10 +2400,12 @@ atomic_t irq_mis_count;
  * Otherwise, we simulate the EOI message manually by changing the trigger
  * mode to edge and then back to level, with RTE being masked during this.
 */
-static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
+static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
 {
        struct irq_pin_list *entry;
+       unsigned long flags;
 
+       raw_spin_lock_irqsave(&ioapic_lock, flags);
        for_each_irq_pin(entry, cfg->irq_2_pin) {
                if (mp_ioapics[entry->apic].apicver >= 0x20) {
                        /*
@@ -2584,7 +2414,7 @@ static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
                         * intr-remapping table entry. Hence for the io-apic
                         * EOI we use the pin number.
                         */
-                       if (irq_remapped(irq))
+                       if (irq_remapped(cfg))
                                io_apic_eoi(entry->apic, entry->pin);
                        else
                                io_apic_eoi(entry->apic, cfg->vector);
@@ -2593,36 +2423,22 @@ static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
                        __unmask_and_level_IO_APIC_irq(entry);
                }
        }
-}
-
-static void eoi_ioapic_irq(struct irq_desc *desc)
-{
-       struct irq_cfg *cfg;
-       unsigned long flags;
-       unsigned int irq;
-
-       irq = desc->irq;
-       cfg = desc->chip_data;
-
-       raw_spin_lock_irqsave(&ioapic_lock, flags);
-       __eoi_ioapic_irq(irq, cfg);
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-static void ack_apic_level(unsigned int irq)
+static void ack_apic_level(struct irq_data *data)
 {
+       struct irq_cfg *cfg = data->chip_data;
+       int i, do_unmask_irq = 0, irq = data->irq;
        struct irq_desc *desc = irq_to_desc(irq);
        unsigned long v;
-       int i;
-       struct irq_cfg *cfg;
-       int do_unmask_irq = 0;
 
-       irq_complete_move(&desc);
+       irq_complete_move(cfg);
 #ifdef CONFIG_GENERIC_PENDING_IRQ
        /* If we are moving the irq we need to mask it */
        if (unlikely(desc->status & IRQ_MOVE_PENDING)) {
                do_unmask_irq = 1;
-               mask_IO_APIC_irq_desc(desc);
+               mask_ioapic(cfg);
        }
 #endif
 
@@ -2658,7 +2474,6 @@ static void ack_apic_level(unsigned int irq)
         * we use the above logic (mask+edge followed by unmask+level) from
         * Manfred Spraul to clear the remote IRR.
         */
-       cfg = desc->chip_data;
        i = cfg->vector;
        v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
 
@@ -2678,7 +2493,7 @@ static void ack_apic_level(unsigned int irq)
        if (!(v & (1 << (i & 0x1f)))) {
                atomic_inc(&irq_mis_count);
 
-               eoi_ioapic_irq(desc);
+               eoi_ioapic_irq(irq, cfg);
        }
 
        /* Now we can move and renable the irq */
@@ -2709,61 +2524,57 @@ static void ack_apic_level(unsigned int irq)
                 * accurate and is causing problems then it is a hardware bug
                 * and you can go talk to the chipset vendor about it.
                 */
-               cfg = desc->chip_data;
                if (!io_apic_level_ack_pending(cfg))
                        move_masked_irq(irq);
-               unmask_IO_APIC_irq_desc(desc);
+               unmask_ioapic(cfg);
        }
 }
 
 #ifdef CONFIG_INTR_REMAP
-static void ir_ack_apic_edge(unsigned int irq)
+static void ir_ack_apic_edge(struct irq_data *data)
 {
        ack_APIC_irq();
 }
 
-static void ir_ack_apic_level(unsigned int irq)
+static void ir_ack_apic_level(struct irq_data *data)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-
        ack_APIC_irq();
-       eoi_ioapic_irq(desc);
+       eoi_ioapic_irq(data->irq, data->chip_data);
 }
 #endif /* CONFIG_INTR_REMAP */
 
 static struct irq_chip ioapic_chip __read_mostly = {
-       .name           = "IO-APIC",
-       .startup        = startup_ioapic_irq,
-       .mask           = mask_IO_APIC_irq,
-       .unmask         = unmask_IO_APIC_irq,
-       .ack            = ack_apic_edge,
-       .eoi            = ack_apic_level,
+       .name                   = "IO-APIC",
+       .irq_startup            = startup_ioapic_irq,
+       .irq_mask               = mask_ioapic_irq,
+       .irq_unmask             = unmask_ioapic_irq,
+       .irq_ack                = ack_apic_edge,
+       .irq_eoi                = ack_apic_level,
 #ifdef CONFIG_SMP
-       .set_affinity   = set_ioapic_affinity_irq,
+       .irq_set_affinity       = ioapic_set_affinity,
 #endif
-       .retrigger      = ioapic_retrigger_irq,
+       .irq_retrigger          = ioapic_retrigger_irq,
 };
 
 static struct irq_chip ir_ioapic_chip __read_mostly = {
-       .name           = "IR-IO-APIC",
-       .startup        = startup_ioapic_irq,
-       .mask           = mask_IO_APIC_irq,
-       .unmask         = unmask_IO_APIC_irq,
+       .name                   = "IR-IO-APIC",
+       .irq_startup            = startup_ioapic_irq,
+       .irq_mask               = mask_ioapic_irq,
+       .irq_unmask             = unmask_ioapic_irq,
 #ifdef CONFIG_INTR_REMAP
-       .ack            = ir_ack_apic_edge,
-       .eoi            = ir_ack_apic_level,
+       .irq_ack                = ir_ack_apic_edge,
+       .irq_eoi                = ir_ack_apic_level,
 #ifdef CONFIG_SMP
-       .set_affinity   = set_ir_ioapic_affinity_irq,
+       .irq_set_affinity       = ir_ioapic_set_affinity,
 #endif
 #endif
-       .retrigger      = ioapic_retrigger_irq,
+       .irq_retrigger          = ioapic_retrigger_irq,
 };
 
 static inline void init_IO_APIC_traps(void)
 {
-       int irq;
-       struct irq_desc *desc;
        struct irq_cfg *cfg;
+       unsigned int irq;
 
        /*
         * NOTE! The local APIC isn't very good at handling
@@ -2776,8 +2587,8 @@ static inline void init_IO_APIC_traps(void)
         * Also, we've got to be careful not to trash gate
         * 0x80, because int 0x80 is hm, kind of importantish. ;)
         */
-       for_each_irq_desc(irq, desc) {
-               cfg = desc->chip_data;
+       for_each_active_irq(irq) {
+               cfg = get_irq_chip_data(irq);
                if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) {
                        /*
                         * Hmm.. We don't have an entry for this,
@@ -2788,7 +2599,7 @@ static inline void init_IO_APIC_traps(void)
                                legacy_pic->make_irq(irq);
                        else
                                /* Strange. Oh, well.. */
-                               desc->chip = &no_irq_chip;
+                               set_irq_chip(irq, &no_irq_chip);
                }
        }
 }
@@ -2797,7 +2608,7 @@ static inline void init_IO_APIC_traps(void)
  * The local APIC irq-chip implementation:
  */
 
-static void mask_lapic_irq(unsigned int irq)
+static void mask_lapic_irq(struct irq_data *data)
 {
        unsigned long v;
 
@@ -2805,7 +2616,7 @@ static void mask_lapic_irq(unsigned int irq)
        apic_write(APIC_LVT0, v | APIC_LVT_MASKED);
 }
 
-static void unmask_lapic_irq(unsigned int irq)
+static void unmask_lapic_irq(struct irq_data *data)
 {
        unsigned long v;
 
@@ -2813,21 +2624,21 @@ static void unmask_lapic_irq(unsigned int irq)
        apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED);
 }
 
-static void ack_lapic_irq(unsigned int irq)
+static void ack_lapic_irq(struct irq_data *data)
 {
        ack_APIC_irq();
 }
 
 static struct irq_chip lapic_chip __read_mostly = {
        .name           = "local-APIC",
-       .mask           = mask_lapic_irq,
-       .unmask         = unmask_lapic_irq,
-       .ack            = ack_lapic_irq,
+       .irq_mask       = mask_lapic_irq,
+       .irq_unmask     = unmask_lapic_irq,
+       .irq_ack        = ack_lapic_irq,
 };
 
-static void lapic_register_intr(int irq, struct irq_desc *desc)
+static void lapic_register_intr(int irq)
 {
-       desc->status &= ~IRQ_LEVEL;
+       irq_clear_status_flags(irq, IRQ_LEVEL);
        set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
                                      "edge");
 }
@@ -2930,9 +2741,8 @@ int timer_through_8259 __initdata;
  */
 static inline void __init check_timer(void)
 {
-       struct irq_desc *desc = irq_to_desc(0);
-       struct irq_cfg *cfg = desc->chip_data;
-       int node = cpu_to_node(boot_cpu_id);
+       struct irq_cfg *cfg = get_irq_chip_data(0);
+       int node = cpu_to_node(0);
        int apic1, pin1, apic2, pin2;
        unsigned long flags;
        int no_pin1 = 0;
@@ -2942,7 +2752,7 @@ static inline void __init check_timer(void)
        /*
         * get/set the timer IRQ vector:
         */
-       legacy_pic->chip->mask(0);
+       legacy_pic->mask(0);
        assign_irq_vector(0, cfg, apic->target_cpus());
 
        /*
@@ -3001,7 +2811,7 @@ static inline void __init check_timer(void)
                        add_pin_to_irq_node(cfg, node, apic1, pin1);
                        setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
                } else {
-                       /* for edge trigger, setup_IO_APIC_irq already
+                       /* for edge trigger, setup_ioapic_irq already
                         * leave it unmasked.
                         * so only need to unmask if it is level-trigger
                         * do we really have level trigger timer?
@@ -3009,12 +2819,12 @@ static inline void __init check_timer(void)
                        int idx;
                        idx = find_irq_entry(apic1, pin1, mp_INT);
                        if (idx != -1 && irq_trigger(idx))
-                               unmask_IO_APIC_irq_desc(desc);
+                               unmask_ioapic(cfg);
                }
                if (timer_irq_works()) {
                        if (nmi_watchdog == NMI_IO_APIC) {
                                setup_nmi();
-                               legacy_pic->chip->unmask(0);
+                               legacy_pic->unmask(0);
                        }
                        if (disable_timer_pin_1 > 0)
                                clear_IO_APIC_pin(0, pin1);
@@ -3037,14 +2847,14 @@ static inline void __init check_timer(void)
                 */
                replace_pin_at_irq_node(cfg, node, apic1, pin1, apic2, pin2);
                setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
-               legacy_pic->chip->unmask(0);
+               legacy_pic->unmask(0);
                if (timer_irq_works()) {
                        apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
                        timer_through_8259 = 1;
                        if (nmi_watchdog == NMI_IO_APIC) {
-                               legacy_pic->chip->mask(0);
+                               legacy_pic->mask(0);
                                setup_nmi();
-                               legacy_pic->chip->unmask(0);
+                               legacy_pic->unmask(0);
                        }
                        goto out;
                }
@@ -3052,7 +2862,7 @@ static inline void __init check_timer(void)
                 * Cleanup, just in case ...
                 */
                local_irq_disable();
-               legacy_pic->chip->mask(0);
+               legacy_pic->mask(0);
                clear_IO_APIC_pin(apic2, pin2);
                apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n");
        }
@@ -3069,16 +2879,16 @@ static inline void __init check_timer(void)
        apic_printk(APIC_QUIET, KERN_INFO
                    "...trying to set up timer as Virtual Wire IRQ...\n");
 
-       lapic_register_intr(0, desc);
+       lapic_register_intr(0);
        apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector);     /* Fixed mode */
-       legacy_pic->chip->unmask(0);
+       legacy_pic->unmask(0);
 
        if (timer_irq_works()) {
                apic_printk(APIC_QUIET, KERN_INFO "..... works.\n");
                goto out;
        }
        local_irq_disable();
-       legacy_pic->chip->mask(0);
+       legacy_pic->mask(0);
        apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
        apic_printk(APIC_QUIET, KERN_INFO "..... failed.\n");
 
@@ -3244,49 +3054,42 @@ device_initcall(ioapic_init_sysfs);
 /*
  * Dynamic irq allocate and deallocation
  */
-unsigned int create_irq_nr(unsigned int irq_want, int node)
+unsigned int create_irq_nr(unsigned int from, int node)
 {
-       /* Allocate an unused irq */
-       unsigned int irq;
-       unsigned int new;
+       struct irq_cfg *cfg;
        unsigned long flags;
-       struct irq_cfg *cfg_new = NULL;
-       struct irq_desc *desc_new = NULL;
-
-       irq = 0;
-       if (irq_want < nr_irqs_gsi)
-               irq_want = nr_irqs_gsi;
-
-       raw_spin_lock_irqsave(&vector_lock, flags);
-       for (new = irq_want; new < nr_irqs; new++) {
-               desc_new = irq_to_desc_alloc_node(new, node);
-               if (!desc_new) {
-                       printk(KERN_INFO "can not get irq_desc for %d\n", new);
-                       continue;
-               }
-               cfg_new = desc_new->chip_data;
-
-               if (cfg_new->vector != 0)
-                       continue;
+       unsigned int ret = 0;
+       int irq;
 
-               desc_new = move_irq_desc(desc_new, node);
-               cfg_new = desc_new->chip_data;
+       if (from < nr_irqs_gsi)
+               from = nr_irqs_gsi;
 
-               if (__assign_irq_vector(new, cfg_new, apic->target_cpus()) == 0)
-                       irq = new;
-               break;
+       irq = alloc_irq_from(from, node);
+       if (irq < 0)
+               return 0;
+       cfg = alloc_irq_cfg(irq, node);
+       if (!cfg) {
+               free_irq_at(irq, NULL);
+               return 0;
        }
-       raw_spin_unlock_irqrestore(&vector_lock, flags);
 
-       if (irq > 0)
-               dynamic_irq_init_keep_chip_data(irq);
+       raw_spin_lock_irqsave(&vector_lock, flags);
+       if (!__assign_irq_vector(irq, cfg, apic->target_cpus()))
+               ret = irq;
+       raw_spin_unlock_irqrestore(&vector_lock, flags);
 
-       return irq;
+       if (ret) {
+               set_irq_chip_data(irq, cfg);
+               irq_clear_status_flags(irq, IRQ_NOREQUEST);
+       } else {
+               free_irq_at(irq, cfg);
+       }
+       return ret;
 }
 
 int create_irq(void)
 {
-       int node = cpu_to_node(boot_cpu_id);
+       int node = cpu_to_node(0);
        unsigned int irq_want;
        int irq;
 
@@ -3301,14 +3104,17 @@ int create_irq(void)
 
 void destroy_irq(unsigned int irq)
 {
+       struct irq_cfg *cfg = get_irq_chip_data(irq);
        unsigned long flags;
 
-       dynamic_irq_cleanup_keep_chip_data(irq);
+       irq_set_status_flags(irq, IRQ_NOREQUEST|IRQ_NOPROBE);
 
-       free_irte(irq);
+       if (intr_remapping_enabled)
+               free_irte(irq);
        raw_spin_lock_irqsave(&vector_lock, flags);
-       __clear_irq_vector(irq, get_irq_chip_data(irq));
+       __clear_irq_vector(irq, cfg);
        raw_spin_unlock_irqrestore(&vector_lock, flags);
+       free_irq_at(irq, cfg);
 }
 
 /*
@@ -3332,7 +3138,7 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
 
        dest = apic->cpu_mask_to_apicid_and(cfg->domain, apic->target_cpus());
 
-       if (irq_remapped(irq)) {
+       if (irq_remapped(get_irq_chip_data(irq))) {
                struct irte irte;
                int ir_index;
                u16 sub_handle;
@@ -3340,14 +3146,7 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
                ir_index = map_irq_to_irte_handle(irq, &sub_handle);
                BUG_ON(ir_index == -1);
 
-               memset (&irte, 0, sizeof(irte));
-
-               irte.present = 1;
-               irte.dst_mode = apic->irq_dest_mode;
-               irte.trigger_mode = 0; /* edge */
-               irte.dlvry_mode = apic->irq_delivery_mode;
-               irte.vector = cfg->vector;
-               irte.dest_id = IRTE_DEST(dest);
+               prepare_irte(&irte, cfg->vector, dest);
 
                /* Set source-id of interrupt request */
                if (pdev)
@@ -3392,26 +3191,24 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
 }
 
 #ifdef CONFIG_SMP
-static int set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
+static int
+msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_cfg *cfg;
+       struct irq_cfg *cfg = data->chip_data;
        struct msi_msg msg;
        unsigned int dest;
 
-       if (set_desc_affinity(desc, mask, &dest))
+       if (__ioapic_set_affinity(data, mask, &dest))
                return -1;
 
-       cfg = desc->chip_data;
-
-       get_cached_msi_msg_desc(desc, &msg);
+       __get_cached_msi_msg(data->msi_desc, &msg);
 
        msg.data &= ~MSI_DATA_VECTOR_MASK;
        msg.data |= MSI_DATA_VECTOR(cfg->vector);
        msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
-       write_msi_msg_desc(desc, &msg);
+       __write_msi_msg(data->msi_desc, &msg);
 
        return 0;
 }
@@ -3421,17 +3218,17 @@ static int set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
  * done in the process context using interrupt-remapping hardware.
  */
 static int
-ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
+ir_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
+                   bool force)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_cfg *cfg = desc->chip_data;
-       unsigned int dest;
+       struct irq_cfg *cfg = data->chip_data;
+       unsigned int dest, irq = data->irq;
        struct irte irte;
 
        if (get_irte(irq, &irte))
                return -1;
 
-       if (set_desc_affinity(desc, mask, &dest))
+       if (__ioapic_set_affinity(data, mask, &dest))
                return -1;
 
        irte.vector = cfg->vector;
@@ -3461,27 +3258,27 @@ ir_set_msi_irq_affinity(unsigned int irq, const struct cpumask *mask)
  * which implement the MSI or MSI-X Capability Structure.
  */
 static struct irq_chip msi_chip = {
-       .name           = "PCI-MSI",
-       .unmask         = unmask_msi_irq,
-       .mask           = mask_msi_irq,
-       .ack            = ack_apic_edge,
+       .name                   = "PCI-MSI",
+       .irq_unmask             = unmask_msi_irq,
+       .irq_mask               = mask_msi_irq,
+       .irq_ack                = ack_apic_edge,
 #ifdef CONFIG_SMP
-       .set_affinity   = set_msi_irq_affinity,
+       .irq_set_affinity       = msi_set_affinity,
 #endif
-       .retrigger      = ioapic_retrigger_irq,
+       .irq_retrigger          = ioapic_retrigger_irq,
 };
 
 static struct irq_chip msi_ir_chip = {
-       .name           = "IR-PCI-MSI",
-       .unmask         = unmask_msi_irq,
-       .mask           = mask_msi_irq,
+       .name                   = "IR-PCI-MSI",
+       .irq_unmask             = unmask_msi_irq,
+       .irq_mask               = mask_msi_irq,
 #ifdef CONFIG_INTR_REMAP
-       .ack            = ir_ack_apic_edge,
+       .irq_ack                = ir_ack_apic_edge,
 #ifdef CONFIG_SMP
-       .set_affinity   = ir_set_msi_irq_affinity,
+       .irq_set_affinity       = ir_msi_set_affinity,
 #endif
 #endif
-       .retrigger      = ioapic_retrigger_irq,
+       .irq_retrigger          = ioapic_retrigger_irq,
 };
 
 /*
@@ -3513,8 +3310,8 @@ static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
 
 static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
 {
-       int ret;
        struct msi_msg msg;
+       int ret;
 
        ret = msi_compose_msg(dev, irq, &msg, -1);
        if (ret < 0)
@@ -3523,12 +3320,8 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
        set_irq_msi(irq, msidesc);
        write_msi_msg(irq, &msg);
 
-       if (irq_remapped(irq)) {
-               struct irq_desc *desc = irq_to_desc(irq);
-               /*
-                * irq migration in process context
-                */
-               desc->status |= IRQ_MOVE_PCNTXT;
+       if (irq_remapped(get_irq_chip_data(irq))) {
+               irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
                set_irq_chip_and_handler_name(irq, &msi_ir_chip, handle_edge_irq, "edge");
        } else
                set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
@@ -3540,13 +3333,10 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
 
 int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
-       unsigned int irq;
-       int ret, sub_handle;
+       int node, ret, sub_handle, index = 0;
+       unsigned int irq, irq_want;
        struct msi_desc *msidesc;
-       unsigned int irq_want;
        struct intel_iommu *iommu = NULL;
-       int index = 0;
-       int node;
 
        /* x86 doesn't support multiple MSI yet */
        if (type == PCI_CAP_ID_MSI && nvec > 1)
@@ -3606,18 +3396,17 @@ void arch_teardown_msi_irq(unsigned int irq)
 
 #if defined (CONFIG_DMAR) || defined (CONFIG_INTR_REMAP)
 #ifdef CONFIG_SMP
-static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int
+dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
+                     bool force)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_cfg *cfg;
+       struct irq_cfg *cfg = data->chip_data;
+       unsigned int dest, irq = data->irq;
        struct msi_msg msg;
-       unsigned int dest;
 
-       if (set_desc_affinity(desc, mask, &dest))
+       if (__ioapic_set_affinity(data, mask, &dest))
                return -1;
 
-       cfg = desc->chip_data;
-
        dmar_msi_read(irq, &msg);
 
        msg.data &= ~MSI_DATA_VECTOR_MASK;
@@ -3633,14 +3422,14 @@ static int dmar_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 #endif /* CONFIG_SMP */
 
 static struct irq_chip dmar_msi_type = {
-       .name = "DMAR_MSI",
-       .unmask = dmar_msi_unmask,
-       .mask = dmar_msi_mask,
-       .ack = ack_apic_edge,
+       .name                   = "DMAR_MSI",
+       .irq_unmask             = dmar_msi_unmask,
+       .irq_mask               = dmar_msi_mask,
+       .irq_ack                = ack_apic_edge,
 #ifdef CONFIG_SMP
-       .set_affinity = dmar_msi_set_affinity,
+       .irq_set_affinity       = dmar_msi_set_affinity,
 #endif
-       .retrigger = ioapic_retrigger_irq,
+       .irq_retrigger          = ioapic_retrigger_irq,
 };
 
 int arch_setup_dmar_msi(unsigned int irq)
@@ -3661,26 +3450,24 @@ int arch_setup_dmar_msi(unsigned int irq)
 #ifdef CONFIG_HPET_TIMER
 
 #ifdef CONFIG_SMP
-static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
+static int hpet_msi_set_affinity(struct irq_data *data,
+                                const struct cpumask *mask, bool force)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_cfg *cfg;
+       struct irq_cfg *cfg = data->chip_data;
        struct msi_msg msg;
        unsigned int dest;
 
-       if (set_desc_affinity(desc, mask, &dest))
+       if (__ioapic_set_affinity(data, mask, &dest))
                return -1;
 
-       cfg = desc->chip_data;
-
-       hpet_msi_read(irq, &msg);
+       hpet_msi_read(data->handler_data, &msg);
 
        msg.data &= ~MSI_DATA_VECTOR_MASK;
        msg.data |= MSI_DATA_VECTOR(cfg->vector);
        msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
-       hpet_msi_write(irq, &msg);
+       hpet_msi_write(data->handler_data, &msg);
 
        return 0;
 }
@@ -3688,34 +3475,33 @@ static int hpet_msi_set_affinity(unsigned int irq, const struct cpumask *mask)
 #endif /* CONFIG_SMP */
 
 static struct irq_chip ir_hpet_msi_type = {
-       .name = "IR-HPET_MSI",
-       .unmask = hpet_msi_unmask,
-       .mask = hpet_msi_mask,
+       .name                   = "IR-HPET_MSI",
+       .irq_unmask             = hpet_msi_unmask,
+       .irq_mask               = hpet_msi_mask,
 #ifdef CONFIG_INTR_REMAP
-       .ack = ir_ack_apic_edge,
+       .irq_ack                = ir_ack_apic_edge,
 #ifdef CONFIG_SMP
-       .set_affinity = ir_set_msi_irq_affinity,
+       .irq_set_affinity       = ir_msi_set_affinity,
 #endif
 #endif
-       .retrigger = ioapic_retrigger_irq,
+       .irq_retrigger          = ioapic_retrigger_irq,
 };
 
 static struct irq_chip hpet_msi_type = {
        .name = "HPET_MSI",
-       .unmask = hpet_msi_unmask,
-       .mask = hpet_msi_mask,
-       .ack = ack_apic_edge,
+       .irq_unmask = hpet_msi_unmask,
+       .irq_mask = hpet_msi_mask,
+       .irq_ack = ack_apic_edge,
 #ifdef CONFIG_SMP
-       .set_affinity = hpet_msi_set_affinity,
+       .irq_set_affinity = hpet_msi_set_affinity,
 #endif
-       .retrigger = ioapic_retrigger_irq,
+       .irq_retrigger = ioapic_retrigger_irq,
 };
 
 int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
 {
-       int ret;
        struct msi_msg msg;
-       struct irq_desc *desc = irq_to_desc(irq);
+       int ret;
 
        if (intr_remapping_enabled) {
                struct intel_iommu *iommu = map_hpet_to_ir(id);
@@ -3733,9 +3519,9 @@ int arch_setup_hpet_msi(unsigned int irq, unsigned int id)
        if (ret < 0)
                return ret;
 
-       hpet_msi_write(irq, &msg);
-       desc->status |= IRQ_MOVE_PCNTXT;
-       if (irq_remapped(irq))
+       hpet_msi_write(get_irq_data(irq), &msg);
+       irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
+       if (irq_remapped(get_irq_chip_data(irq)))
                set_irq_chip_and_handler_name(irq, &ir_hpet_msi_type,
                                              handle_edge_irq, "edge");
        else
@@ -3768,33 +3554,30 @@ static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
        write_ht_irq_msg(irq, &msg);
 }
 
-static int set_ht_irq_affinity(unsigned int irq, const struct cpumask *mask)
+static int
+ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_cfg *cfg;
+       struct irq_cfg *cfg = data->chip_data;
        unsigned int dest;
 
-       if (set_desc_affinity(desc, mask, &dest))
+       if (__ioapic_set_affinity(data, mask, &dest))
                return -1;
 
-       cfg = desc->chip_data;
-
-       target_ht_irq(irq, dest, cfg->vector);
-
+       target_ht_irq(data->irq, dest, cfg->vector);
        return 0;
 }
 
 #endif
 
 static struct irq_chip ht_irq_chip = {
-       .name           = "PCI-HT",
-       .mask           = mask_ht_irq,
-       .unmask         = unmask_ht_irq,
-       .ack            = ack_apic_edge,
+       .name                   = "PCI-HT",
+       .irq_mask               = mask_ht_irq,
+       .irq_unmask             = unmask_ht_irq,
+       .irq_ack                = ack_apic_edge,
 #ifdef CONFIG_SMP
-       .set_affinity   = set_ht_irq_affinity,
+       .irq_set_affinity       = ht_set_affinity,
 #endif
-       .retrigger      = ioapic_retrigger_irq,
+       .irq_retrigger          = ioapic_retrigger_irq,
 };
 
 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
@@ -3885,14 +3668,13 @@ int __init arch_probe_nr_irqs(void)
        if (nr < nr_irqs)
                nr_irqs = nr;
 
-       return 0;
+       return NR_IRQS_LEGACY;
 }
 #endif
 
 static int __io_apic_set_pci_routing(struct device *dev, int irq,
                                struct io_apic_irq_attr *irq_attr)
 {
-       struct irq_desc *desc;
        struct irq_cfg *cfg;
        int node;
        int ioapic, pin;
@@ -3908,13 +3690,11 @@ static int __io_apic_set_pci_routing(struct device *dev, int irq,
        if (dev)
                node = dev_to_node(dev);
        else
-               node = cpu_to_node(boot_cpu_id);
+               node = cpu_to_node(0);
 
-       desc = irq_to_desc_alloc_node(irq, node);
-       if (!desc) {
-               printk(KERN_INFO "can not get irq_desc %d\n", irq);
+       cfg = alloc_irq_and_cfg_at(irq, node);
+       if (!cfg)
                return 0;
-       }
 
        pin = irq_attr->ioapic_pin;
        trigger = irq_attr->trigger;
@@ -3924,15 +3704,14 @@ static int __io_apic_set_pci_routing(struct device *dev, int irq,
         * IRQs < 16 are already in the irq_2_pin[] map
         */
        if (irq >= legacy_pic->nr_legacy_irqs) {
-               cfg = desc->chip_data;
-               if (add_pin_to_irq_node_nopanic(cfg, node, ioapic, pin)) {
+               if (__add_pin_to_irq_node(cfg, node, ioapic, pin)) {
                        printk(KERN_INFO "can not add pin %d for irq %d\n",
                                pin, irq);
                        return 0;
                }
        }
 
-       setup_IO_APIC_irq(ioapic, pin, irq, desc, trigger, polarity);
+       setup_ioapic_irq(ioapic, pin, irq, cfg, trigger, polarity);
 
        return 0;
 }
@@ -4125,14 +3904,14 @@ void __init setup_ioapic_dest(void)
                 */
                if (desc->status &
                    (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
-                       mask = desc->affinity;
+                       mask = desc->irq_data.affinity;
                else
                        mask = apic->target_cpus();
 
                if (intr_remapping_enabled)
-                       set_ir_ioapic_affinity_irq_desc(desc, mask);
+                       ir_ioapic_set_affinity(&desc->irq_data, mask, false);
                else
-                       set_ioapic_affinity_irq_desc(desc, mask);
+                       ioapic_set_affinity(&desc->irq_data, mask, false);
        }
 
 }
@@ -4316,19 +4095,18 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
 void __init pre_init_apic_IRQ0(void)
 {
        struct irq_cfg *cfg;
-       struct irq_desc *desc;
 
        printk(KERN_INFO "Early APIC setup for system timer0\n");
 #ifndef CONFIG_SMP
        phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
 #endif
-       desc = irq_to_desc_alloc_node(0, 0);
+       /* Make sure the irq descriptor is set up */
+       cfg = alloc_irq_and_cfg_at(0, 0);
 
        setup_local_APIC();
 
-       cfg = irq_cfg(0);
        add_pin_to_irq_node(cfg, 0, 0, 0);
        set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
 
-       setup_IO_APIC_irq(0, 0, 0, desc, 0, 0);
+       setup_ioapic_irq(0, 0, 0, cfg, 0, 0);
 }
index a43f71cb30f8709595fe77c80be19d36c24aae29..c90041ccb74239cd471a5d334f16d93b28a46b62 100644 (file)
@@ -178,7 +178,7 @@ int __init check_nmi_watchdog(void)
 error:
        if (nmi_watchdog == NMI_IO_APIC) {
                if (!timer_through_8259)
-                       legacy_pic->chip->mask(0);
+                       legacy_pic->mask(0);
                on_each_cpu(__acpi_nmi_disable, NULL, 1);
        }
 
index 3e28401f161c768193e784cc013814cadf190078..960f26ab5c9f24ed2f4587107faa2fcd457d782c 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/nodemask.h>
 #include <linux/topology.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/kernel.h>
@@ -88,7 +89,7 @@ static inline void numaq_register_node(int node, struct sys_cfg_data *scd)
        node_end_pfn[node] =
                 MB_TO_PAGES(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size);
 
-       e820_register_active_regions(node, node_start_pfn[node],
+       memblock_x86_register_active_regions(node, node_start_pfn[node],
                                                node_end_pfn[node]);
 
        memory_present(node, node_start_pfn[node], node_end_pfn[node]);
index 83e9be4778e2b597791306a85ca9ca527003e2c2..f9e4e6a54073e3d901d0475da9c5deceb21d55d8 100644 (file)
@@ -54,6 +54,9 @@ static int apicid_phys_pkg_id(int initial_apic_id, int index_msb)
  */
 void __init default_setup_apic_routing(void)
 {
+
+       enable_IR_x2apic();
+
 #ifdef CONFIG_X86_X2APIC
        if (x2apic_mode
 #ifdef CONFIG_X86_UV
index fc999e6fc46a34cf1417cd600c11a0e07af1acfd..13a389179514eb4b17c7d5fc6d5100e1996d0770 100644 (file)
@@ -2,7 +2,8 @@
 #include <linux/sched.h>
 #include <linux/kthread.h>
 #include <linux/workqueue.h>
-#include <asm/e820.h>
+#include <linux/memblock.h>
+
 #include <asm/proto.h>
 
 /*
@@ -18,10 +19,12 @@ static int __read_mostly memory_corruption_check = -1;
 static unsigned __read_mostly corruption_check_size = 64*1024;
 static unsigned __read_mostly corruption_check_period = 60; /* seconds */
 
-static struct e820entry scan_areas[MAX_SCAN_AREAS];
+static struct scan_area {
+       u64 addr;
+       u64 size;
+} scan_areas[MAX_SCAN_AREAS];
 static int num_scan_areas;
 
-
 static __init int set_corruption_check(char *arg)
 {
        char *end;
@@ -81,9 +84,9 @@ void __init setup_bios_corruption_check(void)
 
        while (addr < corruption_check_size && num_scan_areas < MAX_SCAN_AREAS) {
                u64 size;
-               addr = find_e820_area_size(addr, &size, PAGE_SIZE);
+               addr = memblock_x86_find_in_range_size(addr, &size, PAGE_SIZE);
 
-               if (!(addr + 1))
+               if (addr == MEMBLOCK_ERROR)
                        break;
 
                if (addr >= corruption_check_size)
@@ -92,7 +95,7 @@ void __init setup_bios_corruption_check(void)
                if ((addr + size) > corruption_check_size)
                        size = corruption_check_size - addr;
 
-               e820_update_range(addr, size, E820_RAM, E820_RESERVED);
+               memblock_x86_reserve_range(addr, addr + size, "SCAN RAM");
                scan_areas[num_scan_areas].addr = addr;
                scan_areas[num_scan_areas].size = size;
                num_scan_areas++;
@@ -105,7 +108,6 @@ void __init setup_bios_corruption_check(void)
 
        printk(KERN_INFO "Scanning %d areas for low memory corruption\n",
               num_scan_areas);
-       update_e820();
 }
 
 
index ba5f62f45f01e136e849894076917684ffcd8c40..9e093f8fe78c4713aec4f91a62394eb0efa1f6c0 100644 (file)
@@ -148,7 +148,7 @@ static void __cpuinit amd_k7_smp_check(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
        /* calling is from identify_secondary_cpu() ? */
-       if (c->cpu_index == boot_cpu_id)
+       if (!c->cpu_index)
                return;
 
        /*
@@ -253,37 +253,51 @@ static int __cpuinit nearby_node(int apicid)
 #endif
 
 /*
- * Fixup core topology information for AMD multi-node processors.
- * Assumption: Number of cores in each internal node is the same.
+ * Fixup core topology information for
+ * (1) AMD multi-node processors
+ *     Assumption: Number of cores in each internal node is the same.
+ * (2) AMD processors supporting compute units
  */
 #ifdef CONFIG_X86_HT
-static void __cpuinit amd_fixup_dcm(struct cpuinfo_x86 *c)
+static void __cpuinit amd_get_topology(struct cpuinfo_x86 *c)
 {
-       unsigned long long value;
-       u32 nodes, cores_per_node;
+       u32 nodes;
+       u8 node_id;
        int cpu = smp_processor_id();
 
-       if (!cpu_has(c, X86_FEATURE_NODEID_MSR))
-               return;
+       /* get information required for multi-node processors */
+       if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
+               u32 eax, ebx, ecx, edx;
 
-       /* fixup topology information only once for a core */
-       if (cpu_has(c, X86_FEATURE_AMD_DCM))
-               return;
+               cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
+               nodes = ((ecx >> 8) & 7) + 1;
+               node_id = ecx & 7;
 
-       rdmsrl(MSR_FAM10H_NODE_ID, value);
+               /* get compute unit information */
+               smp_num_siblings = ((ebx >> 8) & 3) + 1;
+               c->compute_unit_id = ebx & 0xff;
+       } else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
+               u64 value;
 
-       nodes = ((value >> 3) & 7) + 1;
-       if (nodes == 1)
+               rdmsrl(MSR_FAM10H_NODE_ID, value);
+               nodes = ((value >> 3) & 7) + 1;
+               node_id = value & 7;
+       } else
                return;
 
-       set_cpu_cap(c, X86_FEATURE_AMD_DCM);
-       cores_per_node = c->x86_max_cores / nodes;
+       /* fixup multi-node processor information */
+       if (nodes > 1) {
+               u32 cores_per_node;
+
+               set_cpu_cap(c, X86_FEATURE_AMD_DCM);
+               cores_per_node = c->x86_max_cores / nodes;
 
-       /* store NodeID, use llc_shared_map to store sibling info */
-       per_cpu(cpu_llc_id, cpu) = value & 7;
+               /* store NodeID, use llc_shared_map to store sibling info */
+               per_cpu(cpu_llc_id, cpu) = node_id;
 
-       /* fixup core id to be in range from 0 to (cores_per_node - 1) */
-       c->cpu_core_id = c->cpu_core_id % cores_per_node;
+               /* core id to be in range from 0 to (cores_per_node - 1) */
+               c->cpu_core_id = c->cpu_core_id % cores_per_node;
+       }
 }
 #endif
 
@@ -304,9 +318,7 @@ static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
        c->phys_proc_id = c->initial_apicid >> bits;
        /* use socket ID also for last level cache */
        per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
-       /* fixup topology information on multi-node processors */
-       if ((c->x86 == 0x10) && (c->x86_model == 9))
-               amd_fixup_dcm(c);
+       amd_get_topology(c);
 #endif
 }
 
@@ -412,6 +424,23 @@ static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
                        set_cpu_cap(c, X86_FEATURE_EXTD_APICID);
        }
 #endif
+
+       /* We need to do the following only once */
+       if (c != &boot_cpu_data)
+               return;
+
+       if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) {
+
+               if (c->x86 > 0x10 ||
+                   (c->x86 == 0x10 && c->x86_model >= 0x2)) {
+                       u64 val;
+
+                       rdmsrl(MSR_K7_HWCR, val);
+                       if (!(val & BIT(24)))
+                               printk(KERN_WARNING FW_BUG "TSC doesn't count "
+                                       "with P0 frequency!\n");
+               }
+       }
 }
 
 static void __cpuinit init_amd(struct cpuinfo_x86 *c)
@@ -523,7 +552,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 #endif
 
        if (c->extended_cpuid_level >= 0x80000006) {
-               if ((c->x86 >= 0x0f) && (cpuid_edx(0x80000006) & 0xf000))
+               if (cpuid_edx(0x80000006) & 0xf000)
                        num_cache_leaves = 4;
                else
                        num_cache_leaves = 3;
index f2f9ac7da25ccfba6d5ba7ea44b63899ba672e97..4b68bda30938d0a55ed39eeaeff68157266a9ea0 100644 (file)
@@ -665,7 +665,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
                this_cpu->c_early_init(c);
 
 #ifdef CONFIG_SMP
-       c->cpu_index = boot_cpu_id;
+       c->cpu_index = 0;
 #endif
        filter_cpuid_features(c, false);
 }
@@ -704,16 +704,21 @@ void __init early_cpu_init(void)
 }
 
 /*
- * The NOPL instruction is supposed to exist on all CPUs with
- * family >= 6; unfortunately, that's not true in practice because
- * of early VIA chips and (more importantly) broken virtualizers that
- * are not easy to detect.  In the latter case it doesn't even *fail*
- * reliably, so probing for it doesn't even work.  Disable it completely
+ * The NOPL instruction is supposed to exist on all CPUs of family >= 6;
+ * unfortunately, that's not true in practice because of early VIA
+ * chips and (more importantly) broken virtualizers that are not easy
+ * to detect. In the latter case it doesn't even *fail* reliably, so
+ * probing for it doesn't even work. Disable it completely on 32-bit
  * unless we can find a reliable way to detect all the broken cases.
+ * Enable it explicitly on 64-bit for non-constant inputs of cpu_has().
  */
 static void __cpuinit detect_nopl(struct cpuinfo_x86 *c)
 {
+#ifdef CONFIG_X86_32
        clear_cpu_cap(c, X86_FEATURE_NOPL);
+#else
+       set_cpu_cap(c, X86_FEATURE_NOPL);
+#endif
 }
 
 static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
@@ -1264,13 +1269,6 @@ void __cpuinit cpu_init(void)
        clear_all_debug_regs();
        dbg_restore_debug_regs();
 
-       /*
-        * Force FPU initialization:
-        */
-       current_thread_info()->status = 0;
-       clear_used_math();
-       mxcsr_feature_mask_init();
-
        fpu_init();
        xsave_init();
 }
index f668bb1f7d432811bc3f773d777ca2596b6f6e33..e765633f210ed893f56bc23ba26e6cfea6c074fd 100644 (file)
@@ -32,6 +32,7 @@ struct cpu_dev {
 extern const struct cpu_dev *const __x86_cpu_dev_start[],
                            *const __x86_cpu_dev_end[];
 
+extern void get_cpu_cap(struct cpuinfo_x86 *c);
 extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
 extern void get_cpu_cap(struct cpuinfo_x86 *c);
 
index b4389441efbbd8e791289aa936369e5e73917c18..695f17731e2382ce63bbbb4a9caaf2ec7e16e29e 100644 (file)
@@ -170,7 +170,7 @@ static void __cpuinit intel_smp_check(struct cpuinfo_x86 *c)
 {
 #ifdef CONFIG_SMP
        /* calling is from identify_secondary_cpu() ? */
-       if (c->cpu_index == boot_cpu_id)
+       if (!c->cpu_index)
                return;
 
        /*
index 898c2f4eab88b28cb74719b943cad01ec06efa29..12cd823c8d038008f8abe77785b4bb475dd3cf20 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <asm/processor.h>
 #include <linux/smp.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 #include <asm/smp.h>
 
 #define LVL_1_INST     1
@@ -306,7 +306,7 @@ struct _cache_attr {
        ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count);
 };
 
-#ifdef CONFIG_CPU_SUP_AMD
+#ifdef CONFIG_AMD_NB
 
 /*
  * L3 cache descriptors
@@ -369,7 +369,7 @@ static void __cpuinit amd_check_l3_disable(struct _cpuid4_info_regs *this_leaf,
                        return;
 
        /* not in virtualized environments */
-       if (num_k8_northbridges == 0)
+       if (k8_northbridges.num == 0)
                return;
 
        /*
@@ -377,7 +377,7 @@ static void __cpuinit amd_check_l3_disable(struct _cpuid4_info_regs *this_leaf,
         * never freed but this is done only on shutdown so it doesn't matter.
         */
        if (!l3_caches) {
-               int size = num_k8_northbridges * sizeof(struct amd_l3_cache *);
+               int size = k8_northbridges.num * sizeof(struct amd_l3_cache *);
 
                l3_caches = kzalloc(size, GFP_ATOMIC);
                if (!l3_caches)
@@ -556,12 +556,12 @@ static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
 static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
                show_cache_disable_1, store_cache_disable_1);
 
-#else  /* CONFIG_CPU_SUP_AMD */
+#else  /* CONFIG_AMD_NB */
 static void __cpuinit
 amd_check_l3_disable(struct _cpuid4_info_regs *this_leaf, int index)
 {
 };
-#endif /* CONFIG_CPU_SUP_AMD */
+#endif /* CONFIG_AMD_NB */
 
 static int
 __cpuinit cpuid4_cache_lookup_regs(int index,
@@ -1000,7 +1000,7 @@ static struct attribute *default_attrs[] = {
 
 static struct attribute *default_l3_attrs[] = {
        DEFAULT_SYSFS_CACHE_ATTRS,
-#ifdef CONFIG_CPU_SUP_AMD
+#ifdef CONFIG_AMD_NB
        &cache_disable_0.attr,
        &cache_disable_1.attr,
 #endif
index 39aaee5c1ab23f742dd749500ca09834e0d39bc4..80c482382d5c95e06b71ffdf91b6f5d362bf2b45 100644 (file)
@@ -131,7 +131,8 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
        u32 low = 0, high = 0, address = 0;
        unsigned int bank, block;
        struct thresh_restart tr;
-       u8 lvt_off;
+       int lvt_off = -1;
+       u8 offset;
 
        for (bank = 0; bank < NR_BANKS; ++bank) {
                for (block = 0; block < NR_BLOCKS; ++block) {
@@ -162,8 +163,28 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
                        if (shared_bank[bank] && c->cpu_core_id)
                                break;
 #endif
-                       lvt_off = setup_APIC_eilvt_mce(THRESHOLD_APIC_VECTOR,
-                                                      APIC_EILVT_MSG_FIX, 0);
+                       offset = (high & MASK_LVTOFF_HI) >> 20;
+                       if (lvt_off < 0) {
+                               if (setup_APIC_eilvt(offset,
+                                                    THRESHOLD_APIC_VECTOR,
+                                                    APIC_EILVT_MSG_FIX, 0)) {
+                                       pr_err(FW_BUG "cpu %d, failed to "
+                                              "setup threshold interrupt "
+                                              "for bank %d, block %d "
+                                              "(MSR%08X=0x%x%08x)",
+                                              smp_processor_id(), bank, block,
+                                              address, high, low);
+                                       continue;
+                               }
+                               lvt_off = offset;
+                       } else if (lvt_off != offset) {
+                               pr_err(FW_BUG "cpu %d, invalid threshold "
+                                      "interrupt offset %d for bank %d,"
+                                      "block %d (MSR%08X=0x%x%08x)",
+                                      smp_processor_id(), lvt_off, bank,
+                                      block, address, high, low);
+                               continue;
+                       }
 
                        high &= ~MASK_LVTOFF_HI;
                        high |= lvt_off << 20;
index 169d8804a9f8eed37faf06503e1b8243a566cb37..4b683267eca5fb982111375ab9e000d7eda3b437 100644 (file)
@@ -350,7 +350,7 @@ static void intel_thermal_interrupt(void)
 
 static void unexpected_thermal_interrupt(void)
 {
-       printk(KERN_ERR "CPU%d: Unexpected LVT TMR interrupt!\n",
+       printk(KERN_ERR "CPU%d: Unexpected LVT thermal interrupt!\n",
                        smp_processor_id());
        add_taint(TAINT_MACHINE_CHECK);
 }
index c5f59d07142562e9c673572970ae79fca1e3622e..ac140c7be396b6f55c97521ddcd572df664e95b6 100644 (file)
@@ -827,7 +827,7 @@ int __init amd_special_default_mtrr(void)
 
        if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
                return 0;
-       if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
+       if (boot_cpu_data.x86 < 0xf)
                return 0;
        /* In case some hypervisor doesn't pass SYSCFG through: */
        if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
index 7d28d7d03885a1d28e0785221f8e0197b89f957f..9f27228ceffd4e90da9467498e409e451187ee99 100644 (file)
@@ -64,18 +64,59 @@ static inline void k8_check_syscfg_dram_mod_en(void)
        }
 }
 
+/* Get the size of contiguous MTRR range */
+static u64 get_mtrr_size(u64 mask)
+{
+       u64 size;
+
+       mask >>= PAGE_SHIFT;
+       mask |= size_or_mask;
+       size = -mask;
+       size <<= PAGE_SHIFT;
+       return size;
+}
+
 /*
- * Returns the effective MTRR type for the region
- * Error returns:
- * - 0xFE - when the range is "not entirely covered" by _any_ var range MTRR
- * - 0xFF - when MTRR is not enabled
+ * Check and return the effective type for MTRR-MTRR type overlap.
+ * Returns 1 if the effective type is UNCACHEABLE, else returns 0
  */
-u8 mtrr_type_lookup(u64 start, u64 end)
+static int check_type_overlap(u8 *prev, u8 *curr)
+{
+       if (*prev == MTRR_TYPE_UNCACHABLE || *curr == MTRR_TYPE_UNCACHABLE) {
+               *prev = MTRR_TYPE_UNCACHABLE;
+               *curr = MTRR_TYPE_UNCACHABLE;
+               return 1;
+       }
+
+       if ((*prev == MTRR_TYPE_WRBACK && *curr == MTRR_TYPE_WRTHROUGH) ||
+           (*prev == MTRR_TYPE_WRTHROUGH && *curr == MTRR_TYPE_WRBACK)) {
+               *prev = MTRR_TYPE_WRTHROUGH;
+               *curr = MTRR_TYPE_WRTHROUGH;
+       }
+
+       if (*prev != *curr) {
+               *prev = MTRR_TYPE_UNCACHABLE;
+               *curr = MTRR_TYPE_UNCACHABLE;
+               return 1;
+       }
+
+       return 0;
+}
+
+/*
+ * Error/Semi-error returns:
+ * 0xFF - when MTRR is not enabled
+ * *repeat == 1 implies [start:end] spanned across MTRR range and type returned
+ *             corresponds only to [start:*partial_end].
+ *             Caller has to lookup again for [*partial_end:end].
+ */
+static u8 __mtrr_type_lookup(u64 start, u64 end, u64 *partial_end, int *repeat)
 {
        int i;
        u64 base, mask;
        u8 prev_match, curr_match;
 
+       *repeat = 0;
        if (!mtrr_state_set)
                return 0xFF;
 
@@ -126,8 +167,34 @@ u8 mtrr_type_lookup(u64 start, u64 end)
 
                start_state = ((start & mask) == (base & mask));
                end_state = ((end & mask) == (base & mask));
-               if (start_state != end_state)
-                       return 0xFE;
+
+               if (start_state != end_state) {
+                       /*
+                        * We have start:end spanning across an MTRR.
+                        * We split the region into
+                        * either
+                        * (start:mtrr_end) (mtrr_end:end)
+                        * or
+                        * (start:mtrr_start) (mtrr_start:end)
+                        * depending on kind of overlap.
+                        * Return the type for first region and a pointer to
+                        * the start of second region so that caller will
+                        * lookup again on the second region.
+                        * Note: This way we handle multiple overlaps as well.
+                        */
+                       if (start_state)
+                               *partial_end = base + get_mtrr_size(mask);
+                       else
+                               *partial_end = base;
+
+                       if (unlikely(*partial_end <= start)) {
+                               WARN_ON(1);
+                               *partial_end = start + PAGE_SIZE;
+                       }
+
+                       end = *partial_end - 1; /* end is inclusive */
+                       *repeat = 1;
+               }
 
                if ((start & mask) != (base & mask))
                        continue;
@@ -138,21 +205,8 @@ u8 mtrr_type_lookup(u64 start, u64 end)
                        continue;
                }
 
-               if (prev_match == MTRR_TYPE_UNCACHABLE ||
-                   curr_match == MTRR_TYPE_UNCACHABLE) {
-                       return MTRR_TYPE_UNCACHABLE;
-               }
-
-               if ((prev_match == MTRR_TYPE_WRBACK &&
-                    curr_match == MTRR_TYPE_WRTHROUGH) ||
-                   (prev_match == MTRR_TYPE_WRTHROUGH &&
-                    curr_match == MTRR_TYPE_WRBACK)) {
-                       prev_match = MTRR_TYPE_WRTHROUGH;
-                       curr_match = MTRR_TYPE_WRTHROUGH;
-               }
-
-               if (prev_match != curr_match)
-                       return MTRR_TYPE_UNCACHABLE;
+               if (check_type_overlap(&prev_match, &curr_match))
+                       return curr_match;
        }
 
        if (mtrr_tom2) {
@@ -166,6 +220,36 @@ u8 mtrr_type_lookup(u64 start, u64 end)
        return mtrr_state.def_type;
 }
 
+/*
+ * Returns the effective MTRR type for the region
+ * Error return:
+ * 0xFF - when MTRR is not enabled
+ */
+u8 mtrr_type_lookup(u64 start, u64 end)
+{
+       u8 type, prev_type;
+       int repeat;
+       u64 partial_end;
+
+       type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
+
+       /*
+        * Common path is with repeat = 0.
+        * However, we can have cases where [start:end] spans across some
+        * MTRR range. Do repeated lookups for that case here.
+        */
+       while (repeat) {
+               prev_type = type;
+               start = partial_end;
+               type = __mtrr_type_lookup(start, end, &partial_end, &repeat);
+
+               if (check_type_overlap(&prev_type, &type))
+                       return type;
+       }
+
+       return type;
+}
+
 /* Get the MSR pair relating to a var range */
 static void
 get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr)
index 03a5b0385ad6c4402d2192b42aa14e9bfaccc80e..a333bf9189f6edb4100138d57dce4f40aa07e0d1 100644 (file)
@@ -238,6 +238,7 @@ struct x86_pmu {
         * Intel DebugStore bits
         */
        int             bts, pebs;
+       int             bts_active, pebs_active;
        int             pebs_record_size;
        void            (*drain_pebs)(struct pt_regs *regs);
        struct event_constraint *pebs_constraints;
@@ -381,7 +382,7 @@ static void release_pmc_hardware(void) {}
 
 #endif
 
-static int reserve_ds_buffers(void);
+static void reserve_ds_buffers(void);
 static void release_ds_buffers(void);
 
 static void hw_perf_event_destroy(struct perf_event *event)
@@ -478,7 +479,7 @@ static int x86_setup_perfctr(struct perf_event *event)
        if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
            (hwc->sample_period == 1)) {
                /* BTS is not supported by this architecture. */
-               if (!x86_pmu.bts)
+               if (!x86_pmu.bts_active)
                        return -EOPNOTSUPP;
 
                /* BTS is currently only allowed for user-mode. */
@@ -497,12 +498,13 @@ static int x86_pmu_hw_config(struct perf_event *event)
                int precise = 0;
 
                /* Support for constant skid */
-               if (x86_pmu.pebs)
+               if (x86_pmu.pebs_active) {
                        precise++;
 
-               /* Support for IP fixup */
-               if (x86_pmu.lbr_nr)
-                       precise++;
+                       /* Support for IP fixup */
+                       if (x86_pmu.lbr_nr)
+                               precise++;
+               }
 
                if (event->attr.precise_ip > precise)
                        return -EOPNOTSUPP;
@@ -531,7 +533,7 @@ static int x86_pmu_hw_config(struct perf_event *event)
 /*
  * Setup the hardware configuration for a given attr_type
  */
-static int __hw_perf_event_init(struct perf_event *event)
+static int __x86_pmu_event_init(struct perf_event *event)
 {
        int err;
 
@@ -544,11 +546,8 @@ static int __hw_perf_event_init(struct perf_event *event)
                if (atomic_read(&active_events) == 0) {
                        if (!reserve_pmc_hardware())
                                err = -EBUSY;
-                       else {
-                               err = reserve_ds_buffers();
-                               if (err)
-                                       release_pmc_hardware();
-                       }
+                       else
+                               reserve_ds_buffers();
                }
                if (!err)
                        atomic_inc(&active_events);
@@ -584,7 +583,7 @@ static void x86_pmu_disable_all(void)
        }
 }
 
-void hw_perf_disable(void)
+static void x86_pmu_disable(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
@@ -619,7 +618,7 @@ static void x86_pmu_enable_all(int added)
        }
 }
 
-static const struct pmu pmu;
+static struct pmu pmu;
 
 static inline int is_x86_event(struct perf_event *event)
 {
@@ -801,10 +800,10 @@ static inline int match_prev_assignment(struct hw_perf_event *hwc,
                hwc->last_tag == cpuc->tags[i];
 }
 
-static int x86_pmu_start(struct perf_event *event);
-static void x86_pmu_stop(struct perf_event *event);
+static void x86_pmu_start(struct perf_event *event, int flags);
+static void x86_pmu_stop(struct perf_event *event, int flags);
 
-void hw_perf_enable(void)
+static void x86_pmu_enable(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct perf_event *event;
@@ -840,7 +839,14 @@ void hw_perf_enable(void)
                            match_prev_assignment(hwc, cpuc, i))
                                continue;
 
-                       x86_pmu_stop(event);
+                       /*
+                        * Ensure we don't accidentally enable a stopped
+                        * counter simply because we rescheduled.
+                        */
+                       if (hwc->state & PERF_HES_STOPPED)
+                               hwc->state |= PERF_HES_ARCH;
+
+                       x86_pmu_stop(event, PERF_EF_UPDATE);
                }
 
                for (i = 0; i < cpuc->n_events; i++) {
@@ -852,7 +858,10 @@ void hw_perf_enable(void)
                        else if (i < n_running)
                                continue;
 
-                       x86_pmu_start(event);
+                       if (hwc->state & PERF_HES_ARCH)
+                               continue;
+
+                       x86_pmu_start(event, PERF_EF_RELOAD);
                }
                cpuc->n_added = 0;
                perf_events_lapic_init();
@@ -953,15 +962,12 @@ static void x86_pmu_enable_event(struct perf_event *event)
 }
 
 /*
- * activate a single event
+ * Add a single event to the PMU.
  *
  * The event is added to the group of enabled events
  * but only if it can be scehduled with existing events.
- *
- * Called with PMU disabled. If successful and return value 1,
- * then guaranteed to call perf_enable() and hw_perf_enable()
  */
-static int x86_pmu_enable(struct perf_event *event)
+static int x86_pmu_add(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc;
@@ -970,58 +976,67 @@ static int x86_pmu_enable(struct perf_event *event)
 
        hwc = &event->hw;
 
+       perf_pmu_disable(event->pmu);
        n0 = cpuc->n_events;
-       n = collect_events(cpuc, event, false);
-       if (n < 0)
-               return n;
+       ret = n = collect_events(cpuc, event, false);
+       if (ret < 0)
+               goto out;
+
+       hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+       if (!(flags & PERF_EF_START))
+               hwc->state |= PERF_HES_ARCH;
 
        /*
         * If group events scheduling transaction was started,
         * skip the schedulability test here, it will be peformed
-        * at commit time(->commit_txn) as a whole
+        * at commit time (->commit_txn) as a whole
         */
        if (cpuc->group_flag & PERF_EVENT_TXN)
-               goto out;
+               goto done_collect;
 
        ret = x86_pmu.schedule_events(cpuc, n, assign);
        if (ret)
-               return ret;
+               goto out;
        /*
         * copy new assignment, now we know it is possible
         * will be used by hw_perf_enable()
         */
        memcpy(cpuc->assign, assign, n*sizeof(int));
 
-out:
+done_collect:
        cpuc->n_events = n;
        cpuc->n_added += n - n0;
        cpuc->n_txn += n - n0;
 
-       return 0;
+       ret = 0;
+out:
+       perf_pmu_enable(event->pmu);
+       return ret;
 }
 
-static int x86_pmu_start(struct perf_event *event)
+static void x86_pmu_start(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        int idx = event->hw.idx;
 
-       if (idx == -1)
-               return -EAGAIN;
+       if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+               return;
+
+       if (WARN_ON_ONCE(idx == -1))
+               return;
+
+       if (flags & PERF_EF_RELOAD) {
+               WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+               x86_perf_event_set_period(event);
+       }
+
+       event->hw.state = 0;
 
-       x86_perf_event_set_period(event);
        cpuc->events[idx] = event;
        __set_bit(idx, cpuc->active_mask);
        __set_bit(idx, cpuc->running);
        x86_pmu.enable(event);
        perf_event_update_userpage(event);
-
-       return 0;
-}
-
-static void x86_pmu_unthrottle(struct perf_event *event)
-{
-       int ret = x86_pmu_start(event);
-       WARN_ON_ONCE(ret);
 }
 
 void perf_event_print_debug(void)
@@ -1078,27 +1093,29 @@ void perf_event_print_debug(void)
        local_irq_restore(flags);
 }
 
-static void x86_pmu_stop(struct perf_event *event)
+static void x86_pmu_stop(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
-       int idx = hwc->idx;
-
-       if (!__test_and_clear_bit(idx, cpuc->active_mask))
-               return;
-
-       x86_pmu.disable(event);
 
-       /*
-        * Drain the remaining delta count out of a event
-        * that we are disabling:
-        */
-       x86_perf_event_update(event);
+       if (__test_and_clear_bit(hwc->idx, cpuc->active_mask)) {
+               x86_pmu.disable(event);
+               cpuc->events[hwc->idx] = NULL;
+               WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+               hwc->state |= PERF_HES_STOPPED;
+       }
 
-       cpuc->events[idx] = NULL;
+       if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+               /*
+                * Drain the remaining delta count out of a event
+                * that we are disabling:
+                */
+               x86_perf_event_update(event);
+               hwc->state |= PERF_HES_UPTODATE;
+       }
 }
 
-static void x86_pmu_disable(struct perf_event *event)
+static void x86_pmu_del(struct perf_event *event, int flags)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        int i;
@@ -1111,7 +1128,7 @@ static void x86_pmu_disable(struct perf_event *event)
        if (cpuc->group_flag & PERF_EVENT_TXN)
                return;
 
-       x86_pmu_stop(event);
+       x86_pmu_stop(event, PERF_EF_UPDATE);
 
        for (i = 0; i < cpuc->n_events; i++) {
                if (event == cpuc->event_list[i]) {
@@ -1134,7 +1151,6 @@ static int x86_pmu_handle_irq(struct pt_regs *regs)
        struct perf_sample_data data;
        struct cpu_hw_events *cpuc;
        struct perf_event *event;
-       struct hw_perf_event *hwc;
        int idx, handled = 0;
        u64 val;
 
@@ -1155,7 +1171,6 @@ static int x86_pmu_handle_irq(struct pt_regs *regs)
                }
 
                event = cpuc->events[idx];
-               hwc = &event->hw;
 
                val = x86_perf_event_update(event);
                if (val & (1ULL << (x86_pmu.cntval_bits - 1)))
@@ -1171,7 +1186,7 @@ static int x86_pmu_handle_irq(struct pt_regs *regs)
                        continue;
 
                if (perf_event_overflow(event, 1, &data, regs))
-                       x86_pmu_stop(event);
+                       x86_pmu_stop(event, 0);
        }
 
        if (handled)
@@ -1180,25 +1195,6 @@ static int x86_pmu_handle_irq(struct pt_regs *regs)
        return handled;
 }
 
-void smp_perf_pending_interrupt(struct pt_regs *regs)
-{
-       irq_enter();
-       ack_APIC_irq();
-       inc_irq_stat(apic_pending_irqs);
-       perf_event_do_pending();
-       irq_exit();
-}
-
-void set_perf_event_pending(void)
-{
-#ifdef CONFIG_X86_LOCAL_APIC
-       if (!x86_pmu.apic || !x86_pmu_initialized())
-               return;
-
-       apic->send_IPI_self(LOCAL_PENDING_VECTOR);
-#endif
-}
-
 void perf_events_lapic_init(void)
 {
        if (!x86_pmu.apic || !x86_pmu_initialized())
@@ -1388,7 +1384,6 @@ void __init init_hw_perf_events(void)
                x86_pmu.num_counters = X86_PMC_MAX_GENERIC;
        }
        x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1;
-       perf_max_events = x86_pmu.num_counters;
 
        if (x86_pmu.num_counters_fixed > X86_PMC_MAX_FIXED) {
                WARN(1, KERN_ERR "hw perf events fixed %d > max(%d), clipping!",
@@ -1424,6 +1419,7 @@ void __init init_hw_perf_events(void)
        pr_info("... fixed-purpose events:   %d\n",     x86_pmu.num_counters_fixed);
        pr_info("... event mask:             %016Lx\n", x86_pmu.intel_ctrl);
 
+       perf_pmu_register(&pmu);
        perf_cpu_notifier(x86_pmu_notifier);
 }
 
@@ -1437,10 +1433,11 @@ static inline void x86_pmu_read(struct perf_event *event)
  * Set the flag to make pmu::enable() not perform the
  * schedulability test, it will be performed at commit time
  */
-static void x86_pmu_start_txn(const struct pmu *pmu)
+static void x86_pmu_start_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
+       perf_pmu_disable(pmu);
        cpuc->group_flag |= PERF_EVENT_TXN;
        cpuc->n_txn = 0;
 }
@@ -1450,7 +1447,7 @@ static void x86_pmu_start_txn(const struct pmu *pmu)
  * Clear the flag and pmu::enable() will perform the
  * schedulability test.
  */
-static void x86_pmu_cancel_txn(const struct pmu *pmu)
+static void x86_pmu_cancel_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
 
@@ -1460,6 +1457,7 @@ static void x86_pmu_cancel_txn(const struct pmu *pmu)
         */
        cpuc->n_added -= cpuc->n_txn;
        cpuc->n_events -= cpuc->n_txn;
+       perf_pmu_enable(pmu);
 }
 
 /*
@@ -1467,7 +1465,7 @@ static void x86_pmu_cancel_txn(const struct pmu *pmu)
  * Perform the group schedulability test as a whole
  * Return 0 if success
  */
-static int x86_pmu_commit_txn(const struct pmu *pmu)
+static int x86_pmu_commit_txn(struct pmu *pmu)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        int assign[X86_PMC_IDX_MAX];
@@ -1489,22 +1487,10 @@ static int x86_pmu_commit_txn(const struct pmu *pmu)
        memcpy(cpuc->assign, assign, n*sizeof(int));
 
        cpuc->group_flag &= ~PERF_EVENT_TXN;
-
+       perf_pmu_enable(pmu);
        return 0;
 }
 
-static const struct pmu pmu = {
-       .enable         = x86_pmu_enable,
-       .disable        = x86_pmu_disable,
-       .start          = x86_pmu_start,
-       .stop           = x86_pmu_stop,
-       .read           = x86_pmu_read,
-       .unthrottle     = x86_pmu_unthrottle,
-       .start_txn      = x86_pmu_start_txn,
-       .cancel_txn     = x86_pmu_cancel_txn,
-       .commit_txn     = x86_pmu_commit_txn,
-};
-
 /*
  * validate that we can schedule this event
  */
@@ -1579,12 +1565,22 @@ out:
        return ret;
 }
 
-const struct pmu *hw_perf_event_init(struct perf_event *event)
+int x86_pmu_event_init(struct perf_event *event)
 {
-       const struct pmu *tmp;
+       struct pmu *tmp;
        int err;
 
-       err = __hw_perf_event_init(event);
+       switch (event->attr.type) {
+       case PERF_TYPE_RAW:
+       case PERF_TYPE_HARDWARE:
+       case PERF_TYPE_HW_CACHE:
+               break;
+
+       default:
+               return -ENOENT;
+       }
+
+       err = __x86_pmu_event_init(event);
        if (!err) {
                /*
                 * we temporarily connect event to its pmu
@@ -1604,26 +1600,31 @@ const struct pmu *hw_perf_event_init(struct perf_event *event)
        if (err) {
                if (event->destroy)
                        event->destroy(event);
-               return ERR_PTR(err);
        }
 
-       return &pmu;
+       return err;
 }
 
-/*
- * callchain support
- */
+static struct pmu pmu = {
+       .pmu_enable     = x86_pmu_enable,
+       .pmu_disable    = x86_pmu_disable,
 
-static inline
-void callchain_store(struct perf_callchain_entry *entry, u64 ip)
-{
-       if (entry->nr < PERF_MAX_STACK_DEPTH)
-               entry->ip[entry->nr++] = ip;
-}
+       .event_init     = x86_pmu_event_init,
 
-static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_irq_entry);
-static DEFINE_PER_CPU(struct perf_callchain_entry, pmc_nmi_entry);
+       .add            = x86_pmu_add,
+       .del            = x86_pmu_del,
+       .start          = x86_pmu_start,
+       .stop           = x86_pmu_stop,
+       .read           = x86_pmu_read,
 
+       .start_txn      = x86_pmu_start_txn,
+       .cancel_txn     = x86_pmu_cancel_txn,
+       .commit_txn     = x86_pmu_commit_txn,
+};
+
+/*
+ * callchain support
+ */
 
 static void
 backtrace_warning_symbol(void *data, char *msg, unsigned long symbol)
@@ -1645,7 +1646,7 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
 {
        struct perf_callchain_entry *entry = data;
 
-       callchain_store(entry, addr);
+       perf_callchain_store(entry, addr);
 }
 
 static const struct stacktrace_ops backtrace_ops = {
@@ -1656,11 +1657,15 @@ static const struct stacktrace_ops backtrace_ops = {
        .walk_stack             = print_context_stack_bp,
 };
 
-static void
-perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry)
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
-       callchain_store(entry, PERF_CONTEXT_KERNEL);
-       callchain_store(entry, regs->ip);
+       if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+               /* TODO: We don't support guest os callchain now */
+               return;
+       }
+
+       perf_callchain_store(entry, regs->ip);
 
        dump_trace(NULL, regs, NULL, regs->bp, &backtrace_ops, entry);
 }
@@ -1689,7 +1694,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
                if (fp < compat_ptr(regs->sp))
                        break;
 
-               callchain_store(entry, frame.return_address);
+               perf_callchain_store(entry, frame.return_address);
                fp = compat_ptr(frame.next_frame);
        }
        return 1;
@@ -1702,19 +1707,20 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
 }
 #endif
 
-static void
-perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry)
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
 {
        struct stack_frame frame;
        const void __user *fp;
 
-       if (!user_mode(regs))
-               regs = task_pt_regs(current);
+       if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+               /* TODO: We don't support guest os callchain now */
+               return;
+       }
 
        fp = (void __user *)regs->bp;
 
-       callchain_store(entry, PERF_CONTEXT_USER);
-       callchain_store(entry, regs->ip);
+       perf_callchain_store(entry, regs->ip);
 
        if (perf_callchain_user32(regs, entry))
                return;
@@ -1731,52 +1737,11 @@ perf_callchain_user(struct pt_regs *regs, struct perf_callchain_entry *entry)
                if ((unsigned long)fp < regs->sp)
                        break;
 
-               callchain_store(entry, frame.return_address);
+               perf_callchain_store(entry, frame.return_address);
                fp = frame.next_frame;
        }
 }
 
-static void
-perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry)
-{
-       int is_user;
-
-       if (!regs)
-               return;
-
-       is_user = user_mode(regs);
-
-       if (is_user && current->state != TASK_RUNNING)
-               return;
-
-       if (!is_user)
-               perf_callchain_kernel(regs, entry);
-
-       if (current->mm)
-               perf_callchain_user(regs, entry);
-}
-
-struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
-{
-       struct perf_callchain_entry *entry;
-
-       if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
-               /* TODO: We don't support guest os callchain now */
-               return NULL;
-       }
-
-       if (in_nmi())
-               entry = &__get_cpu_var(pmc_nmi_entry);
-       else
-               entry = &__get_cpu_var(pmc_irq_entry);
-
-       entry->nr = 0;
-
-       perf_do_callchain(regs, entry);
-
-       return entry;
-}
-
 unsigned long perf_instruction_pointer(struct pt_regs *regs)
 {
        unsigned long ip;
index c2897b7b4a3b1c7a6cfe4fe7e70b3d7378432d4c..46d58448c3aff9039fdf0b909d069d00d80ef75e 100644 (file)
@@ -52,7 +52,7 @@ static __initconst const u64 amd_hw_cache_event_ids
  [ C(DTLB) ] = {
        [ C(OP_READ) ] = {
                [ C(RESULT_ACCESS) ] = 0x0040, /* Data Cache Accesses        */
-               [ C(RESULT_MISS)   ] = 0x0046, /* L1 DTLB and L2 DLTB Miss   */
+               [ C(RESULT_MISS)   ] = 0x0746, /* L1_DTLB_AND_L2_DLTB_MISS.ALL */
        },
        [ C(OP_WRITE) ] = {
                [ C(RESULT_ACCESS) ] = 0,
@@ -66,7 +66,7 @@ static __initconst const u64 amd_hw_cache_event_ids
  [ C(ITLB) ] = {
        [ C(OP_READ) ] = {
                [ C(RESULT_ACCESS) ] = 0x0080, /* Instruction fecthes        */
-               [ C(RESULT_MISS)   ] = 0x0085, /* Instr. fetch ITLB misses   */
+               [ C(RESULT_MISS)   ] = 0x0385, /* L1_ITLB_AND_L2_ITLB_MISS.ALL */
        },
        [ C(OP_WRITE) ] = {
                [ C(RESULT_ACCESS) ] = -1,
index ee05c90012d269e66de9ffb6a5952d1434317c1e..c8f5c088cad11ae3f245e1e7374bb43c915170d6 100644 (file)
@@ -713,18 +713,18 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
        struct cpu_hw_events *cpuc;
        int bit, loops;
        u64 status;
-       int handled = 0;
+       int handled;
 
        perf_sample_data_init(&data, 0);
 
        cpuc = &__get_cpu_var(cpu_hw_events);
 
        intel_pmu_disable_all();
-       intel_pmu_drain_bts_buffer();
+       handled = intel_pmu_drain_bts_buffer();
        status = intel_pmu_get_status();
        if (!status) {
                intel_pmu_enable_all(0);
-               return 0;
+               return handled;
        }
 
        loops = 0;
@@ -763,7 +763,7 @@ again:
                data.period = event->hw.last_period;
 
                if (perf_event_overflow(event, 1, &data, regs))
-                       x86_pmu_stop(event);
+                       x86_pmu_stop(event, 0);
        }
 
        /*
index 18018d1311cdf3fa7f550b2fd7894c278505afe6..b7dcd9f2b8a04b8204762e50700264570e8ce498 100644 (file)
@@ -74,6 +74,107 @@ static void fini_debug_store_on_cpu(int cpu)
        wrmsr_on_cpu(cpu, MSR_IA32_DS_AREA, 0, 0);
 }
 
+static int alloc_pebs_buffer(int cpu)
+{
+       struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+       int node = cpu_to_node(cpu);
+       int max, thresh = 1; /* always use a single PEBS record */
+       void *buffer;
+
+       if (!x86_pmu.pebs)
+               return 0;
+
+       buffer = kmalloc_node(PEBS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
+       if (unlikely(!buffer))
+               return -ENOMEM;
+
+       max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
+
+       ds->pebs_buffer_base = (u64)(unsigned long)buffer;
+       ds->pebs_index = ds->pebs_buffer_base;
+       ds->pebs_absolute_maximum = ds->pebs_buffer_base +
+               max * x86_pmu.pebs_record_size;
+
+       ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
+               thresh * x86_pmu.pebs_record_size;
+
+       return 0;
+}
+
+static void release_pebs_buffer(int cpu)
+{
+       struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+       if (!ds || !x86_pmu.pebs)
+               return;
+
+       kfree((void *)(unsigned long)ds->pebs_buffer_base);
+       ds->pebs_buffer_base = 0;
+}
+
+static int alloc_bts_buffer(int cpu)
+{
+       struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+       int node = cpu_to_node(cpu);
+       int max, thresh;
+       void *buffer;
+
+       if (!x86_pmu.bts)
+               return 0;
+
+       buffer = kmalloc_node(BTS_BUFFER_SIZE, GFP_KERNEL | __GFP_ZERO, node);
+       if (unlikely(!buffer))
+               return -ENOMEM;
+
+       max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE;
+       thresh = max / 16;
+
+       ds->bts_buffer_base = (u64)(unsigned long)buffer;
+       ds->bts_index = ds->bts_buffer_base;
+       ds->bts_absolute_maximum = ds->bts_buffer_base +
+               max * BTS_RECORD_SIZE;
+       ds->bts_interrupt_threshold = ds->bts_absolute_maximum -
+               thresh * BTS_RECORD_SIZE;
+
+       return 0;
+}
+
+static void release_bts_buffer(int cpu)
+{
+       struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+       if (!ds || !x86_pmu.bts)
+               return;
+
+       kfree((void *)(unsigned long)ds->bts_buffer_base);
+       ds->bts_buffer_base = 0;
+}
+
+static int alloc_ds_buffer(int cpu)
+{
+       int node = cpu_to_node(cpu);
+       struct debug_store *ds;
+
+       ds = kmalloc_node(sizeof(*ds), GFP_KERNEL | __GFP_ZERO, node);
+       if (unlikely(!ds))
+               return -ENOMEM;
+
+       per_cpu(cpu_hw_events, cpu).ds = ds;
+
+       return 0;
+}
+
+static void release_ds_buffer(int cpu)
+{
+       struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
+
+       if (!ds)
+               return;
+
+       per_cpu(cpu_hw_events, cpu).ds = NULL;
+       kfree(ds);
+}
+
 static void release_ds_buffers(void)
 {
        int cpu;
@@ -82,93 +183,77 @@ static void release_ds_buffers(void)
                return;
 
        get_online_cpus();
-
        for_each_online_cpu(cpu)
                fini_debug_store_on_cpu(cpu);
 
        for_each_possible_cpu(cpu) {
-               struct debug_store *ds = per_cpu(cpu_hw_events, cpu).ds;
-
-               if (!ds)
-                       continue;
-
-               per_cpu(cpu_hw_events, cpu).ds = NULL;
-
-               kfree((void *)(unsigned long)ds->pebs_buffer_base);
-               kfree((void *)(unsigned long)ds->bts_buffer_base);
-               kfree(ds);
+               release_pebs_buffer(cpu);
+               release_bts_buffer(cpu);
+               release_ds_buffer(cpu);
        }
-
        put_online_cpus();
 }
 
-static int reserve_ds_buffers(void)
+static void reserve_ds_buffers(void)
 {
-       int cpu, err = 0;
+       int bts_err = 0, pebs_err = 0;
+       int cpu;
+
+       x86_pmu.bts_active = 0;
+       x86_pmu.pebs_active = 0;
 
        if (!x86_pmu.bts && !x86_pmu.pebs)
-               return 0;
+               return;
+
+       if (!x86_pmu.bts)
+               bts_err = 1;
+
+       if (!x86_pmu.pebs)
+               pebs_err = 1;
 
        get_online_cpus();
 
        for_each_possible_cpu(cpu) {
-               struct debug_store *ds;
-               void *buffer;
-               int max, thresh;
+               if (alloc_ds_buffer(cpu)) {
+                       bts_err = 1;
+                       pebs_err = 1;
+               }
+
+               if (!bts_err && alloc_bts_buffer(cpu))
+                       bts_err = 1;
+
+               if (!pebs_err && alloc_pebs_buffer(cpu))
+                       pebs_err = 1;
 
-               err = -ENOMEM;
-               ds = kzalloc(sizeof(*ds), GFP_KERNEL);
-               if (unlikely(!ds))
+               if (bts_err && pebs_err)
                        break;
-               per_cpu(cpu_hw_events, cpu).ds = ds;
-
-               if (x86_pmu.bts) {
-                       buffer = kzalloc(BTS_BUFFER_SIZE, GFP_KERNEL);
-                       if (unlikely(!buffer))
-                               break;
-
-                       max = BTS_BUFFER_SIZE / BTS_RECORD_SIZE;
-                       thresh = max / 16;
-
-                       ds->bts_buffer_base = (u64)(unsigned long)buffer;
-                       ds->bts_index = ds->bts_buffer_base;
-                       ds->bts_absolute_maximum = ds->bts_buffer_base +
-                               max * BTS_RECORD_SIZE;
-                       ds->bts_interrupt_threshold = ds->bts_absolute_maximum -
-                               thresh * BTS_RECORD_SIZE;
-               }
+       }
 
-               if (x86_pmu.pebs) {
-                       buffer = kzalloc(PEBS_BUFFER_SIZE, GFP_KERNEL);
-                       if (unlikely(!buffer))
-                               break;
-
-                       max = PEBS_BUFFER_SIZE / x86_pmu.pebs_record_size;
-
-                       ds->pebs_buffer_base = (u64)(unsigned long)buffer;
-                       ds->pebs_index = ds->pebs_buffer_base;
-                       ds->pebs_absolute_maximum = ds->pebs_buffer_base +
-                               max * x86_pmu.pebs_record_size;
-                       /*
-                        * Always use single record PEBS
-                        */
-                       ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
-                               x86_pmu.pebs_record_size;
-               }
+       if (bts_err) {
+               for_each_possible_cpu(cpu)
+                       release_bts_buffer(cpu);
+       }
 
-               err = 0;
+       if (pebs_err) {
+               for_each_possible_cpu(cpu)
+                       release_pebs_buffer(cpu);
        }
 
-       if (err)
-               release_ds_buffers();
-       else {
+       if (bts_err && pebs_err) {
+               for_each_possible_cpu(cpu)
+                       release_ds_buffer(cpu);
+       } else {
+               if (x86_pmu.bts && !bts_err)
+                       x86_pmu.bts_active = 1;
+
+               if (x86_pmu.pebs && !pebs_err)
+                       x86_pmu.pebs_active = 1;
+
                for_each_online_cpu(cpu)
                        init_debug_store_on_cpu(cpu);
        }
 
        put_online_cpus();
-
-       return err;
 }
 
 /*
@@ -214,7 +299,7 @@ static void intel_pmu_disable_bts(void)
        update_debugctlmsr(debugctlmsr);
 }
 
-static void intel_pmu_drain_bts_buffer(void)
+static int intel_pmu_drain_bts_buffer(void)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct debug_store *ds = cpuc->ds;
@@ -231,16 +316,16 @@ static void intel_pmu_drain_bts_buffer(void)
        struct pt_regs regs;
 
        if (!event)
-               return;
+               return 0;
 
-       if (!ds)
-               return;
+       if (!x86_pmu.bts_active)
+               return 0;
 
        at  = (struct bts_record *)(unsigned long)ds->bts_buffer_base;
        top = (struct bts_record *)(unsigned long)ds->bts_index;
 
        if (top <= at)
-               return;
+               return 0;
 
        ds->bts_index = ds->bts_buffer_base;
 
@@ -256,7 +341,7 @@ static void intel_pmu_drain_bts_buffer(void)
        perf_prepare_sample(&header, &data, event, &regs);
 
        if (perf_output_begin(&handle, event, header.size * (top - at), 1, 1))
-               return;
+               return 1;
 
        for (; at < top; at++) {
                data.ip         = at->from;
@@ -270,6 +355,7 @@ static void intel_pmu_drain_bts_buffer(void)
        /* There's new data available. */
        event->hw.interrupts++;
        event->pending_kill = POLL_IN;
+       return 1;
 }
 
 /*
@@ -491,7 +577,7 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
                regs.flags &= ~PERF_EFLAGS_EXACT;
 
        if (perf_event_overflow(event, 1, &data, &regs))
-               x86_pmu_stop(event);
+               x86_pmu_stop(event, 0);
 }
 
 static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
@@ -502,7 +588,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
        struct pebs_record_core *at, *top;
        int n;
 
-       if (!ds || !x86_pmu.pebs)
+       if (!x86_pmu.pebs_active)
                return;
 
        at  = (struct pebs_record_core *)(unsigned long)ds->pebs_buffer_base;
@@ -544,7 +630,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
        u64 status = 0;
        int bit, n;
 
-       if (!ds || !x86_pmu.pebs)
+       if (!x86_pmu.pebs_active)
                return;
 
        at  = (struct pebs_record_nhm *)(unsigned long)ds->pebs_buffer_base;
@@ -629,9 +715,8 @@ static void intel_ds_init(void)
 
 #else /* CONFIG_CPU_SUP_INTEL */
 
-static int reserve_ds_buffers(void)
+static void reserve_ds_buffers(void)
 {
-       return 0;
 }
 
 static void release_ds_buffers(void)
index 2490151739921e074085a5d4a39a6cfb783f7187..81400b93e69483e18bedf1c541753e2f915910cd 100644 (file)
@@ -18,6 +18,8 @@
 struct p4_event_bind {
        unsigned int opcode;                    /* Event code and ESCR selector */
        unsigned int escr_msr[2];               /* ESCR MSR for this event */
+       unsigned int escr_emask;                /* valid ESCR EventMask bits */
+       unsigned int shared;                    /* event is shared across threads */
        char cntr[2][P4_CNTR_LIMIT];            /* counter index (offset), -1 on abscence */
 };
 
@@ -66,231 +68,435 @@ static struct p4_event_bind p4_event_bind_map[] = {
        [P4_EVENT_TC_DELIVER_MODE] = {
                .opcode         = P4_OPCODE(P4_EVENT_TC_DELIVER_MODE),
                .escr_msr       = { MSR_P4_TC_ESCR0, MSR_P4_TC_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, DD)                 |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, DB)                 |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, DI)                 |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, BD)                 |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, BB)                 |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, BI)                 |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_TC_DELIVER_MODE, ID),
+               .shared         = 1,
                .cntr           = { {4, 5, -1}, {6, 7, -1} },
        },
        [P4_EVENT_BPU_FETCH_REQUEST] = {
                .opcode         = P4_OPCODE(P4_EVENT_BPU_FETCH_REQUEST),
                .escr_msr       = { MSR_P4_BPU_ESCR0, MSR_P4_BPU_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BPU_FETCH_REQUEST, TCMISS),
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_ITLB_REFERENCE] = {
                .opcode         = P4_OPCODE(P4_EVENT_ITLB_REFERENCE),
                .escr_msr       = { MSR_P4_ITLB_ESCR0, MSR_P4_ITLB_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_ITLB_REFERENCE, HIT)                 |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_ITLB_REFERENCE, MISS)                |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_ITLB_REFERENCE, HIT_UK),
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_MEMORY_CANCEL] = {
                .opcode         = P4_OPCODE(P4_EVENT_MEMORY_CANCEL),
                .escr_msr       = { MSR_P4_DAC_ESCR0, MSR_P4_DAC_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_CANCEL, ST_RB_FULL)           |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_CANCEL, 64K_CONF),
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_MEMORY_COMPLETE] = {
                .opcode         = P4_OPCODE(P4_EVENT_MEMORY_COMPLETE),
                .escr_msr       = { MSR_P4_SAAT_ESCR0 , MSR_P4_SAAT_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_COMPLETE, LSC)                |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MEMORY_COMPLETE, SSC),
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_LOAD_PORT_REPLAY] = {
                .opcode         = P4_OPCODE(P4_EVENT_LOAD_PORT_REPLAY),
                .escr_msr       = { MSR_P4_SAAT_ESCR0, MSR_P4_SAAT_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_LOAD_PORT_REPLAY, SPLIT_LD),
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_STORE_PORT_REPLAY] = {
                .opcode         = P4_OPCODE(P4_EVENT_STORE_PORT_REPLAY),
                .escr_msr       = { MSR_P4_SAAT_ESCR0 ,  MSR_P4_SAAT_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_STORE_PORT_REPLAY, SPLIT_ST),
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_MOB_LOAD_REPLAY] = {
                .opcode         = P4_OPCODE(P4_EVENT_MOB_LOAD_REPLAY),
                .escr_msr       = { MSR_P4_MOB_ESCR0, MSR_P4_MOB_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, NO_STA)             |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, NO_STD)             |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, PARTIAL_DATA)       |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MOB_LOAD_REPLAY, UNALGN_ADDR),
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_PAGE_WALK_TYPE] = {
                .opcode         = P4_OPCODE(P4_EVENT_PAGE_WALK_TYPE),
                .escr_msr       = { MSR_P4_PMH_ESCR0, MSR_P4_PMH_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_PAGE_WALK_TYPE, DTMISS)              |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_PAGE_WALK_TYPE, ITMISS),
+               .shared         = 1,
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_BSQ_CACHE_REFERENCE] = {
                .opcode         = P4_OPCODE(P4_EVENT_BSQ_CACHE_REFERENCE),
                .escr_msr       = { MSR_P4_BSU_ESCR0, MSR_P4_BSU_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITS)   |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITE)   |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_HITM)   |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITS)   |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITE)   |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_HITM)   |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_2ndL_MISS)   |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, RD_3rdL_MISS)   |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_CACHE_REFERENCE, WR_2ndL_MISS),
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_IOQ_ALLOCATION] = {
                .opcode         = P4_OPCODE(P4_EVENT_IOQ_ALLOCATION),
                .escr_msr       = { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, DEFAULT)             |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, ALL_READ)            |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, ALL_WRITE)           |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_UC)              |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WC)              |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WT)              |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WP)              |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, MEM_WB)              |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, OWN)                 |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, OTHER)               |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ALLOCATION, PREFETCH),
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_IOQ_ACTIVE_ENTRIES] = {       /* shared ESCR */
                .opcode         = P4_OPCODE(P4_EVENT_IOQ_ACTIVE_ENTRIES),
                .escr_msr       = { MSR_P4_FSB_ESCR1,  MSR_P4_FSB_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, DEFAULT)         |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, ALL_READ)        |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, ALL_WRITE)       |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_UC)          |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WC)          |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WT)          |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WP)          |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, MEM_WB)          |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, OWN)             |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, OTHER)           |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_IOQ_ACTIVE_ENTRIES, PREFETCH),
                .cntr           = { {2, -1, -1}, {3, -1, -1} },
        },
        [P4_EVENT_FSB_DATA_ACTIVITY] = {
                .opcode         = P4_OPCODE(P4_EVENT_FSB_DATA_ACTIVITY),
                .escr_msr       = { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_DRV)         |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_OWN)         |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DRDY_OTHER)       |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DBSY_DRV)         |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DBSY_OWN)         |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_FSB_DATA_ACTIVITY, DBSY_OTHER),
+               .shared         = 1,
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_BSQ_ALLOCATION] = {           /* shared ESCR, broken CCCR1 */
                .opcode         = P4_OPCODE(P4_EVENT_BSQ_ALLOCATION),
                .escr_msr       = { MSR_P4_BSU_ESCR0, MSR_P4_BSU_ESCR0 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_TYPE0)           |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_TYPE1)           |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_LEN0)            |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_LEN1)            |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_IO_TYPE)         |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_LOCK_TYPE)       |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_CACHE_TYPE)      |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_SPLIT_TYPE)      |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_DEM_TYPE)        |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, REQ_ORD_TYPE)        |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, MEM_TYPE0)           |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, MEM_TYPE1)           |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ALLOCATION, MEM_TYPE2),
                .cntr           = { {0, -1, -1}, {1, -1, -1} },
        },
        [P4_EVENT_BSQ_ACTIVE_ENTRIES] = {       /* shared ESCR */
                .opcode         = P4_OPCODE(P4_EVENT_BSQ_ACTIVE_ENTRIES),
                .escr_msr       = { MSR_P4_BSU_ESCR1 , MSR_P4_BSU_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_TYPE0)       |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_TYPE1)       |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_LEN0)        |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_LEN1)        |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_IO_TYPE)     |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_LOCK_TYPE)   |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_CACHE_TYPE)  |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_SPLIT_TYPE)  |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_DEM_TYPE)    |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, REQ_ORD_TYPE)    |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, MEM_TYPE0)       |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, MEM_TYPE1)       |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BSQ_ACTIVE_ENTRIES, MEM_TYPE2),
                .cntr           = { {2, -1, -1}, {3, -1, -1} },
        },
        [P4_EVENT_SSE_INPUT_ASSIST] = {
                .opcode         = P4_OPCODE(P4_EVENT_SSE_INPUT_ASSIST),
                .escr_msr       = { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_SSE_INPUT_ASSIST, ALL),
+               .shared         = 1,
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_PACKED_SP_UOP] = {
                .opcode         = P4_OPCODE(P4_EVENT_PACKED_SP_UOP),
                .escr_msr       = { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_PACKED_SP_UOP, ALL),
+               .shared         = 1,
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_PACKED_DP_UOP] = {
                .opcode         = P4_OPCODE(P4_EVENT_PACKED_DP_UOP),
                .escr_msr       = { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_PACKED_DP_UOP, ALL),
+               .shared         = 1,
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_SCALAR_SP_UOP] = {
                .opcode         = P4_OPCODE(P4_EVENT_SCALAR_SP_UOP),
                .escr_msr       = { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_SCALAR_SP_UOP, ALL),
+               .shared         = 1,
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_SCALAR_DP_UOP] = {
                .opcode         = P4_OPCODE(P4_EVENT_SCALAR_DP_UOP),
                .escr_msr       = { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_SCALAR_DP_UOP, ALL),
+               .shared         = 1,
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_64BIT_MMX_UOP] = {
                .opcode         = P4_OPCODE(P4_EVENT_64BIT_MMX_UOP),
                .escr_msr       = { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_64BIT_MMX_UOP, ALL),
+               .shared         = 1,
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_128BIT_MMX_UOP] = {
                .opcode         = P4_OPCODE(P4_EVENT_128BIT_MMX_UOP),
                .escr_msr       = { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_128BIT_MMX_UOP, ALL),
+               .shared         = 1,
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_X87_FP_UOP] = {
                .opcode         = P4_OPCODE(P4_EVENT_X87_FP_UOP),
                .escr_msr       = { MSR_P4_FIRM_ESCR0, MSR_P4_FIRM_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_X87_FP_UOP, ALL),
+               .shared         = 1,
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_TC_MISC] = {
                .opcode         = P4_OPCODE(P4_EVENT_TC_MISC),
                .escr_msr       = { MSR_P4_TC_ESCR0, MSR_P4_TC_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_TC_MISC, FLUSH),
                .cntr           = { {4, 5, -1}, {6, 7, -1} },
        },
        [P4_EVENT_GLOBAL_POWER_EVENTS] = {
                .opcode         = P4_OPCODE(P4_EVENT_GLOBAL_POWER_EVENTS),
                .escr_msr       = { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_GLOBAL_POWER_EVENTS, RUNNING),
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_TC_MS_XFER] = {
                .opcode         = P4_OPCODE(P4_EVENT_TC_MS_XFER),
                .escr_msr       = { MSR_P4_MS_ESCR0, MSR_P4_MS_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_TC_MS_XFER, CISC),
                .cntr           = { {4, 5, -1}, {6, 7, -1} },
        },
        [P4_EVENT_UOP_QUEUE_WRITES] = {
                .opcode         = P4_OPCODE(P4_EVENT_UOP_QUEUE_WRITES),
                .escr_msr       = { MSR_P4_MS_ESCR0, MSR_P4_MS_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_UOP_QUEUE_WRITES, FROM_TC_BUILD)     |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_UOP_QUEUE_WRITES, FROM_TC_DELIVER)   |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_UOP_QUEUE_WRITES, FROM_ROM),
                .cntr           = { {4, 5, -1}, {6, 7, -1} },
        },
        [P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE] = {
                .opcode         = P4_OPCODE(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE),
                .escr_msr       = { MSR_P4_TBPU_ESCR0 , MSR_P4_TBPU_ESCR0 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, CONDITIONAL)    |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, CALL)           |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, RETURN)         |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_MISPRED_BRANCH_TYPE, INDIRECT),
                .cntr           = { {4, 5, -1}, {6, 7, -1} },
        },
        [P4_EVENT_RETIRED_BRANCH_TYPE] = {
                .opcode         = P4_OPCODE(P4_EVENT_RETIRED_BRANCH_TYPE),
                .escr_msr       = { MSR_P4_TBPU_ESCR0 , MSR_P4_TBPU_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, CONDITIONAL)    |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, CALL)           |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, RETURN)         |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_RETIRED_BRANCH_TYPE, INDIRECT),
                .cntr           = { {4, 5, -1}, {6, 7, -1} },
        },
        [P4_EVENT_RESOURCE_STALL] = {
                .opcode         = P4_OPCODE(P4_EVENT_RESOURCE_STALL),
                .escr_msr       = { MSR_P4_ALF_ESCR0, MSR_P4_ALF_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_RESOURCE_STALL, SBFULL),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_WC_BUFFER] = {
                .opcode         = P4_OPCODE(P4_EVENT_WC_BUFFER),
                .escr_msr       = { MSR_P4_DAC_ESCR0, MSR_P4_DAC_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_WC_BUFFER, WCB_EVICTS)               |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_WC_BUFFER, WCB_FULL_EVICTS),
+               .shared         = 1,
                .cntr           = { {8, 9, -1}, {10, 11, -1} },
        },
        [P4_EVENT_B2B_CYCLES] = {
                .opcode         = P4_OPCODE(P4_EVENT_B2B_CYCLES),
                .escr_msr       = { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+               .escr_emask     = 0,
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_BNR] = {
                .opcode         = P4_OPCODE(P4_EVENT_BNR),
                .escr_msr       = { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+               .escr_emask     = 0,
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_SNOOP] = {
                .opcode         = P4_OPCODE(P4_EVENT_SNOOP),
                .escr_msr       = { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+               .escr_emask     = 0,
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_RESPONSE] = {
                .opcode         = P4_OPCODE(P4_EVENT_RESPONSE),
                .escr_msr       = { MSR_P4_FSB_ESCR0, MSR_P4_FSB_ESCR1 },
+               .escr_emask     = 0,
                .cntr           = { {0, -1, -1}, {2, -1, -1} },
        },
        [P4_EVENT_FRONT_END_EVENT] = {
                .opcode         = P4_OPCODE(P4_EVENT_FRONT_END_EVENT),
                .escr_msr       = { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_FRONT_END_EVENT, NBOGUS)             |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_FRONT_END_EVENT, BOGUS),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_EXECUTION_EVENT] = {
                .opcode         = P4_OPCODE(P4_EVENT_EXECUTION_EVENT),
                .escr_msr       = { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS0)            |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS1)            |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS2)            |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, NBOGUS3)            |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS0)             |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS1)             |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS2)             |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_EXECUTION_EVENT, BOGUS3),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_REPLAY_EVENT] = {
                .opcode         = P4_OPCODE(P4_EVENT_REPLAY_EVENT),
                .escr_msr       = { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_REPLAY_EVENT, NBOGUS)                |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_REPLAY_EVENT, BOGUS),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_INSTR_RETIRED] = {
                .opcode         = P4_OPCODE(P4_EVENT_INSTR_RETIRED),
                .escr_msr       = { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, NBOGUSNTAG)           |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, NBOGUSTAG)            |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, BOGUSNTAG)            |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_RETIRED, BOGUSTAG),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_UOPS_RETIRED] = {
                .opcode         = P4_OPCODE(P4_EVENT_UOPS_RETIRED),
                .escr_msr       = { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_UOPS_RETIRED, NBOGUS)                |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_UOPS_RETIRED, BOGUS),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_UOP_TYPE] = {
                .opcode         = P4_OPCODE(P4_EVENT_UOP_TYPE),
                .escr_msr       = { MSR_P4_RAT_ESCR0, MSR_P4_RAT_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_UOP_TYPE, TAGLOADS)                  |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_UOP_TYPE, TAGSTORES),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_BRANCH_RETIRED] = {
                .opcode         = P4_OPCODE(P4_EVENT_BRANCH_RETIRED),
                .escr_msr       = { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMNP)                |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMNM)                |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMTP)                |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_BRANCH_RETIRED, MMTM),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_MISPRED_BRANCH_RETIRED] = {
                .opcode         = P4_OPCODE(P4_EVENT_MISPRED_BRANCH_RETIRED),
                .escr_msr       = { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+               .escr_emask     =
+               P4_ESCR_EMASK_BIT(P4_EVENT_MISPRED_BRANCH_RETIRED, NBOGUS),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_X87_ASSIST] = {
                .opcode         = P4_OPCODE(P4_EVENT_X87_ASSIST),
                .escr_msr       = { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, FPSU)                    |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, FPSO)                    |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, POAO)                    |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, POAU)                    |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_X87_ASSIST, PREA),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_MACHINE_CLEAR] = {
                .opcode         = P4_OPCODE(P4_EVENT_MACHINE_CLEAR),
                .escr_msr       = { MSR_P4_CRU_ESCR2, MSR_P4_CRU_ESCR3 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MACHINE_CLEAR, CLEAR)                |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MACHINE_CLEAR, MOCLEAR)              |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_MACHINE_CLEAR, SMCLEAR),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
        [P4_EVENT_INSTR_COMPLETED] = {
                .opcode         = P4_OPCODE(P4_EVENT_INSTR_COMPLETED),
                .escr_msr       = { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
+               .escr_emask     =
+                       P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_COMPLETED, NBOGUS)             |
+                       P4_ESCR_EMASK_BIT(P4_EVENT_INSTR_COMPLETED, BOGUS),
                .cntr           = { {12, 13, 16}, {14, 15, 17} },
        },
 };
@@ -428,29 +634,73 @@ static u64 p4_pmu_event_map(int hw_event)
        return config;
 }
 
+/* check cpu model specifics */
+static bool p4_event_match_cpu_model(unsigned int event_idx)
+{
+       /* INSTR_COMPLETED event only exist for model 3, 4, 6 (Prescott) */
+       if (event_idx == P4_EVENT_INSTR_COMPLETED) {
+               if (boot_cpu_data.x86_model != 3 &&
+                       boot_cpu_data.x86_model != 4 &&
+                       boot_cpu_data.x86_model != 6)
+                       return false;
+       }
+
+       /*
+        * For info
+        * - IQ_ESCR0, IQ_ESCR1 only for models 1 and 2
+        */
+
+       return true;
+}
+
 static int p4_validate_raw_event(struct perf_event *event)
 {
-       unsigned int v;
+       unsigned int v, emask;
 
-       /* user data may have out-of-bound event index */
+       /* User data may have out-of-bound event index */
        v = p4_config_unpack_event(event->attr.config);
-       if (v >= ARRAY_SIZE(p4_event_bind_map)) {
-               pr_warning("P4 PMU: Unknown event code: %d\n", v);
+       if (v >= ARRAY_SIZE(p4_event_bind_map))
+               return -EINVAL;
+
+       /* It may be unsupported: */
+       if (!p4_event_match_cpu_model(v))
                return -EINVAL;
+
+       /*
+        * NOTE: P4_CCCR_THREAD_ANY has not the same meaning as
+        * in Architectural Performance Monitoring, it means not
+        * on _which_ logical cpu to count but rather _when_, ie it
+        * depends on logical cpu state -- count event if one cpu active,
+        * none, both or any, so we just allow user to pass any value
+        * desired.
+        *
+        * In turn we always set Tx_OS/Tx_USR bits bound to logical
+        * cpu without their propagation to another cpu
+        */
+
+       /*
+        * if an event is shared accross the logical threads
+        * the user needs special permissions to be able to use it
+        */
+       if (p4_event_bind_map[v].shared) {
+               if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
+                       return -EACCES;
        }
 
+       /* ESCR EventMask bits may be invalid */
+       emask = p4_config_unpack_escr(event->attr.config) & P4_ESCR_EVENTMASK_MASK;
+       if (emask & ~p4_event_bind_map[v].escr_emask)
+               return -EINVAL;
+
        /*
-        * it may have some screwed PEBS bits
+        * it may have some invalid PEBS bits
         */
-       if (p4_config_pebs_has(event->attr.config, P4_PEBS_CONFIG_ENABLE)) {
-               pr_warning("P4 PMU: PEBS are not supported yet\n");
+       if (p4_config_pebs_has(event->attr.config, P4_PEBS_CONFIG_ENABLE))
                return -EINVAL;
-       }
+
        v = p4_config_unpack_metric(event->attr.config);
-       if (v >= ARRAY_SIZE(p4_pebs_bind_map)) {
-               pr_warning("P4 PMU: Unknown metric code: %d\n", v);
+       if (v >= ARRAY_SIZE(p4_pebs_bind_map))
                return -EINVAL;
-       }
 
        return 0;
 }
@@ -478,27 +728,21 @@ static int p4_hw_config(struct perf_event *event)
 
        if (event->attr.type == PERF_TYPE_RAW) {
 
+               /*
+                * Clear bits we reserve to be managed by kernel itself
+                * and never allowed from a user space
+                */
+                event->attr.config &= P4_CONFIG_MASK;
+
                rc = p4_validate_raw_event(event);
                if (rc)
                        goto out;
 
                /*
-                * We don't control raw events so it's up to the caller
-                * to pass sane values (and we don't count the thread number
-                * on HT machine but allow HT-compatible specifics to be
-                * passed on)
-                *
                 * Note that for RAW events we allow user to use P4_CCCR_RESERVED
                 * bits since we keep additional info here (for cache events and etc)
-                *
-                * XXX: HT wide things should check perf_paranoid_cpu() &&
-                *      CAP_SYS_ADMIN
                 */
-               event->hw.config |= event->attr.config &
-                       (p4_config_pack_escr(P4_ESCR_MASK_HT) |
-                        p4_config_pack_cccr(P4_CCCR_MASK_HT | P4_CCCR_RESERVED));
-
-               event->hw.config &= ~P4_CCCR_FORCE_OVF;
+               event->hw.config |= event->attr.config;
        }
 
        rc = x86_setup_perfctr(event);
index fb329e9f849443315e19c8db38c01161f5edf73b..d9f4ff8fcd693c509b2d079b381a8e8683d10d9c 100644 (file)
@@ -700,11 +700,10 @@ static void probe_nmi_watchdog(void)
 {
        switch (boot_cpu_data.x86_vendor) {
        case X86_VENDOR_AMD:
-               if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 &&
-                   boot_cpu_data.x86 != 16 && boot_cpu_data.x86 != 17)
-                       return;
-               wd_ops = &k7_wd_ops;
-               break;
+               if (boot_cpu_data.x86 == 6 ||
+                   (boot_cpu_data.x86 >= 0xf && boot_cpu_data.x86 <= 0x15))
+                       wd_ops = &k7_wd_ops;
+               return;
        case X86_VENDOR_INTEL:
                /* Work around where perfctr1 doesn't have a working enable
                 * bit as described in the following errata:
index d49079515122a6f47d2731cb1d2ac2f03efaf6e0..c7f64e6f537a8dc5195e6d37082b205d6df5cfbd 100644 (file)
@@ -44,6 +44,12 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c)
                { X86_FEATURE_LBRV,             CR_EDX, 1, 0x8000000a, 0 },
                { X86_FEATURE_SVML,             CR_EDX, 2, 0x8000000a, 0 },
                { X86_FEATURE_NRIPS,            CR_EDX, 3, 0x8000000a, 0 },
+               { X86_FEATURE_TSCRATEMSR,       CR_EDX, 4, 0x8000000a, 0 },
+               { X86_FEATURE_VMCBCLEAN,        CR_EDX, 5, 0x8000000a, 0 },
+               { X86_FEATURE_FLUSHBYASID,      CR_EDX, 6, 0x8000000a, 0 },
+               { X86_FEATURE_DECODEASSISTS,    CR_EDX, 7, 0x8000000a, 0 },
+               { X86_FEATURE_PAUSEFILTER,      CR_EDX,10, 0x8000000a, 0 },
+               { X86_FEATURE_PFTHRESHOLD,      CR_EDX,12, 0x8000000a, 0 },
                { 0, 0, 0, 0, 0 }
        };
 
index 045b36cada655370382231cb186d45d5d8820d95..994828899e098350d12ca73217235af843b0d497 100644 (file)
@@ -34,7 +34,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
        if (!csize)
                return 0;
 
-       vaddr = ioremap(pfn << PAGE_SHIFT, PAGE_SIZE);
+       vaddr = ioremap_cache(pfn << PAGE_SHIFT, PAGE_SIZE);
        if (!vaddr)
                return -ENOMEM;
 
@@ -46,6 +46,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
        } else
                memcpy(buf, vaddr + offset, csize);
 
+       set_iounmap_nonlazy();
        iounmap(vaddr);
        return csize;
 }
index 0d6fc71bedb152802401b49eb801696cb5ee460d..0c2b7ef7a34d5453d510ba3a598e5b15c2af6b53 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/pfn.h>
 #include <linux/suspend.h>
 #include <linux/firmware-map.h>
+#include <linux/memblock.h>
 
 #include <asm/e820.h>
 #include <asm/proto.h>
@@ -738,73 +739,7 @@ core_initcall(e820_mark_nvs_memory);
 #endif
 
 /*
- * Find a free area with specified alignment in a specific range.
- */
-u64 __init find_e820_area(u64 start, u64 end, u64 size, u64 align)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-               u64 addr;
-               u64 ei_start, ei_last;
-
-               if (ei->type != E820_RAM)
-                       continue;
-
-               ei_last = ei->addr + ei->size;
-               ei_start = ei->addr;
-               addr = find_early_area(ei_start, ei_last, start, end,
-                                        size, align);
-
-               if (addr != -1ULL)
-                       return addr;
-       }
-       return -1ULL;
-}
-
-u64 __init find_fw_memmap_area(u64 start, u64 end, u64 size, u64 align)
-{
-       return find_e820_area(start, end, size, align);
-}
-
-u64 __init get_max_mapped(void)
-{
-       u64 end = max_pfn_mapped;
-
-       end <<= PAGE_SHIFT;
-
-       return end;
-}
-/*
- * Find next free range after *start
- */
-u64 __init find_e820_area_size(u64 start, u64 *sizep, u64 align)
-{
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               struct e820entry *ei = &e820.map[i];
-               u64 addr;
-               u64 ei_start, ei_last;
-
-               if (ei->type != E820_RAM)
-                       continue;
-
-               ei_last = ei->addr + ei->size;
-               ei_start = ei->addr;
-               addr = find_early_area_size(ei_start, ei_last, start,
-                                        sizep, align);
-
-               if (addr != -1ULL)
-                       return addr;
-       }
-
-       return -1ULL;
-}
-
-/*
- * pre allocated 4k and reserved it in e820
+ * pre allocated 4k and reserved it in memblock and e820_saved
  */
 u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
 {
@@ -813,8 +748,8 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
        u64 start;
 
        for (start = startt; ; start += size) {
-               start = find_e820_area_size(start, &size, align);
-               if (!(start + 1))
+               start = memblock_x86_find_in_range_size(start, &size, align);
+               if (start == MEMBLOCK_ERROR)
                        return 0;
                if (size >= sizet)
                        break;
@@ -830,10 +765,9 @@ u64 __init early_reserve_e820(u64 startt, u64 sizet, u64 align)
        addr = round_down(start + size - sizet, align);
        if (addr < start)
                return 0;
-       e820_update_range(addr, sizet, E820_RAM, E820_RESERVED);
+       memblock_x86_reserve_range(addr, addr + sizet, "new next");
        e820_update_range_saved(addr, sizet, E820_RAM, E820_RESERVED);
-       printk(KERN_INFO "update e820 for early_reserve_e820\n");
-       update_e820();
+       printk(KERN_INFO "update e820_saved for early_reserve_e820\n");
        update_e820_saved();
 
        return addr;
@@ -895,74 +829,6 @@ unsigned long __init e820_end_of_low_ram_pfn(void)
 {
        return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM);
 }
-/*
- * Finds an active region in the address range from start_pfn to last_pfn and
- * returns its range in ei_startpfn and ei_endpfn for the e820 entry.
- */
-int __init e820_find_active_region(const struct e820entry *ei,
-                                 unsigned long start_pfn,
-                                 unsigned long last_pfn,
-                                 unsigned long *ei_startpfn,
-                                 unsigned long *ei_endpfn)
-{
-       u64 align = PAGE_SIZE;
-
-       *ei_startpfn = round_up(ei->addr, align) >> PAGE_SHIFT;
-       *ei_endpfn = round_down(ei->addr + ei->size, align) >> PAGE_SHIFT;
-
-       /* Skip map entries smaller than a page */
-       if (*ei_startpfn >= *ei_endpfn)
-               return 0;
-
-       /* Skip if map is outside the node */
-       if (ei->type != E820_RAM || *ei_endpfn <= start_pfn ||
-                                   *ei_startpfn >= last_pfn)
-               return 0;
-
-       /* Check for overlaps */
-       if (*ei_startpfn < start_pfn)
-               *ei_startpfn = start_pfn;
-       if (*ei_endpfn > last_pfn)
-               *ei_endpfn = last_pfn;
-
-       return 1;
-}
-
-/* Walk the e820 map and register active regions within a node */
-void __init e820_register_active_regions(int nid, unsigned long start_pfn,
-                                        unsigned long last_pfn)
-{
-       unsigned long ei_startpfn;
-       unsigned long ei_endpfn;
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++)
-               if (e820_find_active_region(&e820.map[i],
-                                           start_pfn, last_pfn,
-                                           &ei_startpfn, &ei_endpfn))
-                       add_active_range(nid, ei_startpfn, ei_endpfn);
-}
-
-/*
- * Find the hole size (in bytes) in the memory range.
- * @start: starting address of the memory range to scan
- * @end: ending address of the memory range to scan
- */
-u64 __init e820_hole_size(u64 start, u64 end)
-{
-       unsigned long start_pfn = start >> PAGE_SHIFT;
-       unsigned long last_pfn = end >> PAGE_SHIFT;
-       unsigned long ei_startpfn, ei_endpfn, ram = 0;
-       int i;
-
-       for (i = 0; i < e820.nr_map; i++) {
-               if (e820_find_active_region(&e820.map[i],
-                                           start_pfn, last_pfn,
-                                           &ei_startpfn, &ei_endpfn))
-                       ram += ei_endpfn - ei_startpfn;
-       }
-       return end - start - ((u64)ram << PAGE_SHIFT);
-}
 
 static void early_panic(char *msg)
 {
@@ -1210,3 +1076,48 @@ void __init setup_memory_map(void)
        printk(KERN_INFO "BIOS-provided physical RAM map:\n");
        e820_print_map(who);
 }
+
+void __init memblock_x86_fill(void)
+{
+       int i;
+       u64 end;
+
+       /*
+        * EFI may have more than 128 entries
+        * We are safe to enable resizing, beause memblock_x86_fill()
+        * is rather later for x86
+        */
+       memblock_can_resize = 1;
+
+       for (i = 0; i < e820.nr_map; i++) {
+               struct e820entry *ei = &e820.map[i];
+
+               end = ei->addr + ei->size;
+               if (end != (resource_size_t)end)
+                       continue;
+
+               if (ei->type != E820_RAM && ei->type != E820_RESERVED_KERN)
+                       continue;
+
+               memblock_add(ei->addr, ei->size);
+       }
+
+       memblock_analyze();
+       memblock_dump_all();
+}
+
+void __init memblock_find_dma_reserve(void)
+{
+#ifdef CONFIG_X86_64
+       u64 free_size_pfn;
+       u64 mem_size_pfn;
+       /*
+        * need to find out used area below MAX_DMA_PFN
+        * need to use memblock to get free size in [0, MAX_DMA_PFN]
+        * at first, and assume boot_mem will not take below MAX_DMA_PFN
+        */
+       mem_size_pfn = memblock_x86_memory_in_range(0, MAX_DMA_PFN << PAGE_SHIFT) >> PAGE_SHIFT;
+       free_size_pfn = memblock_x86_free_memory_in_range(0, MAX_DMA_PFN << PAGE_SHIFT) >> PAGE_SHIFT;
+       set_dma_reserve(mem_size_pfn - free_size_pfn);
+#endif
+}
index ebdb85cf2686fa36702cd4d50b657f22de85b3bd..76b8cd953deed9f8a50d572cdc52b5edb68bc3b7 100644 (file)
@@ -96,7 +96,6 @@ static void __init nvidia_bugs(int num, int slot, int func)
 
 }
 
-#if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC)
 #if defined(CONFIG_ACPI) && defined(CONFIG_X86_IO_APIC)
 static u32 __init ati_ixp4x0_rev(int num, int slot, int func)
 {
@@ -115,7 +114,6 @@ static u32 __init ati_ixp4x0_rev(int num, int slot, int func)
        d &= 0xff;
        return d;
 }
-#endif
 
 static void __init ati_bugs(int num, int slot, int func)
 {
index fa99bae75acee4d1efb12b141a24d97019e03b5f..4572f25f93255f8bb4a5e5158d3c9949f912b657 100644 (file)
@@ -14,6 +14,7 @@
 #include <xen/hvc-console.h>
 #include <asm/pci-direct.h>
 #include <asm/fixmap.h>
+#include <asm/mrst.h>
 #include <asm/pgtable.h>
 #include <linux/usb/ehci_def.h>
 
@@ -238,6 +239,18 @@ static int __init setup_early_printk(char *buf)
 #ifdef CONFIG_HVC_XEN
                if (!strncmp(buf, "xen", 3))
                        early_console_register(&xenboot_console, keep);
+#endif
+#ifdef CONFIG_X86_MRST_EARLY_PRINTK
+               if (!strncmp(buf, "mrst", 4)) {
+                       mrst_early_console_init();
+                       early_console_register(&early_mrst_console, keep);
+               }
+
+               if (!strncmp(buf, "hsu", 3)) {
+                       hsu_early_console_init();
+                       early_console_register(&early_hsu_console, keep);
+               }
+
 #endif
                buf++;
        }
diff --git a/arch/x86/kernel/early_printk_mrst.c b/arch/x86/kernel/early_printk_mrst.c
new file mode 100644 (file)
index 0000000..65df603
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * early_printk_mrst.c - early consoles for Intel MID platforms
+ *
+ * Copyright (c) 2008-2010, 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.
+ */
+
+/*
+ * This file implements two early consoles named mrst and hsu.
+ * mrst is based on Maxim3110 spi-uart device, it exists in both
+ * Moorestown and Medfield platforms, while hsu is based on a High
+ * Speed UART device which only exists in the Medfield platform
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/serial_mfd.h>
+#include <linux/kmsg_dump.h>
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <asm/fixmap.h>
+#include <asm/pgtable.h>
+#include <asm/mrst.h>
+
+#define MRST_SPI_TIMEOUT               0x200000
+#define MRST_REGBASE_SPI0              0xff128000
+#define MRST_REGBASE_SPI1              0xff128400
+#define MRST_CLK_SPI0_REG              0xff11d86c
+
+/* Bit fields in CTRLR0 */
+#define SPI_DFS_OFFSET                 0
+
+#define SPI_FRF_OFFSET                 4
+#define SPI_FRF_SPI                    0x0
+#define SPI_FRF_SSP                    0x1
+#define SPI_FRF_MICROWIRE              0x2
+#define SPI_FRF_RESV                   0x3
+
+#define SPI_MODE_OFFSET                        6
+#define SPI_SCPH_OFFSET                        6
+#define SPI_SCOL_OFFSET                        7
+#define SPI_TMOD_OFFSET                        8
+#define        SPI_TMOD_TR                     0x0             /* xmit & recv */
+#define SPI_TMOD_TO                    0x1             /* xmit only */
+#define SPI_TMOD_RO                    0x2             /* recv only */
+#define SPI_TMOD_EPROMREAD             0x3             /* eeprom read mode */
+
+#define SPI_SLVOE_OFFSET               10
+#define SPI_SRL_OFFSET                 11
+#define SPI_CFS_OFFSET                 12
+
+/* Bit fields in SR, 7 bits */
+#define SR_MASK                                0x7f            /* cover 7 bits */
+#define SR_BUSY                                (1 << 0)
+#define SR_TF_NOT_FULL                 (1 << 1)
+#define SR_TF_EMPT                     (1 << 2)
+#define SR_RF_NOT_EMPT                 (1 << 3)
+#define SR_RF_FULL                     (1 << 4)
+#define SR_TX_ERR                      (1 << 5)
+#define SR_DCOL                                (1 << 6)
+
+struct dw_spi_reg {
+       u32     ctrl0;
+       u32     ctrl1;
+       u32     ssienr;
+       u32     mwcr;
+       u32     ser;
+       u32     baudr;
+       u32     txfltr;
+       u32     rxfltr;
+       u32     txflr;
+       u32     rxflr;
+       u32     sr;
+       u32     imr;
+       u32     isr;
+       u32     risr;
+       u32     txoicr;
+       u32     rxoicr;
+       u32     rxuicr;
+       u32     msticr;
+       u32     icr;
+       u32     dmacr;
+       u32     dmatdlr;
+       u32     dmardlr;
+       u32     idr;
+       u32     version;
+
+       /* Currently operates as 32 bits, though only the low 16 bits matter */
+       u32     dr;
+} __packed;
+
+#define dw_readl(dw, name)             __raw_readl(&(dw)->name)
+#define dw_writel(dw, name, val)       __raw_writel((val), &(dw)->name)
+
+/* Default use SPI0 register for mrst, we will detect Penwell and use SPI1 */
+static unsigned long mrst_spi_paddr = MRST_REGBASE_SPI0;
+
+static u32 *pclk_spi0;
+/* Always contains an accessable address, start with 0 */
+static struct dw_spi_reg *pspi;
+
+static struct kmsg_dumper dw_dumper;
+static int dumper_registered;
+
+static void dw_kmsg_dump(struct kmsg_dumper *dumper,
+                       enum kmsg_dump_reason reason,
+                       const char *s1, unsigned long l1,
+                       const char *s2, unsigned long l2)
+{
+       int i;
+
+       /* When run to this, we'd better re-init the HW */
+       mrst_early_console_init();
+
+       for (i = 0; i < l1; i++)
+               early_mrst_console.write(&early_mrst_console, s1 + i, 1);
+       for (i = 0; i < l2; i++)
+               early_mrst_console.write(&early_mrst_console, s2 + i, 1);
+}
+
+/* Set the ratio rate to 115200, 8n1, IRQ disabled */
+static void max3110_write_config(void)
+{
+       u16 config;
+
+       config = 0xc001;
+       dw_writel(pspi, dr, config);
+}
+
+/* Translate char to a eligible word and send to max3110 */
+static void max3110_write_data(char c)
+{
+       u16 data;
+
+       data = 0x8000 | c;
+       dw_writel(pspi, dr, data);
+}
+
+void mrst_early_console_init(void)
+{
+       u32 ctrlr0 = 0;
+       u32 spi0_cdiv;
+       u32 freq; /* Freqency info only need be searched once */
+
+       /* Base clk is 100 MHz, the actual clk = 100M / (clk_divider + 1) */
+       pclk_spi0 = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
+                                                       MRST_CLK_SPI0_REG);
+       spi0_cdiv = ((*pclk_spi0) & 0xe00) >> 9;
+       freq = 100000000 / (spi0_cdiv + 1);
+
+       if (mrst_identify_cpu() == MRST_CPU_CHIP_PENWELL)
+               mrst_spi_paddr = MRST_REGBASE_SPI1;
+
+       pspi = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
+                                               mrst_spi_paddr);
+
+       /* Disable SPI controller */
+       dw_writel(pspi, ssienr, 0);
+
+       /* Set control param, 8 bits, transmit only mode */
+       ctrlr0 = dw_readl(pspi, ctrl0);
+
+       ctrlr0 &= 0xfcc0;
+       ctrlr0 |= 0xf | (SPI_FRF_SPI << SPI_FRF_OFFSET)
+                     | (SPI_TMOD_TO << SPI_TMOD_OFFSET);
+       dw_writel(pspi, ctrl0, ctrlr0);
+
+       /*
+        * Change the spi0 clk to comply with 115200 bps, use 100000 to
+        * calculate the clk dividor to make the clock a little slower
+        * than real baud rate.
+        */
+       dw_writel(pspi, baudr, freq/100000);
+
+       /* Disable all INT for early phase */
+       dw_writel(pspi, imr, 0x0);
+
+       /* Set the cs to spi-uart */
+       dw_writel(pspi, ser, 0x2);
+
+       /* Enable the HW, the last step for HW init */
+       dw_writel(pspi, ssienr, 0x1);
+
+       /* Set the default configuration */
+       max3110_write_config();
+
+       /* Register the kmsg dumper */
+       if (!dumper_registered) {
+               dw_dumper.dump = dw_kmsg_dump;
+               kmsg_dump_register(&dw_dumper);
+               dumper_registered = 1;
+       }
+}
+
+/* Slave select should be called in the read/write function */
+static void early_mrst_spi_putc(char c)
+{
+       unsigned int timeout;
+       u32 sr;
+
+       timeout = MRST_SPI_TIMEOUT;
+       /* Early putc needs to make sure the TX FIFO is not full */
+       while (--timeout) {
+               sr = dw_readl(pspi, sr);
+               if (!(sr & SR_TF_NOT_FULL))
+                       cpu_relax();
+               else
+                       break;
+       }
+
+       if (!timeout)
+               pr_warning("MRST earlycon: timed out\n");
+       else
+               max3110_write_data(c);
+}
+
+/* Early SPI only uses polling mode */
+static void early_mrst_spi_write(struct console *con, const char *str, unsigned n)
+{
+       int i;
+
+       for (i = 0; i < n && *str; i++) {
+               if (*str == '\n')
+                       early_mrst_spi_putc('\r');
+               early_mrst_spi_putc(*str);
+               str++;
+       }
+}
+
+struct console early_mrst_console = {
+       .name =         "earlymrst",
+       .write =        early_mrst_spi_write,
+       .flags =        CON_PRINTBUFFER,
+       .index =        -1,
+};
+
+/*
+ * Following is the early console based on Medfield HSU (High
+ * Speed UART) device.
+ */
+#define HSU_PORT2_PADDR                0xffa28180
+
+static void __iomem *phsu;
+
+void hsu_early_console_init(void)
+{
+       u8 lcr;
+
+       phsu = (void *)set_fixmap_offset_nocache(FIX_EARLYCON_MEM_BASE,
+                                                       HSU_PORT2_PADDR);
+
+       /* Disable FIFO */
+       writeb(0x0, phsu + UART_FCR);
+
+       /* Set to default 115200 bps, 8n1 */
+       lcr = readb(phsu + UART_LCR);
+       writeb((0x80 | lcr), phsu + UART_LCR);
+       writeb(0x18, phsu + UART_DLL);
+       writeb(lcr,  phsu + UART_LCR);
+       writel(0x3600, phsu + UART_MUL*4);
+
+       writeb(0x8, phsu + UART_MCR);
+       writeb(0x7, phsu + UART_FCR);
+       writeb(0x3, phsu + UART_LCR);
+
+       /* Clear IRQ status */
+       readb(phsu + UART_LSR);
+       readb(phsu + UART_RX);
+       readb(phsu + UART_IIR);
+       readb(phsu + UART_MSR);
+
+       /* Enable FIFO */
+       writeb(0x7, phsu + UART_FCR);
+}
+
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+static void early_hsu_putc(char ch)
+{
+       unsigned int timeout = 10000; /* 10ms */
+       u8 status;
+
+       while (--timeout) {
+               status = readb(phsu + UART_LSR);
+               if (status & BOTH_EMPTY)
+                       break;
+               udelay(1);
+       }
+
+       /* Only write the char when there was no timeout */
+       if (timeout)
+               writeb(ch, phsu + UART_TX);
+}
+
+static void early_hsu_write(struct console *con, const char *str, unsigned n)
+{
+       int i;
+
+       for (i = 0; i < n && *str; i++) {
+               if (*str == '\n')
+                       early_hsu_putc('\r');
+               early_hsu_putc(*str);
+               str++;
+       }
+}
+
+struct console early_hsu_console = {
+       .name =         "earlyhsu",
+       .write =        early_hsu_write,
+       .flags =        CON_PRINTBUFFER,
+       .index =        -1,
+};
index c2fa9b8b497e082cd703f2e2e0f9b03319bdd2e6..0fe27d7c6258e8e22b8918c0fbf14d088ecd9380 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/init.h>
 #include <linux/efi.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
 #include <linux/time.h>
@@ -275,7 +276,7 @@ static void __init do_add_efi_memmap(void)
        sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 }
 
-void __init efi_reserve_early(void)
+void __init efi_memblock_x86_reserve_range(void)
 {
        unsigned long pmap;
 
@@ -290,7 +291,7 @@ void __init efi_reserve_early(void)
                boot_params.efi_info.efi_memdesc_size;
        memmap.desc_version = boot_params.efi_info.efi_memdesc_version;
        memmap.desc_size = boot_params.efi_info.efi_memdesc_size;
-       reserve_early(pmap, pmap + memmap.nr_map * memmap.desc_size,
+       memblock_x86_reserve_range(pmap, pmap + memmap.nr_map * memmap.desc_size,
                      "EFI memmap");
 }
 
index 227d00920d2f8eaa1d90340ced0261ffe0a8f859..9fb188d7bc762a8101bffde7d32f8e4851512360 100644 (file)
 
  /* unfortunately push/pop can't be no-op */
 .macro PUSH_GS
-       pushl $0
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0
 .endm
 .macro POP_GS pop=0
        addl $(4 + \pop), %esp
 #else  /* CONFIG_X86_32_LAZY_GS */
 
 .macro PUSH_GS
-       pushl %gs
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %gs
        /*CFI_REL_OFFSET gs, 0*/
 .endm
 
 .macro POP_GS pop=0
-98:    popl %gs
-       CFI_ADJUST_CFA_OFFSET -4
+98:    popl_cfi %gs
        /*CFI_RESTORE gs*/
   .if \pop <> 0
        add $\pop, %esp
 .macro SAVE_ALL
        cld
        PUSH_GS
-       pushl %fs
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %fs
        /*CFI_REL_OFFSET fs, 0;*/
-       pushl %es
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %es
        /*CFI_REL_OFFSET es, 0;*/
-       pushl %ds
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ds
        /*CFI_REL_OFFSET ds, 0;*/
-       pushl %eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %eax
        CFI_REL_OFFSET eax, 0
-       pushl %ebp
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebp
        CFI_REL_OFFSET ebp, 0
-       pushl %edi
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %edi
        CFI_REL_OFFSET edi, 0
-       pushl %esi
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %esi
        CFI_REL_OFFSET esi, 0
-       pushl %edx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %edx
        CFI_REL_OFFSET edx, 0
-       pushl %ecx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ecx
        CFI_REL_OFFSET ecx, 0
-       pushl %ebx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebx
        CFI_REL_OFFSET ebx, 0
        movl $(__USER_DS), %edx
        movl %edx, %ds
 .endm
 
 .macro RESTORE_INT_REGS
-       popl %ebx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ebx
        CFI_RESTORE ebx
-       popl %ecx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ecx
        CFI_RESTORE ecx
-       popl %edx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %edx
        CFI_RESTORE edx
-       popl %esi
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %esi
        CFI_RESTORE esi
-       popl %edi
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %edi
        CFI_RESTORE edi
-       popl %ebp
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ebp
        CFI_RESTORE ebp
-       popl %eax
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %eax
        CFI_RESTORE eax
 .endm
 
 .macro RESTORE_REGS pop=0
        RESTORE_INT_REGS
-1:     popl %ds
-       CFI_ADJUST_CFA_OFFSET -4
+1:     popl_cfi %ds
        /*CFI_RESTORE ds;*/
-2:     popl %es
-       CFI_ADJUST_CFA_OFFSET -4
+2:     popl_cfi %es
        /*CFI_RESTORE es;*/
-3:     popl %fs
-       CFI_ADJUST_CFA_OFFSET -4
+3:     popl_cfi %fs
        /*CFI_RESTORE fs;*/
        POP_GS \pop
 .pushsection .fixup, "ax"
 
 ENTRY(ret_from_fork)
        CFI_STARTPROC
-       pushl %eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %eax
        call schedule_tail
        GET_THREAD_INFO(%ebp)
-       popl %eax
-       CFI_ADJUST_CFA_OFFSET -4
-       pushl $0x0202                   # Reset kernel eflags
-       CFI_ADJUST_CFA_OFFSET 4
-       popfl
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %eax
+       pushl_cfi $0x0202               # Reset kernel eflags
+       popfl_cfi
        jmp syscall_exit
        CFI_ENDPROC
 END(ret_from_fork)
@@ -409,29 +382,23 @@ sysenter_past_esp:
         * enough kernel state to call TRACE_IRQS_OFF can be called - but
         * we immediately enable interrupts at that point anyway.
         */
-       pushl $(__USER_DS)
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $(__USER_DS)
        /*CFI_REL_OFFSET ss, 0*/
-       pushl %ebp
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebp
        CFI_REL_OFFSET esp, 0
-       pushfl
+       pushfl_cfi
        orl $X86_EFLAGS_IF, (%esp)
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $(__USER_CS)
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $(__USER_CS)
        /*CFI_REL_OFFSET cs, 0*/
        /*
         * Push current_thread_info()->sysenter_return to the stack.
         * A tiny bit of offset fixup is necessary - 4*4 means the 4 words
         * pushed above; +8 corresponds to copy_thread's esp0 setting.
         */
-       pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp)
        CFI_REL_OFFSET eip, 0
 
-       pushl %eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %eax
        SAVE_ALL
        ENABLE_INTERRUPTS(CLBR_NONE)
 
@@ -486,8 +453,7 @@ sysenter_audit:
        movl %eax,%edx                  /* 2nd arg: syscall number */
        movl $AUDIT_ARCH_I386,%eax      /* 1st arg: audit arch */
        call audit_syscall_entry
-       pushl %ebx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebx
        movl PT_EAX(%esp),%eax          /* reload syscall number */
        jmp sysenter_do_call
 
@@ -529,8 +495,7 @@ ENDPROC(ia32_sysenter_target)
        # system call handler stub
 ENTRY(system_call)
        RING0_INT_FRAME                 # can't unwind into user space anyway
-       pushl %eax                      # save orig_eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %eax                  # save orig_eax
        SAVE_ALL
        GET_THREAD_INFO(%ebp)
                                        # system call tracing in operation / emulation
@@ -566,7 +531,6 @@ restore_all_notrace:
        je ldt_ss                       # returning to user-space with LDT SS
 restore_nocheck:
        RESTORE_REGS 4                  # skip orig_eax/error_code
-       CFI_ADJUST_CFA_OFFSET -4
 irq_return:
        INTERRUPT_RETURN
 .section .fixup,"ax"
@@ -619,10 +583,8 @@ ldt_ss:
        shr $16, %edx
        mov %dl, GDT_ESPFIX_SS + 4 /* bits 16..23 */
        mov %dh, GDT_ESPFIX_SS + 7 /* bits 24..31 */
-       pushl $__ESPFIX_SS
-       CFI_ADJUST_CFA_OFFSET 4
-       push %eax                       /* new kernel esp */
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $__ESPFIX_SS
+       pushl_cfi %eax                  /* new kernel esp */
        /* Disable interrupts, but do not irqtrace this section: we
         * will soon execute iret and the tracer was already set to
         * the irqstate after the iret */
@@ -666,11 +628,9 @@ work_notifysig:                            # deal with pending signals and
 
        ALIGN
 work_notifysig_v86:
-       pushl %ecx                      # save ti_flags for do_notify_resume
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ecx                  # save ti_flags for do_notify_resume
        call save_v86_state             # %eax contains pt_regs pointer
-       popl %ecx
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %ecx
        movl %eax, %esp
 #else
        movl %esp, %eax
@@ -750,14 +710,18 @@ ptregs_##name: \
 #define PTREGSCALL3(name) \
        ALIGN; \
 ptregs_##name: \
+       CFI_STARTPROC; \
        leal 4(%esp),%eax; \
-       pushl %eax; \
+       pushl_cfi %eax; \
        movl PT_EDX(%eax),%ecx; \
        movl PT_ECX(%eax),%edx; \
        movl PT_EBX(%eax),%eax; \
        call sys_##name; \
        addl $4,%esp; \
-       ret
+       CFI_ADJUST_CFA_OFFSET -4; \
+       ret; \
+       CFI_ENDPROC; \
+ENDPROC(ptregs_##name)
 
 PTREGSCALL1(iopl)
 PTREGSCALL0(fork)
@@ -772,15 +736,19 @@ PTREGSCALL1(vm86old)
 /* Clone is an oddball.  The 4th arg is in %edi */
        ALIGN;
 ptregs_clone:
+       CFI_STARTPROC
        leal 4(%esp),%eax
-       pushl %eax
-       pushl PT_EDI(%eax)
+       pushl_cfi %eax
+       pushl_cfi PT_EDI(%eax)
        movl PT_EDX(%eax),%ecx
        movl PT_ECX(%eax),%edx
        movl PT_EBX(%eax),%eax
        call sys_clone
        addl $8,%esp
+       CFI_ADJUST_CFA_OFFSET -8
        ret
+       CFI_ENDPROC
+ENDPROC(ptregs_clone)
 
 .macro FIXUP_ESPFIX_STACK
 /*
@@ -795,10 +763,8 @@ ptregs_clone:
        mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */
        shl $16, %eax
        addl %esp, %eax                 /* the adjusted stack pointer */
-       pushl $__KERNEL_DS
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl %eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $__KERNEL_DS
+       pushl_cfi %eax
        lss (%esp), %esp                /* switch to the normal stack segment */
        CFI_ADJUST_CFA_OFFSET -8
 .endm
@@ -835,8 +801,7 @@ vector=FIRST_EXTERNAL_VECTOR
       .if vector <> FIRST_EXTERNAL_VECTOR
        CFI_ADJUST_CFA_OFFSET -4
       .endif
-1:     pushl $(~vector+0x80)   /* Note: always in signed byte range */
-       CFI_ADJUST_CFA_OFFSET 4
+1:     pushl_cfi $(~vector+0x80)       /* Note: always in signed byte range */
       .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6
        jmp 2f
       .endif
@@ -876,8 +841,7 @@ ENDPROC(common_interrupt)
 #define BUILD_INTERRUPT3(name, nr, fn) \
 ENTRY(name)                            \
        RING0_INT_FRAME;                \
-       pushl $~(nr);                   \
-       CFI_ADJUST_CFA_OFFSET 4;        \
+       pushl_cfi $~(nr);               \
        SAVE_ALL;                       \
        TRACE_IRQS_OFF                  \
        movl %esp,%eax;                 \
@@ -893,21 +857,18 @@ ENDPROC(name)
 
 ENTRY(coprocessor_error)
        RING0_INT_FRAME
-       pushl $0
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $do_coprocessor_error
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0
+       pushl_cfi $do_coprocessor_error
        jmp error_code
        CFI_ENDPROC
 END(coprocessor_error)
 
 ENTRY(simd_coprocessor_error)
        RING0_INT_FRAME
-       pushl $0
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0
 #ifdef CONFIG_X86_INVD_BUG
        /* AMD 486 bug: invd from userspace calls exception 19 instead of #GP */
-661:   pushl $do_general_protection
+661:   pushl_cfi $do_general_protection
 662:
 .section .altinstructions,"a"
        .balign 4
@@ -922,19 +883,16 @@ ENTRY(simd_coprocessor_error)
 664:
 .previous
 #else
-       pushl $do_simd_coprocessor_error
+       pushl_cfi $do_simd_coprocessor_error
 #endif
-       CFI_ADJUST_CFA_OFFSET 4
        jmp error_code
        CFI_ENDPROC
 END(simd_coprocessor_error)
 
 ENTRY(device_not_available)
        RING0_INT_FRAME
-       pushl $-1                       # mark this as an int
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $do_device_not_available
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $-1                   # mark this as an int
+       pushl_cfi $do_device_not_available
        jmp error_code
        CFI_ENDPROC
 END(device_not_available)
@@ -956,82 +914,68 @@ END(native_irq_enable_sysexit)
 
 ENTRY(overflow)
        RING0_INT_FRAME
-       pushl $0
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $do_overflow
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0
+       pushl_cfi $do_overflow
        jmp error_code
        CFI_ENDPROC
 END(overflow)
 
 ENTRY(bounds)
        RING0_INT_FRAME
-       pushl $0
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $do_bounds
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0
+       pushl_cfi $do_bounds
        jmp error_code
        CFI_ENDPROC
 END(bounds)
 
 ENTRY(invalid_op)
        RING0_INT_FRAME
-       pushl $0
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $do_invalid_op
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0
+       pushl_cfi $do_invalid_op
        jmp error_code
        CFI_ENDPROC
 END(invalid_op)
 
 ENTRY(coprocessor_segment_overrun)
        RING0_INT_FRAME
-       pushl $0
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $do_coprocessor_segment_overrun
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0
+       pushl_cfi $do_coprocessor_segment_overrun
        jmp error_code
        CFI_ENDPROC
 END(coprocessor_segment_overrun)
 
 ENTRY(invalid_TSS)
        RING0_EC_FRAME
-       pushl $do_invalid_TSS
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $do_invalid_TSS
        jmp error_code
        CFI_ENDPROC
 END(invalid_TSS)
 
 ENTRY(segment_not_present)
        RING0_EC_FRAME
-       pushl $do_segment_not_present
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $do_segment_not_present
        jmp error_code
        CFI_ENDPROC
 END(segment_not_present)
 
 ENTRY(stack_segment)
        RING0_EC_FRAME
-       pushl $do_stack_segment
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $do_stack_segment
        jmp error_code
        CFI_ENDPROC
 END(stack_segment)
 
 ENTRY(alignment_check)
        RING0_EC_FRAME
-       pushl $do_alignment_check
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $do_alignment_check
        jmp error_code
        CFI_ENDPROC
 END(alignment_check)
 
 ENTRY(divide_error)
        RING0_INT_FRAME
-       pushl $0                        # no error code
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $do_divide_error
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0                    # no error code
+       pushl_cfi $do_divide_error
        jmp error_code
        CFI_ENDPROC
 END(divide_error)
@@ -1039,10 +983,8 @@ END(divide_error)
 #ifdef CONFIG_X86_MCE
 ENTRY(machine_check)
        RING0_INT_FRAME
-       pushl $0
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl machine_check_vector
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0
+       pushl_cfi machine_check_vector
        jmp error_code
        CFI_ENDPROC
 END(machine_check)
@@ -1050,10 +992,8 @@ END(machine_check)
 
 ENTRY(spurious_interrupt_bug)
        RING0_INT_FRAME
-       pushl $0
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $do_spurious_interrupt_bug
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0
+       pushl_cfi $do_spurious_interrupt_bug
        jmp error_code
        CFI_ENDPROC
 END(spurious_interrupt_bug)
@@ -1084,8 +1024,7 @@ ENTRY(xen_sysenter_target)
 
 ENTRY(xen_hypervisor_callback)
        CFI_STARTPROC
-       pushl $0
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $0
        SAVE_ALL
        TRACE_IRQS_OFF
 
@@ -1121,23 +1060,20 @@ ENDPROC(xen_hypervisor_callback)
 # We distinguish between categories by maintaining a status value in EAX.
 ENTRY(xen_failsafe_callback)
        CFI_STARTPROC
-       pushl %eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %eax
        movl $1,%eax
 1:     mov 4(%esp),%ds
 2:     mov 8(%esp),%es
 3:     mov 12(%esp),%fs
 4:     mov 16(%esp),%gs
        testl %eax,%eax
-       popl %eax
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %eax
        lea 16(%esp),%esp
        CFI_ADJUST_CFA_OFFSET -16
        jz 5f
        addl $16,%esp
        jmp iret_exc            # EAX != 0 => Category 2 (Bad IRET)
-5:     pushl $0                # EAX == 0 => Category 1 (Bad segment)
-       CFI_ADJUST_CFA_OFFSET 4
+5:     pushl_cfi $0            # EAX == 0 => Category 1 (Bad segment)
        SAVE_ALL
        jmp ret_from_exception
        CFI_ENDPROC
@@ -1287,40 +1223,29 @@ syscall_table_size=(.-sys_call_table)
 
 ENTRY(page_fault)
        RING0_EC_FRAME
-       pushl $do_page_fault
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $do_page_fault
        ALIGN
 error_code:
        /* the function address is in %gs's slot on the stack */
-       pushl %fs
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %fs
        /*CFI_REL_OFFSET fs, 0*/
-       pushl %es
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %es
        /*CFI_REL_OFFSET es, 0*/
-       pushl %ds
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ds
        /*CFI_REL_OFFSET ds, 0*/
-       pushl %eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %eax
        CFI_REL_OFFSET eax, 0
-       pushl %ebp
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebp
        CFI_REL_OFFSET ebp, 0
-       pushl %edi
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %edi
        CFI_REL_OFFSET edi, 0
-       pushl %esi
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %esi
        CFI_REL_OFFSET esi, 0
-       pushl %edx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %edx
        CFI_REL_OFFSET edx, 0
-       pushl %ecx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ecx
        CFI_REL_OFFSET ecx, 0
-       pushl %ebx
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ebx
        CFI_REL_OFFSET ebx, 0
        cld
        movl $(__KERNEL_PERCPU), %ecx
@@ -1362,12 +1287,9 @@ END(page_fault)
        movl TSS_sysenter_sp0 + \offset(%esp), %esp
        CFI_DEF_CFA esp, 0
        CFI_UNDEFINED eip
-       pushfl
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $__KERNEL_CS
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl $sysenter_past_esp
-       CFI_ADJUST_CFA_OFFSET 4
+       pushfl_cfi
+       pushl_cfi $__KERNEL_CS
+       pushl_cfi $sysenter_past_esp
        CFI_REL_OFFSET eip, 0
 .endm
 
@@ -1377,8 +1299,7 @@ ENTRY(debug)
        jne debug_stack_correct
        FIX_STACK 12, debug_stack_correct, debug_esp_fix_insn
 debug_stack_correct:
-       pushl $-1                       # mark this as an int
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $-1                   # mark this as an int
        SAVE_ALL
        TRACE_IRQS_OFF
        xorl %edx,%edx                  # error code 0
@@ -1398,32 +1319,27 @@ END(debug)
  */
 ENTRY(nmi)
        RING0_INT_FRAME
-       pushl %eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %eax
        movl %ss, %eax
        cmpw $__ESPFIX_SS, %ax
-       popl %eax
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %eax
        je nmi_espfix_stack
        cmpl $ia32_sysenter_target,(%esp)
        je nmi_stack_fixup
-       pushl %eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %eax
        movl %esp,%eax
        /* Do not access memory above the end of our stack page,
         * it might not exist.
         */
        andl $(THREAD_SIZE-1),%eax
        cmpl $(THREAD_SIZE-20),%eax
-       popl %eax
-       CFI_ADJUST_CFA_OFFSET -4
+       popl_cfi %eax
        jae nmi_stack_correct
        cmpl $ia32_sysenter_target,12(%esp)
        je nmi_debug_stack_check
 nmi_stack_correct:
        /* We have a RING0_INT_FRAME here */
-       pushl %eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %eax
        SAVE_ALL
        xorl %edx,%edx          # zero error code
        movl %esp,%eax          # pt_regs pointer
@@ -1452,18 +1368,14 @@ nmi_espfix_stack:
         *
         * create the pointer to lss back
         */
-       pushl %ss
-       CFI_ADJUST_CFA_OFFSET 4
-       pushl %esp
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %ss
+       pushl_cfi %esp
        addl $4, (%esp)
        /* copy the iret frame of 12 bytes */
        .rept 3
-       pushl 16(%esp)
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi 16(%esp)
        .endr
-       pushl %eax
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi %eax
        SAVE_ALL
        FIXUP_ESPFIX_STACK              # %eax == %esp
        xorl %edx,%edx                  # zero error code
@@ -1477,8 +1389,7 @@ END(nmi)
 
 ENTRY(int3)
        RING0_INT_FRAME
-       pushl $-1                       # mark this as an int
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $-1                   # mark this as an int
        SAVE_ALL
        TRACE_IRQS_OFF
        xorl %edx,%edx          # zero error code
@@ -1490,8 +1401,7 @@ END(int3)
 
 ENTRY(general_protection)
        RING0_EC_FRAME
-       pushl $do_general_protection
-       CFI_ADJUST_CFA_OFFSET 4
+       pushl_cfi $do_general_protection
        jmp error_code
        CFI_ENDPROC
 END(general_protection)
index 17be5ec7cbbad332973b6b46a79cdb3db2832f74..a7ae7fd1010fdbddcd596aa0aae01ee160b7bb66 100644 (file)
@@ -213,23 +213,17 @@ ENDPROC(native_usergs_sysret64)
        .macro FAKE_STACK_FRAME child_rip
        /* push in order ss, rsp, eflags, cs, rip */
        xorl %eax, %eax
-       pushq $__KERNEL_DS /* ss */
-       CFI_ADJUST_CFA_OFFSET   8
+       pushq_cfi $__KERNEL_DS /* ss */
        /*CFI_REL_OFFSET        ss,0*/
-       pushq %rax /* rsp */
-       CFI_ADJUST_CFA_OFFSET   8
+       pushq_cfi %rax /* rsp */
        CFI_REL_OFFSET  rsp,0
-       pushq $X86_EFLAGS_IF /* eflags - interrupts on */
-       CFI_ADJUST_CFA_OFFSET   8
+       pushq_cfi $X86_EFLAGS_IF /* eflags - interrupts on */
        /*CFI_REL_OFFSET        rflags,0*/
-       pushq $__KERNEL_CS /* cs */
-       CFI_ADJUST_CFA_OFFSET   8
+       pushq_cfi $__KERNEL_CS /* cs */
        /*CFI_REL_OFFSET        cs,0*/
-       pushq \child_rip /* rip */
-       CFI_ADJUST_CFA_OFFSET   8
+       pushq_cfi \child_rip /* rip */
        CFI_REL_OFFSET  rip,0
-       pushq   %rax /* orig rax */
-       CFI_ADJUST_CFA_OFFSET   8
+       pushq_cfi %rax /* orig rax */
        .endm
 
        .macro UNFAKE_STACK_FRAME
@@ -398,10 +392,8 @@ ENTRY(ret_from_fork)
 
        LOCK ; btr $TIF_FORK,TI_flags(%r8)
 
-       push kernel_eflags(%rip)
-       CFI_ADJUST_CFA_OFFSET 8
-       popf                                    # reset kernel eflags
-       CFI_ADJUST_CFA_OFFSET -8
+       pushq_cfi kernel_eflags(%rip)
+       popfq_cfi                               # reset kernel eflags
 
        call schedule_tail                      # rdi: 'prev' task parameter
 
@@ -521,11 +513,9 @@ sysret_careful:
        jnc sysret_signal
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_NONE)
-       pushq %rdi
-       CFI_ADJUST_CFA_OFFSET 8
+       pushq_cfi %rdi
        call schedule
-       popq  %rdi
-       CFI_ADJUST_CFA_OFFSET -8
+       popq_cfi %rdi
        jmp sysret_check
 
        /* Handle a signal */
@@ -634,11 +624,9 @@ int_careful:
        jnc  int_very_careful
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_NONE)
-       pushq %rdi
-       CFI_ADJUST_CFA_OFFSET 8
+       pushq_cfi %rdi
        call schedule
-       popq %rdi
-       CFI_ADJUST_CFA_OFFSET -8
+       popq_cfi %rdi
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
        jmp int_with_check
@@ -652,12 +640,10 @@ int_check_syscall_exit_work:
        /* Check for syscall exit trace */
        testl $_TIF_WORK_SYSCALL_EXIT,%edx
        jz int_signal
-       pushq %rdi
-       CFI_ADJUST_CFA_OFFSET 8
+       pushq_cfi %rdi
        leaq 8(%rsp),%rdi       # &ptregs -> arg1
        call syscall_trace_leave
-       popq %rdi
-       CFI_ADJUST_CFA_OFFSET -8
+       popq_cfi %rdi
        andl $~(_TIF_WORK_SYSCALL_EXIT|_TIF_SYSCALL_EMU),%edi
        jmp int_restore_rest
 
@@ -714,9 +700,8 @@ END(ptregscall_common)
 
 ENTRY(stub_execve)
        CFI_STARTPROC
-       popq %r11
-       CFI_ADJUST_CFA_OFFSET -8
-       CFI_REGISTER rip, r11
+       addq $8, %rsp
+       PARTIAL_FRAME 0
        SAVE_REST
        FIXUP_TOP_OF_STACK %r11
        movq %rsp, %rcx
@@ -735,7 +720,7 @@ END(stub_execve)
 ENTRY(stub_rt_sigreturn)
        CFI_STARTPROC
        addq $8, %rsp
-       CFI_ADJUST_CFA_OFFSET   -8
+       PARTIAL_FRAME 0
        SAVE_REST
        movq %rsp,%rdi
        FIXUP_TOP_OF_STACK %r11
@@ -766,8 +751,7 @@ vector=FIRST_EXTERNAL_VECTOR
       .if vector <> FIRST_EXTERNAL_VECTOR
        CFI_ADJUST_CFA_OFFSET -8
       .endif
-1:     pushq $(~vector+0x80)   /* Note: always in signed byte range */
-       CFI_ADJUST_CFA_OFFSET 8
+1:     pushq_cfi $(~vector+0x80)       /* Note: always in signed byte range */
       .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6
        jmp 2f
       .endif
@@ -796,8 +780,8 @@ END(interrupt)
 
 /* 0(%rsp): ~(interrupt number) */
        .macro interrupt func
-       subq $10*8, %rsp
-       CFI_ADJUST_CFA_OFFSET 10*8
+       subq $ORIG_RAX-ARGOFFSET+8, %rsp
+       CFI_ADJUST_CFA_OFFSET ORIG_RAX-ARGOFFSET+8
        call save_args
        PARTIAL_FRAME 0
        call \func
@@ -822,6 +806,7 @@ ret_from_intr:
        TRACE_IRQS_OFF
        decl PER_CPU_VAR(irq_count)
        leaveq
+       CFI_RESTORE             rbp
        CFI_DEF_CFA_REGISTER    rsp
        CFI_ADJUST_CFA_OFFSET   -8
 exit_intr:
@@ -903,11 +888,9 @@ retint_careful:
        jnc   retint_signal
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_NONE)
-       pushq %rdi
-       CFI_ADJUST_CFA_OFFSET   8
+       pushq_cfi %rdi
        call  schedule
-       popq %rdi
-       CFI_ADJUST_CFA_OFFSET   -8
+       popq_cfi %rdi
        GET_THREAD_INFO(%rcx)
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
@@ -956,8 +939,7 @@ END(common_interrupt)
 .macro apicinterrupt num sym do_sym
 ENTRY(\sym)
        INTR_FRAME
-       pushq $~(\num)
-       CFI_ADJUST_CFA_OFFSET 8
+       pushq_cfi $~(\num)
        interrupt \do_sym
        jmp ret_from_intr
        CFI_ENDPROC
@@ -1023,9 +1005,9 @@ apicinterrupt ERROR_APIC_VECTOR \
 apicinterrupt SPURIOUS_APIC_VECTOR \
        spurious_interrupt smp_spurious_interrupt
 
-#ifdef CONFIG_PERF_EVENTS
-apicinterrupt LOCAL_PENDING_VECTOR \
-       perf_pending_interrupt smp_perf_pending_interrupt
+#ifdef CONFIG_IRQ_WORK
+apicinterrupt IRQ_WORK_VECTOR \
+       irq_work_interrupt smp_irq_work_interrupt
 #endif
 
 /*
@@ -1036,8 +1018,8 @@ ENTRY(\sym)
        INTR_FRAME
        PARAVIRT_ADJUST_EXCEPTION_FRAME
        pushq_cfi $-1           /* ORIG_RAX: no syscall to restart */
-       subq $15*8,%rsp
-       CFI_ADJUST_CFA_OFFSET 15*8
+       subq $ORIG_RAX-R15, %rsp
+       CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
        call error_entry
        DEFAULT_FRAME 0
        movq %rsp,%rdi          /* pt_regs pointer */
@@ -1052,9 +1034,9 @@ END(\sym)
 ENTRY(\sym)
        INTR_FRAME
        PARAVIRT_ADJUST_EXCEPTION_FRAME
-       pushq $-1               /* ORIG_RAX: no syscall to restart */
-       CFI_ADJUST_CFA_OFFSET 8
-       subq $15*8, %rsp
+       pushq_cfi $-1           /* ORIG_RAX: no syscall to restart */
+       subq $ORIG_RAX-R15, %rsp
+       CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
        call save_paranoid
        TRACE_IRQS_OFF
        movq %rsp,%rdi          /* pt_regs pointer */
@@ -1070,9 +1052,9 @@ END(\sym)
 ENTRY(\sym)
        INTR_FRAME
        PARAVIRT_ADJUST_EXCEPTION_FRAME
-       pushq $-1               /* ORIG_RAX: no syscall to restart */
-       CFI_ADJUST_CFA_OFFSET 8
-       subq $15*8, %rsp
+       pushq_cfi $-1           /* ORIG_RAX: no syscall to restart */
+       subq $ORIG_RAX-R15, %rsp
+       CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
        call save_paranoid
        TRACE_IRQS_OFF
        movq %rsp,%rdi          /* pt_regs pointer */
@@ -1089,8 +1071,8 @@ END(\sym)
 ENTRY(\sym)
        XCPT_FRAME
        PARAVIRT_ADJUST_EXCEPTION_FRAME
-       subq $15*8,%rsp
-       CFI_ADJUST_CFA_OFFSET 15*8
+       subq $ORIG_RAX-R15, %rsp
+       CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
        call error_entry
        DEFAULT_FRAME 0
        movq %rsp,%rdi                  /* pt_regs pointer */
@@ -1107,8 +1089,8 @@ END(\sym)
 ENTRY(\sym)
        XCPT_FRAME
        PARAVIRT_ADJUST_EXCEPTION_FRAME
-       subq $15*8,%rsp
-       CFI_ADJUST_CFA_OFFSET 15*8
+       subq $ORIG_RAX-R15, %rsp
+       CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
        call save_paranoid
        DEFAULT_FRAME 0
        TRACE_IRQS_OFF
@@ -1139,16 +1121,14 @@ zeroentry simd_coprocessor_error do_simd_coprocessor_error
        /* edi:  new selector */
 ENTRY(native_load_gs_index)
        CFI_STARTPROC
-       pushf
-       CFI_ADJUST_CFA_OFFSET 8
+       pushfq_cfi
        DISABLE_INTERRUPTS(CLBR_ANY & ~CLBR_RDI)
        SWAPGS
 gs_change:
        movl %edi,%gs
 2:     mfence          /* workaround */
        SWAPGS
-       popf
-       CFI_ADJUST_CFA_OFFSET -8
+       popfq_cfi
        ret
        CFI_ENDPROC
 END(native_load_gs_index)
@@ -1215,8 +1195,7 @@ END(kernel_execve)
 /* Call softirq on interrupt stack. Interrupts are off. */
 ENTRY(call_softirq)
        CFI_STARTPROC
-       push %rbp
-       CFI_ADJUST_CFA_OFFSET   8
+       pushq_cfi %rbp
        CFI_REL_OFFSET rbp,0
        mov  %rsp,%rbp
        CFI_DEF_CFA_REGISTER rbp
@@ -1225,6 +1204,7 @@ ENTRY(call_softirq)
        push  %rbp                      # backlink for old unwinder
        call __do_softirq
        leaveq
+       CFI_RESTORE             rbp
        CFI_DEF_CFA_REGISTER    rsp
        CFI_ADJUST_CFA_OFFSET   -8
        decl PER_CPU_VAR(irq_count)
@@ -1368,7 +1348,7 @@ paranoidzeroentry machine_check *machine_check_vector(%rip)
 
        /* ebx: no swapgs flag */
 ENTRY(paranoid_exit)
-       INTR_FRAME
+       DEFAULT_FRAME
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
        testl %ebx,%ebx                         /* swapgs needed? */
@@ -1445,7 +1425,6 @@ error_swapgs:
 error_sti:
        TRACE_IRQS_OFF
        ret
-       CFI_ENDPROC
 
 /*
  * There are two places in the kernel that can potentially fault with
@@ -1470,6 +1449,7 @@ bstep_iret:
        /* Fix truncated RIP */
        movq %rcx,RIP+8(%rsp)
        jmp error_swapgs
+       CFI_ENDPROC
 END(error_entry)
 
 
@@ -1498,8 +1478,8 @@ ENTRY(nmi)
        INTR_FRAME
        PARAVIRT_ADJUST_EXCEPTION_FRAME
        pushq_cfi $-1
-       subq $15*8, %rsp
-       CFI_ADJUST_CFA_OFFSET 15*8
+       subq $ORIG_RAX-R15, %rsp
+       CFI_ADJUST_CFA_OFFSET ORIG_RAX-R15
        call save_paranoid
        DEFAULT_FRAME 0
        /* paranoidentry do_nmi, 0; without TRACE_IRQS_OFF */
index cd37469b54eeed3fc479d2c931d8d2ed933ea411..3afb33f14d2d2c86a3c961d87aaae531d2631ac8 100644 (file)
@@ -257,14 +257,9 @@ do_ftrace_mod_code(unsigned long ip, void *new_code)
        return mod_code_status;
 }
 
-
-
-
-static unsigned char ftrace_nop[MCOUNT_INSN_SIZE];
-
 static unsigned char *ftrace_nop_replace(void)
 {
-       return ftrace_nop;
+       return ideal_nop5;
 }
 
 static int
@@ -338,62 +333,6 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
 
 int __init ftrace_dyn_arch_init(void *data)
 {
-       extern const unsigned char ftrace_test_p6nop[];
-       extern const unsigned char ftrace_test_nop5[];
-       extern const unsigned char ftrace_test_jmp[];
-       int faulted = 0;
-
-       /*
-        * There is no good nop for all x86 archs.
-        * We will default to using the P6_NOP5, but first we
-        * will test to make sure that the nop will actually
-        * work on this CPU. If it faults, we will then
-        * go to a lesser efficient 5 byte nop. If that fails
-        * we then just use a jmp as our nop. This isn't the most
-        * efficient nop, but we can not use a multi part nop
-        * since we would then risk being preempted in the middle
-        * of that nop, and if we enabled tracing then, it might
-        * cause a system crash.
-        *
-        * TODO: check the cpuid to determine the best nop.
-        */
-       asm volatile (
-               "ftrace_test_jmp:"
-               "jmp ftrace_test_p6nop\n"
-               "nop\n"
-               "nop\n"
-               "nop\n"  /* 2 byte jmp + 3 bytes */
-               "ftrace_test_p6nop:"
-               P6_NOP5
-               "jmp 1f\n"
-               "ftrace_test_nop5:"
-               ".byte 0x66,0x66,0x66,0x66,0x90\n"
-               "1:"
-               ".section .fixup, \"ax\"\n"
-               "2:     movl $1, %0\n"
-               "       jmp ftrace_test_nop5\n"
-               "3:     movl $2, %0\n"
-               "       jmp 1b\n"
-               ".previous\n"
-               _ASM_EXTABLE(ftrace_test_p6nop, 2b)
-               _ASM_EXTABLE(ftrace_test_nop5, 3b)
-               : "=r"(faulted) : "0" (faulted));
-
-       switch (faulted) {
-       case 0:
-               pr_info("converting mcount calls to 0f 1f 44 00 00\n");
-               memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE);
-               break;
-       case 1:
-               pr_info("converting mcount calls to 66 66 66 66 90\n");
-               memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE);
-               break;
-       case 2:
-               pr_info("converting mcount calls to jmp . + 5\n");
-               memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE);
-               break;
-       }
-
        /* The return code is retured via data */
        *(unsigned long *)data = 0;
 
index 3e66bd364a9db3cf8f3fb624f96eeb7075364d78..af0699ba48cfb7efebb03bc5bc57af750b73f9ef 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/memblock.h>
 
 #include <asm/setup.h>
 #include <asm/bios_ebda.h>
@@ -51,5 +52,5 @@ void __init reserve_ebda_region(void)
                lowmem = 0x9f000;
 
        /* reserve all memory between lowmem and the 1MB mark */
-       reserve_early_overlap_ok(lowmem, 0x100000, "BIOS reserved");
+       memblock_x86_reserve_range(lowmem, 0x100000, "* BIOS reserved");
 }
index 784360c0625c04edbcee49e13f5fe471add070ec..9a6ca23921705ee4122e8d90aec48a7bdc350f0e 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/init.h>
 #include <linux/start_kernel.h>
 #include <linux/mm.h>
+#include <linux/memblock.h>
 
 #include <asm/setup.h>
 #include <asm/sections.h>
@@ -30,17 +31,18 @@ static void __init i386_default_early_setup(void)
 
 void __init i386_start_kernel(void)
 {
+       memblock_init();
+
 #ifdef CONFIG_X86_TRAMPOLINE
        /*
         * But first pinch a few for the stack/trampoline stuff
         * FIXME: Don't need the extra page at 4K, but need to fix
         * trampoline before removing it. (see the GDT stuff)
         */
-       reserve_early_overlap_ok(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE,
-                                        "EX TRAMPOLINE");
+       memblock_x86_reserve_range(PAGE_SIZE, PAGE_SIZE + PAGE_SIZE, "EX TRAMPOLINE");
 #endif
 
-       reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
+       memblock_x86_reserve_range(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
 
 #ifdef CONFIG_BLK_DEV_INITRD
        /* Reserve INITRD */
@@ -49,7 +51,7 @@ void __init i386_start_kernel(void)
                u64 ramdisk_image = boot_params.hdr.ramdisk_image;
                u64 ramdisk_size  = boot_params.hdr.ramdisk_size;
                u64 ramdisk_end   = PAGE_ALIGN(ramdisk_image + ramdisk_size);
-               reserve_early(ramdisk_image, ramdisk_end, "RAMDISK");
+               memblock_x86_reserve_range(ramdisk_image, ramdisk_end, "RAMDISK");
        }
 #endif
 
index 7147143fd614e429392741ae13ce5577c7be5364..2d2673c28aff2754af1e6e8848e9068ab1a6cca5 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/percpu.h>
 #include <linux/start_kernel.h>
 #include <linux/io.h>
+#include <linux/memblock.h>
 
 #include <asm/processor.h>
 #include <asm/proto.h>
@@ -79,6 +80,8 @@ void __init x86_64_start_kernel(char * real_mode_data)
        /* Cleanup the over mapped high alias */
        cleanup_highmap();
 
+       max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT;
+
        for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) {
 #ifdef CONFIG_EARLY_PRINTK
                set_intr_gate(i, &early_idt_handlers[i]);
@@ -98,7 +101,9 @@ void __init x86_64_start_reservations(char *real_mode_data)
 {
        copy_bootdata(__va(real_mode_data));
 
-       reserve_early(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
+       memblock_init();
+
+       memblock_x86_reserve_range(__pa_symbol(&_text), __pa_symbol(&__bss_stop), "TEXT DATA BSS");
 
 #ifdef CONFIG_BLK_DEV_INITRD
        /* Reserve INITRD */
@@ -107,7 +112,7 @@ void __init x86_64_start_reservations(char *real_mode_data)
                unsigned long ramdisk_image = boot_params.hdr.ramdisk_image;
                unsigned long ramdisk_size  = boot_params.hdr.ramdisk_size;
                unsigned long ramdisk_end   = PAGE_ALIGN(ramdisk_image + ramdisk_size);
-               reserve_early(ramdisk_image, ramdisk_end, "RAMDISK");
+               memblock_x86_reserve_range(ramdisk_image, ramdisk_end, "RAMDISK");
        }
 #endif
 
index 7494999141b3ae9c9ab67302481a2e6c15e969e6..efaf906daf93ff4dcca7385d26047c2db8691fbe 100644 (file)
@@ -440,9 +440,9 @@ static int hpet_legacy_next_event(unsigned long delta,
 static DEFINE_PER_CPU(struct hpet_dev *, cpu_hpet_dev);
 static struct hpet_dev *hpet_devs;
 
-void hpet_msi_unmask(unsigned int irq)
+void hpet_msi_unmask(struct irq_data *data)
 {
-       struct hpet_dev *hdev = get_irq_data(irq);
+       struct hpet_dev *hdev = data->handler_data;
        unsigned int cfg;
 
        /* unmask it */
@@ -451,10 +451,10 @@ void hpet_msi_unmask(unsigned int irq)
        hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
-void hpet_msi_mask(unsigned int irq)
+void hpet_msi_mask(struct irq_data *data)
 {
+       struct hpet_dev *hdev = data->handler_data;
        unsigned int cfg;
-       struct hpet_dev *hdev = get_irq_data(irq);
 
        /* mask it */
        cfg = hpet_readl(HPET_Tn_CFG(hdev->num));
@@ -462,18 +462,14 @@ void hpet_msi_mask(unsigned int irq)
        hpet_writel(cfg, HPET_Tn_CFG(hdev->num));
 }
 
-void hpet_msi_write(unsigned int irq, struct msi_msg *msg)
+void hpet_msi_write(struct hpet_dev *hdev, struct msi_msg *msg)
 {
-       struct hpet_dev *hdev = get_irq_data(irq);
-
        hpet_writel(msg->data, HPET_Tn_ROUTE(hdev->num));
        hpet_writel(msg->address_lo, HPET_Tn_ROUTE(hdev->num) + 4);
 }
 
-void hpet_msi_read(unsigned int irq, struct msi_msg *msg)
+void hpet_msi_read(struct hpet_dev *hdev, struct msi_msg *msg)
 {
-       struct hpet_dev *hdev = get_irq_data(irq);
-
        msg->data = hpet_readl(HPET_Tn_ROUTE(hdev->num));
        msg->address_lo = hpet_readl(HPET_Tn_ROUTE(hdev->num) + 4);
        msg->address_hi = 0;
index a46cb3522c0c19d67f2d474c6e1f09fb616004ff..58bb239a2fd76d67121bd1c25e48512bad529825 100644 (file)
@@ -68,19 +68,22 @@ static void __cpuinit init_thread_xstate(void)
         */
 
        if (!HAVE_HWFP) {
+               /*
+                * Disable xsave as we do not support it if i387
+                * emulation is enabled.
+                */
+               setup_clear_cpu_cap(X86_FEATURE_XSAVE);
+               setup_clear_cpu_cap(X86_FEATURE_XSAVEOPT);
                xstate_size = sizeof(struct i387_soft_struct);
                return;
        }
 
        if (cpu_has_fxsr)
                xstate_size = sizeof(struct i387_fxsave_struct);
-#ifdef CONFIG_X86_32
        else
                xstate_size = sizeof(struct i387_fsave_struct);
-#endif
 }
 
-#ifdef CONFIG_X86_64
 /*
  * Called at bootup to set up the initial FPU state that is later cloned
  * into all processes.
@@ -88,12 +91,21 @@ static void __cpuinit init_thread_xstate(void)
 
 void __cpuinit fpu_init(void)
 {
-       unsigned long oldcr0 = read_cr0();
-
-       set_in_cr4(X86_CR4_OSFXSR);
-       set_in_cr4(X86_CR4_OSXMMEXCPT);
+       unsigned long cr0;
+       unsigned long cr4_mask = 0;
 
-       write_cr0(oldcr0 & ~(X86_CR0_TS|X86_CR0_EM)); /* clear TS and EM */
+       if (cpu_has_fxsr)
+               cr4_mask |= X86_CR4_OSFXSR;
+       if (cpu_has_xmm)
+               cr4_mask |= X86_CR4_OSXMMEXCPT;
+       if (cr4_mask)
+               set_in_cr4(cr4_mask);
+
+       cr0 = read_cr0();
+       cr0 &= ~(X86_CR0_TS|X86_CR0_EM); /* clear TS and EM */
+       if (!HAVE_HWFP)
+               cr0 |= X86_CR0_EM;
+       write_cr0(cr0);
 
        if (!smp_processor_id())
                init_thread_xstate();
@@ -104,24 +116,12 @@ void __cpuinit fpu_init(void)
        clear_used_math();
 }
 
-#else  /* CONFIG_X86_64 */
-
-void __cpuinit fpu_init(void)
-{
-       if (!smp_processor_id())
-               init_thread_xstate();
-}
-
-#endif /* CONFIG_X86_32 */
-
 void fpu_finit(struct fpu *fpu)
 {
-#ifdef CONFIG_X86_32
        if (!HAVE_HWFP) {
                finit_soft_fpu(&fpu->state->soft);
                return;
        }
-#endif
 
        if (cpu_has_fxsr) {
                struct i387_fxsave_struct *fx = &fpu->state->fxsave;
@@ -386,19 +386,17 @@ convert_from_fxsr(struct user_i387_ia32_struct *env, struct task_struct *tsk)
 #ifdef CONFIG_X86_64
        env->fip = fxsave->rip;
        env->foo = fxsave->rdp;
+       /*
+        * should be actually ds/cs at fpu exception time, but
+        * that information is not available in 64bit mode.
+        */
+       env->fcs = task_pt_regs(tsk)->cs;
        if (tsk == current) {
-               /*
-                * should be actually ds/cs at fpu exception time, but
-                * that information is not available in 64bit mode.
-                */
-               asm("mov %%ds, %[fos]" : [fos] "=r" (env->fos));
-               asm("mov %%cs, %[fcs]" : [fcs] "=r" (env->fcs));
+               savesegment(ds, env->fos);
        } else {
-               struct pt_regs *regs = task_pt_regs(tsk);
-
-               env->fos = 0xffff0000 | tsk->thread.ds;
-               env->fcs = regs->cs;
+               env->fos = tsk->thread.ds;
        }
+       env->fos |= 0xffff0000;
 #else
        env->fip = fxsave->fip;
        env->fcs = (u16) fxsave->fcs | ((u32) fxsave->fop << 16);
index cafa7c80ac95714e7097ba06ff195cd6f285417f..20757cb2efa3121841f89bcbcd2f5e0ae0a6006c 100644 (file)
  * plus some generic x86 specific things if generic specifics makes
  * any sense at all.
  */
+static void init_8259A(int auto_eoi);
 
 static int i8259A_auto_eoi;
 DEFINE_RAW_SPINLOCK(i8259A_lock);
-static void mask_and_ack_8259A(unsigned int);
-static void mask_8259A(void);
-static void unmask_8259A(void);
-static void disable_8259A_irq(unsigned int irq);
-static void enable_8259A_irq(unsigned int irq);
-static void init_8259A(int auto_eoi);
-static int i8259A_irq_pending(unsigned int irq);
-
-struct irq_chip i8259A_chip = {
-       .name           = "XT-PIC",
-       .mask           = disable_8259A_irq,
-       .disable        = disable_8259A_irq,
-       .unmask         = enable_8259A_irq,
-       .mask_ack       = mask_and_ack_8259A,
-};
 
 /*
  * 8259A PIC functions to handle ISA devices:
@@ -68,7 +54,7 @@ unsigned int cached_irq_mask = 0xffff;
  */
 unsigned long io_apic_irqs;
 
-static void disable_8259A_irq(unsigned int irq)
+static void mask_8259A_irq(unsigned int irq)
 {
        unsigned int mask = 1 << irq;
        unsigned long flags;
@@ -82,7 +68,12 @@ static void disable_8259A_irq(unsigned int irq)
        raw_spin_unlock_irqrestore(&i8259A_lock, flags);
 }
 
-static void enable_8259A_irq(unsigned int irq)
+static void disable_8259A_irq(struct irq_data *data)
+{
+       mask_8259A_irq(data->irq);
+}
+
+static void unmask_8259A_irq(unsigned int irq)
 {
        unsigned int mask = ~(1 << irq);
        unsigned long flags;
@@ -96,6 +87,11 @@ static void enable_8259A_irq(unsigned int irq)
        raw_spin_unlock_irqrestore(&i8259A_lock, flags);
 }
 
+static void enable_8259A_irq(struct irq_data *data)
+{
+       unmask_8259A_irq(data->irq);
+}
+
 static int i8259A_irq_pending(unsigned int irq)
 {
        unsigned int mask = 1<<irq;
@@ -117,7 +113,7 @@ static void make_8259A_irq(unsigned int irq)
        disable_irq_nosync(irq);
        io_apic_irqs &= ~(1<<irq);
        set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
-                                     "XT");
+                                     i8259A_chip.name);
        enable_irq(irq);
 }
 
@@ -150,8 +146,9 @@ static inline int i8259A_irq_real(unsigned int irq)
  * first, _then_ send the EOI, and the order of EOI
  * to the two 8259s is important!
  */
-static void mask_and_ack_8259A(unsigned int irq)
+static void mask_and_ack_8259A(struct irq_data *data)
 {
+       unsigned int irq = data->irq;
        unsigned int irqmask = 1 << irq;
        unsigned long flags;
 
@@ -223,6 +220,14 @@ spurious_8259A_irq:
        }
 }
 
+struct irq_chip i8259A_chip = {
+       .name           = "XT-PIC",
+       .irq_mask       = disable_8259A_irq,
+       .irq_disable    = disable_8259A_irq,
+       .irq_unmask     = enable_8259A_irq,
+       .irq_mask_ack   = mask_and_ack_8259A,
+};
+
 static char irq_trigger[2];
 /**
  * ELCR registers (0x4d0, 0x4d1) control edge/level of IRQ
@@ -342,9 +347,9 @@ static void init_8259A(int auto_eoi)
                 * In AEOI mode we just have to mask the interrupt
                 * when acking.
                 */
-               i8259A_chip.mask_ack = disable_8259A_irq;
+               i8259A_chip.irq_mask_ack = disable_8259A_irq;
        else
-               i8259A_chip.mask_ack = mask_and_ack_8259A;
+               i8259A_chip.irq_mask_ack = mask_and_ack_8259A;
 
        udelay(100);            /* wait for 8259A to initialize */
 
@@ -363,14 +368,6 @@ static void init_8259A(int auto_eoi)
 static void legacy_pic_noop(void) { };
 static void legacy_pic_uint_noop(unsigned int unused) { };
 static void legacy_pic_int_noop(int unused) { };
-
-static struct irq_chip dummy_pic_chip  = {
-       .name = "dummy pic",
-       .mask = legacy_pic_uint_noop,
-       .unmask = legacy_pic_uint_noop,
-       .disable = legacy_pic_uint_noop,
-       .mask_ack = legacy_pic_uint_noop,
-};
 static int legacy_pic_irq_pending_noop(unsigned int irq)
 {
        return 0;
@@ -378,7 +375,9 @@ static int legacy_pic_irq_pending_noop(unsigned int irq)
 
 struct legacy_pic null_legacy_pic = {
        .nr_legacy_irqs = 0,
-       .chip = &dummy_pic_chip,
+       .chip = &dummy_irq_chip,
+       .mask = legacy_pic_uint_noop,
+       .unmask = legacy_pic_uint_noop,
        .mask_all = legacy_pic_noop,
        .restore_mask = legacy_pic_noop,
        .init = legacy_pic_int_noop,
@@ -389,7 +388,9 @@ struct legacy_pic null_legacy_pic = {
 struct legacy_pic default_legacy_pic = {
        .nr_legacy_irqs = NR_IRQS_LEGACY,
        .chip  = &i8259A_chip,
-       .mask_all  = mask_8259A,
+       .mask = mask_8259A_irq,
+       .unmask = unmask_8259A_irq,
+       .mask_all = mask_8259A,
        .restore_mask = unmask_8259A,
        .init = init_8259A,
        .irq_pending = i8259A_irq_pending,
index 91fd0c70a18abddc28eff75e287c70dd5d37af7d..83ec0175f986a5742c2ef85eff69d24100cd44b6 100644 (file)
@@ -67,10 +67,10 @@ static int show_other_interrupts(struct seq_file *p, int prec)
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs);
        seq_printf(p, "  Performance monitoring interrupts\n");
-       seq_printf(p, "%*s: ", prec, "PND");
+       seq_printf(p, "%*s: ", prec, "IWI");
        for_each_online_cpu(j)
-               seq_printf(p, "%10u ", irq_stats(j)->apic_pending_irqs);
-       seq_printf(p, "  Performance pending work\n");
+               seq_printf(p, "%10u ", irq_stats(j)->apic_irq_work_irqs);
+       seq_printf(p, "  IRQ work interrupts\n");
 #endif
        if (x86_platform_ipi_callback) {
                seq_printf(p, "%*s: ", prec, "PLT");
@@ -159,7 +159,7 @@ int show_interrupts(struct seq_file *p, void *v)
        seq_printf(p, "%*d: ", prec, i);
        for_each_online_cpu(j)
                seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
-       seq_printf(p, " %8s", desc->chip->name);
+       seq_printf(p, " %8s", desc->irq_data.chip->name);
        seq_printf(p, "-%-8s", desc->name);
 
        if (action) {
@@ -185,7 +185,7 @@ u64 arch_irq_stat_cpu(unsigned int cpu)
        sum += irq_stats(cpu)->apic_timer_irqs;
        sum += irq_stats(cpu)->irq_spurious_count;
        sum += irq_stats(cpu)->apic_perf_irqs;
-       sum += irq_stats(cpu)->apic_pending_irqs;
+       sum += irq_stats(cpu)->apic_irq_work_irqs;
 #endif
        if (x86_platform_ipi_callback)
                sum += irq_stats(cpu)->x86_platform_ipis;
@@ -282,6 +282,7 @@ void fixup_irqs(void)
        unsigned int irq, vector;
        static int warned;
        struct irq_desc *desc;
+       struct irq_data *data;
 
        for_each_irq_desc(irq, desc) {
                int break_affinity = 0;
@@ -296,7 +297,8 @@ void fixup_irqs(void)
                /* interrupt's are disabled at this point */
                raw_spin_lock(&desc->lock);
 
-               affinity = desc->affinity;
+               data = &desc->irq_data;
+               affinity = data->affinity;
                if (!irq_has_action(irq) ||
                    cpumask_equal(affinity, cpu_online_mask)) {
                        raw_spin_unlock(&desc->lock);
@@ -315,16 +317,16 @@ void fixup_irqs(void)
                        affinity = cpu_all_mask;
                }
 
-               if (!(desc->status & IRQ_MOVE_PCNTXT) && desc->chip->mask)
-                       desc->chip->mask(irq);
+               if (!(desc->status & IRQ_MOVE_PCNTXT) && data->chip->irq_mask)
+                       data->chip->irq_mask(data);
 
-               if (desc->chip->set_affinity)
-                       desc->chip->set_affinity(irq, affinity);
+               if (data->chip->irq_set_affinity)
+                       data->chip->irq_set_affinity(data, affinity, true);
                else if (!(warned++))
                        set_affinity = 0;
 
-               if (!(desc->status & IRQ_MOVE_PCNTXT) && desc->chip->unmask)
-                       desc->chip->unmask(irq);
+               if (!(desc->status & IRQ_MOVE_PCNTXT) && data->chip->irq_unmask)
+                       data->chip->irq_unmask(data);
 
                raw_spin_unlock(&desc->lock);
 
@@ -355,10 +357,10 @@ void fixup_irqs(void)
                if (irr  & (1 << (vector % 32))) {
                        irq = __get_cpu_var(vector_irq)[vector];
 
-                       desc = irq_to_desc(irq);
+                       data = irq_get_irq_data(irq);
                        raw_spin_lock(&desc->lock);
-                       if (desc->chip->retrigger)
-                               desc->chip->retrigger(irq);
+                       if (data->chip->irq_retrigger)
+                               data->chip->irq_retrigger(data);
                        raw_spin_unlock(&desc->lock);
                }
        }
diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c
new file mode 100644 (file)
index 0000000..ca8f703
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * x86 specific code for irq_work
+ *
+ * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq_work.h>
+#include <linux/hardirq.h>
+#include <asm/apic.h>
+
+void smp_irq_work_interrupt(struct pt_regs *regs)
+{
+       irq_enter();
+       ack_APIC_irq();
+       inc_irq_stat(apic_irq_work_irqs);
+       irq_work_run();
+       irq_exit();
+}
+
+void arch_irq_work_raise(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+       if (!cpu_has_apic)
+               return;
+
+       apic->send_IPI_self(IRQ_WORK_VECTOR);
+       apic_wait_icr_idle();
+#endif
+}
index 990ae7cfc5783f131df476506bc9341574a466c2..c752e973958d447ca2d34179df67a7af04c8a0bb 100644 (file)
@@ -100,6 +100,8 @@ int vector_used_by_percpu_irq(unsigned int vector)
 
 void __init init_ISA_irqs(void)
 {
+       struct irq_chip *chip = legacy_pic->chip;
+       const char *name = chip->name;
        int i;
 
 #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
@@ -107,19 +109,8 @@ void __init init_ISA_irqs(void)
 #endif
        legacy_pic->init(0);
 
-       /*
-        * 16 old-style INTA-cycle interrupts:
-        */
-       for (i = 0; i < legacy_pic->nr_legacy_irqs; i++) {
-               struct irq_desc *desc = irq_to_desc(i);
-
-               desc->status = IRQ_DISABLED;
-               desc->action = NULL;
-               desc->depth = 1;
-
-               set_irq_chip_and_handler_name(i, &i8259A_chip,
-                                             handle_level_irq, "XT");
-       }
+       for (i = 0; i < legacy_pic->nr_legacy_irqs; i++)
+               set_irq_chip_and_handler_name(i, chip, handle_level_irq, name);
 }
 
 void __init init_IRQ(void)
@@ -224,9 +215,9 @@ static void __init apic_intr_init(void)
        alloc_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
        alloc_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
 
-       /* Performance monitoring interrupts: */
-# ifdef CONFIG_PERF_EVENTS
-       alloc_intr_gate(LOCAL_PENDING_VECTOR, perf_pending_interrupt);
+       /* IRQ work interrupts: */
+# ifdef CONFIG_IRQ_WORK
+       alloc_intr_gate(IRQ_WORK_VECTOR, irq_work_interrupt);
 # endif
 
 #endif
diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c
new file mode 100644 (file)
index 0000000..961b6b3
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * jump label x86 support
+ *
+ * Copyright (C) 2009 Jason Baron <jbaron@redhat.com>
+ *
+ */
+#include <linux/jump_label.h>
+#include <linux/memory.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
+#include <linux/cpu.h>
+#include <asm/kprobes.h>
+#include <asm/alternative.h>
+
+#ifdef HAVE_JUMP_LABEL
+
+union jump_code_union {
+       char code[JUMP_LABEL_NOP_SIZE];
+       struct {
+               char jump;
+               int offset;
+       } __attribute__((packed));
+};
+
+void arch_jump_label_transform(struct jump_entry *entry,
+                              enum jump_label_type type)
+{
+       union jump_code_union code;
+
+       if (type == JUMP_LABEL_ENABLE) {
+               code.jump = 0xe9;
+               code.offset = entry->target -
+                               (entry->code + JUMP_LABEL_NOP_SIZE);
+       } else
+               memcpy(&code, ideal_nop5, JUMP_LABEL_NOP_SIZE);
+       get_online_cpus();
+       mutex_lock(&text_mutex);
+       text_poke_smp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
+       mutex_unlock(&text_mutex);
+       put_online_cpus();
+}
+
+void arch_jump_label_text_poke_early(jump_label_t addr)
+{
+       text_poke_early((void *)addr, ideal_nop5, JUMP_LABEL_NOP_SIZE);
+}
+
+#endif
index 770ebfb349e93efe3367cf0c6caff93b61b8b884..1cbd54c0df99189548a3a03f40fbb75a1703475a 100644 (file)
@@ -230,9 +230,6 @@ static int recover_probed_instruction(kprobe_opcode_t *buf, unsigned long addr)
        return 0;
 }
 
-/* Dummy buffers for kallsyms_lookup */
-static char __dummy_buf[KSYM_NAME_LEN];
-
 /* Check if paddr is at an instruction boundary */
 static int __kprobes can_probe(unsigned long paddr)
 {
@@ -241,7 +238,7 @@ static int __kprobes can_probe(unsigned long paddr)
        struct insn insn;
        kprobe_opcode_t buf[MAX_INSN_SIZE];
 
-       if (!kallsyms_lookup(paddr, NULL, &offset, NULL, __dummy_buf))
+       if (!kallsyms_lookup_size_offset(paddr, NULL, &offset))
                return 0;
 
        /* Decode instructions */
@@ -1129,7 +1126,7 @@ static void __kprobes synthesize_set_arg1(kprobe_opcode_t *addr,
        *(unsigned long *)addr = val;
 }
 
-void __kprobes kprobes_optinsn_template_holder(void)
+static void __used __kprobes kprobes_optinsn_template_holder(void)
 {
        asm volatile (
                        ".global optprobe_template_entry\n"
@@ -1221,7 +1218,8 @@ static int __kprobes copy_optimized_instructions(u8 *dest, u8 *src)
        }
        /* Check whether the address range is reserved */
        if (ftrace_text_reserved(src, src + len - 1) ||
-           alternatives_text_reserved(src, src + len - 1))
+           alternatives_text_reserved(src, src + len - 1) ||
+           jump_label_text_reserved(src, src + len - 1))
                return -EBUSY;
 
        return len;
@@ -1269,11 +1267,9 @@ static int __kprobes can_optimize(unsigned long paddr)
        unsigned long addr, size = 0, offset = 0;
        struct insn insn;
        kprobe_opcode_t buf[MAX_INSN_SIZE];
-       /* Dummy buffers for lookup_symbol_attrs */
-       static char __dummy_buf[KSYM_NAME_LEN];
 
        /* Lookup symbol including addr */
-       if (!kallsyms_lookup(paddr, &size, &offset, NULL, __dummy_buf))
+       if (!kallsyms_lookup_size_offset(paddr, &size, &offset))
                return 0;
 
        /* Check there is enough space for a relative jump. */
index 035c8c529181fa351c042f8d6a5b8ec3240dec8f..b3ea9db39db6f7ee9f9dab00632f754d8a75827d 100644 (file)
@@ -36,7 +36,7 @@ static int init_one_level2_page(struct kimage *image, pgd_t *pgd,
                if (!page)
                        goto out;
                pud = (pud_t *)page_address(page);
-               memset(pud, 0, PAGE_SIZE);
+               clear_page(pud);
                set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE));
        }
        pud = pud_offset(pgd, addr);
@@ -45,7 +45,7 @@ static int init_one_level2_page(struct kimage *image, pgd_t *pgd,
                if (!page)
                        goto out;
                pmd = (pmd_t *)page_address(page);
-               memset(pmd, 0, PAGE_SIZE);
+               clear_page(pmd);
                set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE));
        }
        pmd = pmd_offset(pud, addr);
index 1c355c550960ab75279c644b52269cd5a368239a..8f295609173524cdf06a20c6c0ad4fbe1de12263 100644 (file)
@@ -239,6 +239,9 @@ int module_finalize(const Elf_Ehdr *hdr,
                apply_paravirt(pseg, pseg + para->sh_size);
        }
 
+       /* make jump label nops */
+       jump_label_apply_nops(me);
+
        return 0;
 }
 
index d7b6f7fb4fecfd44205d63ab6cfebfb400e8b21a..9af64d9c4b6770c4fea928f6b2a9533c1f4620e8 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/kernel_stat.h>
 #include <linux/mc146818rtc.h>
 #include <linux/bitops.h>
@@ -657,7 +658,7 @@ static void __init smp_reserve_memory(struct mpf_intel *mpf)
 {
        unsigned long size = get_mpc_size(mpf->physptr);
 
-       reserve_early_overlap_ok(mpf->physptr, mpf->physptr+size, "MP-table mpc");
+       memblock_x86_reserve_range(mpf->physptr, mpf->physptr+size, "* MP-table mpc");
 }
 
 static int __init smp_scan_config(unsigned long base, unsigned long length)
@@ -686,7 +687,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length)
                               mpf, (u64)virt_to_phys(mpf));
 
                        mem = virt_to_phys(mpf);
-                       reserve_early_overlap_ok(mem, mem + sizeof(*mpf), "MP-table mpf");
+                       memblock_x86_reserve_range(mem, mem + sizeof(*mpf), "* MP-table mpf");
                        if (mpf->physptr)
                                smp_reserve_memory(mpf);
 
diff --git a/arch/x86/kernel/olpc-xo1.c b/arch/x86/kernel/olpc-xo1.c
new file mode 100644 (file)
index 0000000..f5442c0
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Support for features of the OLPC XO-1 laptop
+ *
+ * Copyright (C) 2010 One Laptop per Child
+ * Copyright (C) 2006 Red Hat, Inc.
+ * Copyright (C) 2006 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+#include <asm/io.h>
+#include <asm/olpc.h>
+
+#define DRV_NAME "olpc-xo1"
+
+#define PMS_BAR                4
+#define ACPI_BAR       5
+
+/* PMC registers (PMS block) */
+#define PM_SCLK                0x10
+#define PM_IN_SLPCTL   0x20
+#define PM_WKXD                0x34
+#define PM_WKD         0x30
+#define PM_SSC         0x54
+
+/* PM registers (ACPI block) */
+#define PM1_CNT                0x08
+#define PM_GPE0_STS    0x18
+
+static unsigned long acpi_base;
+static unsigned long pms_base;
+
+static void xo1_power_off(void)
+{
+       printk(KERN_INFO "OLPC XO-1 power off sequence...\n");
+
+       /* Enable all of these controls with 0 delay */
+       outl(0x40000000, pms_base + PM_SCLK);
+       outl(0x40000000, pms_base + PM_IN_SLPCTL);
+       outl(0x40000000, pms_base + PM_WKXD);
+       outl(0x40000000, pms_base + PM_WKD);
+
+       /* Clear status bits (possibly unnecessary) */
+       outl(0x0002ffff, pms_base  + PM_SSC);
+       outl(0xffffffff, acpi_base + PM_GPE0_STS);
+
+       /* Write SLP_EN bit to start the machinery */
+       outl(0x00002000, acpi_base + PM1_CNT);
+}
+
+/* Read the base addresses from the PCI BAR info */
+static int __devinit setup_bases(struct pci_dev *pdev)
+{
+       int r;
+
+       r = pci_enable_device_io(pdev);
+       if (r) {
+               dev_err(&pdev->dev, "can't enable device IO\n");
+               return r;
+       }
+
+       r = pci_request_region(pdev, ACPI_BAR, DRV_NAME);
+       if (r) {
+               dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", ACPI_BAR);
+               return r;
+       }
+
+       r = pci_request_region(pdev, PMS_BAR, DRV_NAME);
+       if (r) {
+               dev_err(&pdev->dev, "can't alloc PCI BAR #%d\n", PMS_BAR);
+               pci_release_region(pdev, ACPI_BAR);
+               return r;
+       }
+
+       acpi_base = pci_resource_start(pdev, ACPI_BAR);
+       pms_base = pci_resource_start(pdev, PMS_BAR);
+
+       return 0;
+}
+
+static int __devinit olpc_xo1_probe(struct platform_device *pdev)
+{
+       struct pci_dev *pcidev;
+       int r;
+
+       pcidev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA,
+                               NULL);
+       if (!pdev)
+               return -ENODEV;
+
+       r = setup_bases(pcidev);
+       if (r)
+               return r;
+
+       pm_power_off = xo1_power_off;
+
+       printk(KERN_INFO "OLPC XO-1 support registered\n");
+       return 0;
+}
+
+static int __devexit olpc_xo1_remove(struct platform_device *pdev)
+{
+       pm_power_off = NULL;
+       return 0;
+}
+
+static struct platform_driver olpc_xo1_driver = {
+       .driver = {
+               .name = DRV_NAME,
+               .owner = THIS_MODULE,
+       },
+       .probe = olpc_xo1_probe,
+       .remove = __devexit_p(olpc_xo1_remove),
+};
+
+static int __init olpc_xo1_init(void)
+{
+       return platform_driver_register(&olpc_xo1_driver);
+}
+
+static void __exit olpc_xo1_exit(void)
+{
+       platform_driver_unregister(&olpc_xo1_driver);
+}
+
+MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:olpc-xo1");
+
+module_init(olpc_xo1_init);
+module_exit(olpc_xo1_exit);
index 0e0cdde519be93a3cda8bab4ba6d8637632171ef..edaf3fe8dc5e4b0326c0280042b868cd3400bf4c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/spinlock.h>
 #include <linux/io.h>
 #include <linux/string.h>
+#include <linux/platform_device.h>
 
 #include <asm/geode.h>
 #include <asm/setup.h>
@@ -114,6 +115,7 @@ int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
        unsigned long flags;
        int ret = -EIO;
        int i;
+       int restarts = 0;
 
        spin_lock_irqsave(&ec_lock, flags);
 
@@ -169,7 +171,9 @@ restart:
                        if (wait_on_obf(0x6c, 1)) {
                                printk(KERN_ERR "olpc-ec:  timeout waiting for"
                                                " EC to provide data!\n");
-                               goto restart;
+                               if (restarts++ < 10)
+                                       goto restart;
+                               goto err;
                        }
                        outbuf[i] = inb(0x68);
                        pr_devel("olpc-ec:  received 0x%x\n", outbuf[i]);
@@ -183,8 +187,21 @@ err:
 }
 EXPORT_SYMBOL_GPL(olpc_ec_cmd);
 
-#ifdef CONFIG_OLPC_OPENFIRMWARE
-static void __init platform_detect(void)
+static bool __init check_ofw_architecture(void)
+{
+       size_t propsize;
+       char olpc_arch[5];
+       const void *args[] = { NULL, "architecture", olpc_arch, (void *)5 };
+       void *res[] = { &propsize };
+
+       if (olpc_ofw("getprop", args, res)) {
+               printk(KERN_ERR "ofw: getprop call failed!\n");
+               return false;
+       }
+       return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0;
+}
+
+static u32 __init get_board_revision(void)
 {
        size_t propsize;
        __be32 rev;
@@ -193,45 +210,43 @@ static void __init platform_detect(void)
 
        if (olpc_ofw("getprop", args, res) || propsize != 4) {
                printk(KERN_ERR "ofw: getprop call failed!\n");
-               rev = cpu_to_be32(0);
+               return cpu_to_be32(0);
        }
-       olpc_platform_info.boardrev = be32_to_cpu(rev);
+       return be32_to_cpu(rev);
 }
-#else
-static void __init platform_detect(void)
+
+static bool __init platform_detect(void)
 {
-       /* stopgap until OFW support is added to the kernel */
-       olpc_platform_info.boardrev = olpc_board(0xc2);
+       if (!check_ofw_architecture())
+               return false;
+       olpc_platform_info.flags |= OLPC_F_PRESENT;
+       olpc_platform_info.boardrev = get_board_revision();
+       return true;
 }
-#endif
 
-static int __init olpc_init(void)
+static int __init add_xo1_platform_devices(void)
 {
-       unsigned char *romsig;
+       struct platform_device *pdev;
 
-       /* The ioremap check is dangerous; limit what we run it on */
-       if (!is_geode() || cs5535_has_vsa2())
-               return 0;
+       pdev = platform_device_register_simple("xo1-rfkill", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
 
-       spin_lock_init(&ec_lock);
+       pdev = platform_device_register_simple("olpc-xo1", -1, NULL, 0);
+       if (IS_ERR(pdev))
+               return PTR_ERR(pdev);
 
-       romsig = ioremap(0xffffffc0, 16);
-       if (!romsig)
-               return 0;
+       return 0;
+}
 
-       if (strncmp(romsig, "CL1   Q", 7))
-               goto unmap;
-       if (strncmp(romsig+6, romsig+13, 3)) {
-               printk(KERN_INFO "OLPC BIOS signature looks invalid.  "
-                               "Assuming not OLPC\n");
-               goto unmap;
-       }
+static int __init olpc_init(void)
+{
+       int r = 0;
 
-       printk(KERN_INFO "OLPC board with OpenFirmware %.16s\n", romsig);
-       olpc_platform_info.flags |= OLPC_F_PRESENT;
+       if (!olpc_ofw_present() || !platform_detect())
+               return 0;
 
-       /* get the platform revision */
-       platform_detect();
+       spin_lock_init(&ec_lock);
 
        /* assume B1 and above models always have a DCON */
        if (olpc_board_at_least(olpc_board(0xb1)))
@@ -242,8 +257,10 @@ static int __init olpc_init(void)
                        (unsigned char *) &olpc_platform_info.ecver, 1);
 
 #ifdef CONFIG_PCI_OLPC
-       /* If the VSA exists let it emulate PCI, if not emulate in kernel */
-       if (!cs5535_has_vsa2())
+       /* If the VSA exists let it emulate PCI, if not emulate in kernel.
+        * XO-1 only. */
+       if (olpc_platform_info.boardrev < olpc_board_pre(0xd0) &&
+                       !cs5535_has_vsa2())
                x86_init.pci.arch_init = pci_olpc_init;
 #endif
 
@@ -252,8 +269,12 @@ static int __init olpc_init(void)
                        olpc_platform_info.boardrev >> 4,
                        olpc_platform_info.ecver);
 
-unmap:
-       iounmap(romsig);
+       if (olpc_platform_info.boardrev < olpc_board_pre(0xd0)) { /* XO-1 */
+               r = add_xo1_platform_devices();
+               if (r)
+                       return r;
+       }
+
        return 0;
 }
 
index 3218aa71ab5ebb7dd20a7d1dd94cfd88dcb3d755..787320464379f976626e22fb2d62a83730ccbf52 100644 (file)
@@ -74,6 +74,12 @@ int __olpc_ofw(const char *name, int nr_args, const void **args, int nr_res,
 }
 EXPORT_SYMBOL_GPL(__olpc_ofw);
 
+bool olpc_ofw_present(void)
+{
+       return olpc_ofw_cif != NULL;
+}
+EXPORT_SYMBOL_GPL(olpc_ofw_present);
+
 /* OFW cif _should_ be above this address */
 #define OFW_MIN 0xff000000
 
index 1db183ed7c01cb929cef9dc3fc6e1f1153841e59..c5b250011fd479aa8ecc8f8348ade0b096a7aa08 100644 (file)
@@ -413,7 +413,6 @@ struct pv_mmu_ops pv_mmu_ops = {
 
        .alloc_pte = paravirt_nop,
        .alloc_pmd = paravirt_nop,
-       .alloc_pmd_clone = paravirt_nop,
        .alloc_pud = paravirt_nop,
        .release_pte = paravirt_nop,
        .release_pmd = paravirt_nop,
index 078d4ec1a9d92d462c27e0cd6f7bb095b2838526..f56a117cef68999ceeab576e2ef2b116a4fa9db2 100644 (file)
@@ -47,6 +47,7 @@
 #include <asm/rio.h>
 #include <asm/bios_ebda.h>
 #include <asm/x86_init.h>
+#include <asm/iommu_table.h>
 
 #ifdef CONFIG_CALGARY_IOMMU_ENABLED_BY_DEFAULT
 int use_calgary __read_mostly = 1;
@@ -1364,7 +1365,7 @@ static int __init calgary_iommu_init(void)
        return 0;
 }
 
-void __init detect_calgary(void)
+int __init detect_calgary(void)
 {
        int bus;
        void *tbl;
@@ -1378,13 +1379,13 @@ void __init detect_calgary(void)
         * another HW IOMMU already, bail out.
         */
        if (no_iommu || iommu_detected)
-               return;
+               return -ENODEV;
 
        if (!use_calgary)
-               return;
+               return -ENODEV;
 
        if (!early_pci_allowed())
-               return;
+               return -ENODEV;
 
        printk(KERN_DEBUG "Calgary: detecting Calgary via BIOS EBDA area\n");
 
@@ -1410,13 +1411,13 @@ void __init detect_calgary(void)
        if (!rio_table_hdr) {
                printk(KERN_DEBUG "Calgary: Unable to locate Rio Grande table "
                       "in EBDA - bailing!\n");
-               return;
+               return -ENODEV;
        }
 
        ret = build_detail_arrays();
        if (ret) {
                printk(KERN_DEBUG "Calgary: build_detail_arrays ret %d\n", ret);
-               return;
+               return -ENOMEM;
        }
 
        specified_table_size = determine_tce_table_size((is_kdump_kernel() ?
@@ -1464,7 +1465,7 @@ void __init detect_calgary(void)
 
                x86_init.iommu.iommu_init = calgary_iommu_init;
        }
-       return;
+       return calgary_found;
 
 cleanup:
        for (--bus; bus >= 0; --bus) {
@@ -1473,6 +1474,7 @@ cleanup:
                if (info->tce_space)
                        free_tce_table(info->tce_space);
        }
+       return -ENOMEM;
 }
 
 static int __init calgary_parse_options(char *p)
@@ -1594,3 +1596,5 @@ static int __init calgary_fixup_tce_spaces(void)
  * and before device_initcall.
  */
 rootfs_initcall(calgary_fixup_tce_spaces);
+
+IOMMU_INIT_POST(detect_calgary);
index 9f07cfcbd3a5e60db651c952c9a66fa21dd68d87..9ea999a4dcc178ce4e27dd069a957ff050d1dee7 100644 (file)
@@ -11,9 +11,8 @@
 #include <asm/iommu.h>
 #include <asm/gart.h>
 #include <asm/calgary.h>
-#include <asm/amd_iommu.h>
 #include <asm/x86_init.h>
-#include <asm/xen/swiotlb-xen.h>
+#include <asm/iommu_table.h>
 
 static int forbid_dac __read_mostly;
 
@@ -45,6 +44,8 @@ int iommu_detected __read_mostly = 0;
  */
 int iommu_pass_through __read_mostly;
 
+extern struct iommu_table_entry __iommu_table[], __iommu_table_end[];
+
 /* Dummy device used for NULL arguments (normally ISA). */
 struct device x86_dma_fallback_dev = {
        .init_name = "fallback device",
@@ -130,26 +131,24 @@ static void __init dma32_free_bootmem(void)
 
 void __init pci_iommu_alloc(void)
 {
+       struct iommu_table_entry *p;
+
        /* free the range so iommu could get some range less than 4G */
        dma32_free_bootmem();
 
-       if (pci_xen_swiotlb_detect() || pci_swiotlb_detect())
-               goto out;
-
-       gart_iommu_hole_init();
-
-       detect_calgary();
-
-       detect_intel_iommu();
+       sort_iommu_table(__iommu_table, __iommu_table_end);
+       check_iommu_entries(__iommu_table, __iommu_table_end);
 
-       /* needs to be called after gart_iommu_hole_init */
-       amd_iommu_detect();
-out:
-       pci_xen_swiotlb_init();
-
-       pci_swiotlb_init();
+       for (p = __iommu_table; p < __iommu_table_end; p++) {
+               if (p && p->detect && p->detect() > 0) {
+                       p->flags |= IOMMU_DETECTED;
+                       if (p->early_init)
+                               p->early_init();
+                       if (p->flags & IOMMU_FINISH_IF_DETECTED)
+                               break;
+               }
+       }
 }
-
 void *dma_generic_alloc_coherent(struct device *dev, size_t size,
                                 dma_addr_t *dma_addr, gfp_t flag)
 {
@@ -292,6 +291,7 @@ EXPORT_SYMBOL(dma_supported);
 
 static int __init pci_iommu_init(void)
 {
+       struct iommu_table_entry *p;
        dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES);
 
 #ifdef CONFIG_PCI
@@ -299,12 +299,10 @@ static int __init pci_iommu_init(void)
 #endif
        x86_init.iommu.iommu_init();
 
-       if (swiotlb || xen_swiotlb) {
-               printk(KERN_INFO "PCI-DMA: "
-                      "Using software bounce buffering for IO (SWIOTLB)\n");
-               swiotlb_print_info();
-       } else
-               swiotlb_free();
+       for (p = __iommu_table; p < __iommu_table_end; p++) {
+               if (p && (p->flags & IOMMU_DETECTED) && p->late_init)
+                       p->late_init();
+       }
 
        return 0;
 }
index 0f7f130caa6778d6077868e6e768b88f1439fc24..ba0f0ca9f280bb0473470fdb71a3fa04faec00f0 100644 (file)
@@ -39,8 +39,9 @@
 #include <asm/cacheflush.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 #include <asm/x86_init.h>
+#include <asm/iommu_table.h>
 
 static unsigned long iommu_bus_base;   /* GART remapping area (physical) */
 static unsigned long iommu_size;       /* size of remapping area bytes */
@@ -560,8 +561,11 @@ static void enable_gart_translations(void)
 {
        int i;
 
-       for (i = 0; i < num_k8_northbridges; i++) {
-               struct pci_dev *dev = k8_northbridges[i];
+       if (!k8_northbridges.gart_supported)
+               return;
+
+       for (i = 0; i < k8_northbridges.num; i++) {
+               struct pci_dev *dev = k8_northbridges.nb_misc[i];
 
                enable_gart_translation(dev, __pa(agp_gatt_table));
        }
@@ -592,16 +596,19 @@ static void gart_fixup_northbridges(struct sys_device *dev)
        if (!fix_up_north_bridges)
                return;
 
+       if (!k8_northbridges.gart_supported)
+               return;
+
        pr_info("PCI-DMA: Restoring GART aperture settings\n");
 
-       for (i = 0; i < num_k8_northbridges; i++) {
-               struct pci_dev *dev = k8_northbridges[i];
+       for (i = 0; i < k8_northbridges.num; i++) {
+               struct pci_dev *dev = k8_northbridges.nb_misc[i];
 
                /*
                 * Don't enable translations just yet.  That is the next
                 * step.  Restore the pre-suspend aperture settings.
                 */
-               pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, aperture_order << 1);
+               gart_set_size_and_enable(dev, aperture_order);
                pci_write_config_dword(dev, AMD64_GARTAPERTUREBASE, aperture_alloc >> 25);
        }
 }
@@ -649,8 +656,8 @@ static __init int init_k8_gatt(struct agp_kern_info *info)
 
        aper_size = aper_base = info->aper_size = 0;
        dev = NULL;
-       for (i = 0; i < num_k8_northbridges; i++) {
-               dev = k8_northbridges[i];
+       for (i = 0; i < k8_northbridges.num; i++) {
+               dev = k8_northbridges.nb_misc[i];
                new_aper_base = read_aperture(dev, &new_aper_size);
                if (!new_aper_base)
                        goto nommu;
@@ -718,10 +725,13 @@ static void gart_iommu_shutdown(void)
        if (!no_agp)
                return;
 
-       for (i = 0; i < num_k8_northbridges; i++) {
+       if (!k8_northbridges.gart_supported)
+               return;
+
+       for (i = 0; i < k8_northbridges.num; i++) {
                u32 ctl;
 
-               dev = k8_northbridges[i];
+               dev = k8_northbridges.nb_misc[i];
                pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &ctl);
 
                ctl &= ~GARTEN;
@@ -739,7 +749,7 @@ int __init gart_iommu_init(void)
        unsigned long scratch;
        long i;
 
-       if (num_k8_northbridges == 0)
+       if (!k8_northbridges.gart_supported)
                return 0;
 
 #ifndef CONFIG_AGP_AMD64
@@ -896,3 +906,4 @@ void __init gart_parse_options(char *p)
                }
        }
 }
+IOMMU_INIT_POST(gart_iommu_hole_init);
diff --git a/arch/x86/kernel/pci-iommu_table.c b/arch/x86/kernel/pci-iommu_table.c
new file mode 100644 (file)
index 0000000..55d745e
--- /dev/null
@@ -0,0 +1,89 @@
+#include <linux/dma-mapping.h>
+#include <asm/iommu_table.h>
+#include <linux/string.h>
+#include <linux/kallsyms.h>
+
+
+#define DEBUG 1
+
+static struct iommu_table_entry * __init
+find_dependents_of(struct iommu_table_entry *start,
+                  struct iommu_table_entry *finish,
+                  struct iommu_table_entry *q)
+{
+       struct iommu_table_entry *p;
+
+       if (!q)
+               return NULL;
+
+       for (p = start; p < finish; p++)
+               if (p->detect == q->depend)
+                       return p;
+
+       return NULL;
+}
+
+
+void __init sort_iommu_table(struct iommu_table_entry *start,
+                            struct iommu_table_entry *finish) {
+
+       struct iommu_table_entry *p, *q, tmp;
+
+       for (p = start; p < finish; p++) {
+again:
+               q = find_dependents_of(start, finish, p);
+               /* We are bit sneaky here. We use the memory address to figure
+                * out if the node we depend on is past our point, if so, swap.
+                */
+               if (q > p) {
+                       tmp = *p;
+                       memmove(p, q, sizeof(*p));
+                       *q = tmp;
+                       goto again;
+               }
+       }
+
+}
+
+#ifdef DEBUG
+void __init check_iommu_entries(struct iommu_table_entry *start,
+                               struct iommu_table_entry *finish)
+{
+       struct iommu_table_entry *p, *q, *x;
+       char sym_p[KSYM_SYMBOL_LEN];
+       char sym_q[KSYM_SYMBOL_LEN];
+
+       /* Simple cyclic dependency checker. */
+       for (p = start; p < finish; p++) {
+               q = find_dependents_of(start, finish, p);
+               x = find_dependents_of(start, finish, q);
+               if (p == x) {
+                       sprint_symbol(sym_p, (unsigned long)p->detect);
+                       sprint_symbol(sym_q, (unsigned long)q->detect);
+
+                       printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %s depends" \
+                                       " on %s and vice-versa. BREAKING IT.\n",
+                                       sym_p, sym_q);
+                       /* Heavy handed way..*/
+                       x->depend = 0;
+               }
+       }
+
+       for (p = start; p < finish; p++) {
+               q = find_dependents_of(p, finish, p);
+               if (q && q > p) {
+                       sprint_symbol(sym_p, (unsigned long)p->detect);
+                       sprint_symbol(sym_q, (unsigned long)q->detect);
+
+                       printk(KERN_ERR "EXECUTION ORDER INVALID! %s "\
+                                       "should be called before %s!\n",
+                                       sym_p, sym_q);
+               }
+       }
+}
+#else
+inline void check_iommu_entries(struct iommu_table_entry *start,
+                                      struct iommu_table_entry *finish)
+{
+}
+#endif
index a5bc528d43282a344936922328d2b5bf59b187ae..8f972cbddef0c390df0a386ff4d08a8c20865ea1 100644 (file)
@@ -10,7 +10,8 @@
 #include <asm/iommu.h>
 #include <asm/swiotlb.h>
 #include <asm/dma.h>
-
+#include <asm/xen/swiotlb-xen.h>
+#include <asm/iommu_table.h>
 int swiotlb __read_mostly;
 
 static void *x86_swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -41,25 +42,42 @@ static struct dma_map_ops swiotlb_dma_ops = {
 };
 
 /*
- * pci_swiotlb_detect - set swiotlb to 1 if necessary
+ * pci_swiotlb_detect_override - set swiotlb to 1 if necessary
  *
  * This returns non-zero if we are forced to use swiotlb (by the boot
  * option).
  */
-int __init pci_swiotlb_detect(void)
+int __init pci_swiotlb_detect_override(void)
 {
        int use_swiotlb = swiotlb | swiotlb_force;
 
+       if (swiotlb_force)
+               swiotlb = 1;
+
+       return use_swiotlb;
+}
+IOMMU_INIT_FINISH(pci_swiotlb_detect_override,
+                 pci_xen_swiotlb_detect,
+                 pci_swiotlb_init,
+                 pci_swiotlb_late_init);
+
+/*
+ * if 4GB or more detected (and iommu=off not set) return 1
+ * and set swiotlb to 1.
+ */
+int __init pci_swiotlb_detect_4gb(void)
+{
        /* don't initialize swiotlb if iommu=off (no_iommu=1) */
 #ifdef CONFIG_X86_64
        if (!no_iommu && max_pfn > MAX_DMA32_PFN)
                swiotlb = 1;
 #endif
-       if (swiotlb_force)
-               swiotlb = 1;
-
-       return use_swiotlb;
+       return swiotlb;
 }
+IOMMU_INIT(pci_swiotlb_detect_4gb,
+          pci_swiotlb_detect_override,
+          pci_swiotlb_init,
+          pci_swiotlb_late_init);
 
 void __init pci_swiotlb_init(void)
 {
@@ -68,3 +86,15 @@ void __init pci_swiotlb_init(void)
                dma_ops = &swiotlb_dma_ops;
        }
 }
+
+void __init pci_swiotlb_late_init(void)
+{
+       /* An IOMMU turned us off. */
+       if (!swiotlb)
+               swiotlb_free();
+       else {
+               printk(KERN_INFO "PCI-DMA: "
+                      "Using software bounce buffering for IO (SWIOTLB)\n");
+               swiotlb_print_info();
+       }
+}
diff --git a/arch/x86/kernel/pmtimer_64.c b/arch/x86/kernel/pmtimer_64.c
deleted file mode 100644 (file)
index b112406..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/* Ported over from i386 by AK, original copyright was:
- *
- * (C) Dominik Brodowski <linux@brodo.de> 2003
- *
- * Driver to use the Power Management Timer (PMTMR) available in some
- * southbridges as primary timing source for the Linux kernel.
- *
- * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
- * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
- *
- * This file is licensed under the GPL v2.
- *
- * Dropped all the hardware bug workarounds for now. Hopefully they
- * are not needed on 64bit chipsets.
- */
-
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/time.h>
-#include <linux/init.h>
-#include <linux/cpumask.h>
-#include <linux/acpi_pmtmr.h>
-
-#include <asm/io.h>
-#include <asm/proto.h>
-#include <asm/msr.h>
-#include <asm/vsyscall.h>
-
-static inline u32 cyc2us(u32 cycles)
-{
-       /* The Power Management Timer ticks at 3.579545 ticks per microsecond.
-        * 1 / PM_TIMER_FREQUENCY == 0.27936511 =~ 286/1024 [error: 0.024%]
-        *
-        * Even with HZ = 100, delta is at maximum 35796 ticks, so it can
-        * easily be multiplied with 286 (=0x11E) without having to fear
-        * u32 overflows.
-        */
-       cycles *= 286;
-       return (cycles >> 10);
-}
-
-static unsigned pmtimer_wait_tick(void)
-{
-       u32 a, b;
-       for (a = b = inl(pmtmr_ioport) & ACPI_PM_MASK;
-            a == b;
-            b = inl(pmtmr_ioport) & ACPI_PM_MASK)
-               cpu_relax();
-       return b;
-}
-
-/* note: wait time is rounded up to one tick */
-void pmtimer_wait(unsigned us)
-{
-       u32 a, b;
-       a = pmtimer_wait_tick();
-       do {
-               b = inl(pmtmr_ioport);
-               cpu_relax();
-       } while (cyc2us(b - a) < us);
-}
-
-static int __init nopmtimer_setup(char *s)
-{
-       pmtmr_ioport = 0;
-       return 1;
-}
-
-__setup("nopmtimer", nopmtimer_setup);
index 3d9ea531ddd1bfa8cc9e2e28fbfa8a22f461bc20..b3d7a3a04f389d9626837a1e776c5106e821f7dc 100644 (file)
@@ -424,7 +424,7 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
        load_TLS(next, cpu);
 
        /* Must be after DS reload */
-       unlazy_fpu(prev_p);
+       __unlazy_fpu(prev_p);
 
        /* Make sure cpu is ready for new context */
        if (preload_fpu)
index e3af342fe83ae7a57b8f6db6de4fb9541c4ab15e..7a4cf14223ba3288384909657d49edff7371623e 100644 (file)
@@ -84,7 +84,7 @@ static int __init reboot_setup(char *str)
                        }
                                /* we will leave sorting out the final value
                                   when we are ready to reboot, since we might not
-                                  have set up boot_cpu_id or smp_num_cpu */
+                                  have detected BSP APIC ID or smp_num_cpu */
                        break;
 #endif /* CONFIG_SMP */
 
index c3a4fbb2b996d00277d6523cb76b74e2c5944621..420e6419785025f39c1e4095a9d7e6f558c8a1db 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/apm_bios.h>
 #include <linux/initrd.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/seq_file.h>
 #include <linux/console.h>
 #include <linux/mca.h>
@@ -83,7 +84,6 @@
 #include <asm/dmi.h>
 #include <asm/io_apic.h>
 #include <asm/ist.h>
-#include <asm/vmi.h>
 #include <asm/setup_arch.h>
 #include <asm/bios_ebda.h>
 #include <asm/cacheflush.h>
 #include <asm/percpu.h>
 #include <asm/topology.h>
 #include <asm/apicdef.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 #ifdef CONFIG_X86_64
 #include <asm/numa_64.h>
 #endif
 #include <asm/mce.h>
+#include <asm/alternative.h>
 
 /*
  * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
@@ -125,7 +126,6 @@ unsigned long max_pfn_mapped;
 RESERVE_BRK(dmi_alloc, 65536);
 #endif
 
-unsigned int boot_cpu_id __read_mostly;
 
 static __initdata unsigned long _brk_start = (unsigned long)__brk_base;
 unsigned long _brk_end = (unsigned long)__brk_base;
@@ -302,7 +302,7 @@ static inline void init_gbpages(void)
 static void __init reserve_brk(void)
 {
        if (_brk_end > _brk_start)
-               reserve_early(__pa(_brk_start), __pa(_brk_end), "BRK");
+               memblock_x86_reserve_range(__pa(_brk_start), __pa(_brk_end), "BRK");
 
        /* Mark brk area as locked down and no longer taking any
           new allocations */
@@ -324,17 +324,16 @@ static void __init relocate_initrd(void)
        char *p, *q;
 
        /* We need to move the initrd down into lowmem */
-       ramdisk_here = find_e820_area(0, end_of_lowmem, area_size,
+       ramdisk_here = memblock_find_in_range(0, end_of_lowmem, area_size,
                                         PAGE_SIZE);
 
-       if (ramdisk_here == -1ULL)
+       if (ramdisk_here == MEMBLOCK_ERROR)
                panic("Cannot find place for new RAMDISK of size %lld\n",
                         ramdisk_size);
 
        /* Note: this includes all the lowmem currently occupied by
           the initrd, we rely on that fact to keep the data intact. */
-       reserve_early(ramdisk_here, ramdisk_here + area_size,
-                        "NEW RAMDISK");
+       memblock_x86_reserve_range(ramdisk_here, ramdisk_here + area_size, "NEW RAMDISK");
        initrd_start = ramdisk_here + PAGE_OFFSET;
        initrd_end   = initrd_start + ramdisk_size;
        printk(KERN_INFO "Allocated new RAMDISK: %08llx - %08llx\n",
@@ -390,7 +389,7 @@ static void __init reserve_initrd(void)
        initrd_start = 0;
 
        if (ramdisk_size >= (end_of_lowmem>>1)) {
-               free_early(ramdisk_image, ramdisk_end);
+               memblock_x86_free_range(ramdisk_image, ramdisk_end);
                printk(KERN_ERR "initrd too large to handle, "
                       "disabling initrd\n");
                return;
@@ -413,7 +412,7 @@ static void __init reserve_initrd(void)
 
        relocate_initrd();
 
-       free_early(ramdisk_image, ramdisk_end);
+       memblock_x86_free_range(ramdisk_image, ramdisk_end);
 }
 #else
 static void __init reserve_initrd(void)
@@ -469,7 +468,7 @@ static void __init e820_reserve_setup_data(void)
        e820_print_map("reserve setup_data");
 }
 
-static void __init reserve_early_setup_data(void)
+static void __init memblock_x86_reserve_range_setup_data(void)
 {
        struct setup_data *data;
        u64 pa_data;
@@ -481,7 +480,7 @@ static void __init reserve_early_setup_data(void)
        while (pa_data) {
                data = early_memremap(pa_data, sizeof(*data));
                sprintf(buf, "setup data %x", data->type);
-               reserve_early(pa_data, pa_data+sizeof(*data)+data->len, buf);
+               memblock_x86_reserve_range(pa_data, pa_data+sizeof(*data)+data->len, buf);
                pa_data = data->next;
                early_iounmap(data, sizeof(*data));
        }
@@ -502,6 +501,7 @@ static inline unsigned long long get_total_mem(void)
        return total << PAGE_SHIFT;
 }
 
+#define DEFAULT_BZIMAGE_ADDR_MAX 0x37FFFFFF
 static void __init reserve_crashkernel(void)
 {
        unsigned long long total_mem;
@@ -519,23 +519,27 @@ static void __init reserve_crashkernel(void)
        if (crash_base <= 0) {
                const unsigned long long alignment = 16<<20;    /* 16M */
 
-               crash_base = find_e820_area(alignment, ULONG_MAX, crash_size,
-                                alignment);
-               if (crash_base == -1ULL) {
+               /*
+                *  kexec want bzImage is below DEFAULT_BZIMAGE_ADDR_MAX
+                */
+               crash_base = memblock_find_in_range(alignment,
+                              DEFAULT_BZIMAGE_ADDR_MAX, crash_size, alignment);
+
+               if (crash_base == MEMBLOCK_ERROR) {
                        pr_info("crashkernel reservation failed - No suitable area found.\n");
                        return;
                }
        } else {
                unsigned long long start;
 
-               start = find_e820_area(crash_base, ULONG_MAX, crash_size,
-                                1<<20);
+               start = memblock_find_in_range(crash_base,
+                                crash_base + crash_size, crash_size, 1<<20);
                if (start != crash_base) {
                        pr_info("crashkernel reservation failed - memory is in use.\n");
                        return;
                }
        }
-       reserve_early(crash_base, crash_base + crash_size, "CRASH KERNEL");
+       memblock_x86_reserve_range(crash_base, crash_base + crash_size, "CRASH KERNEL");
 
        printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
                        "for crashkernel (System RAM: %ldMB)\n",
@@ -615,82 +619,10 @@ static __init void reserve_ibft_region(void)
        addr = find_ibft_region(&size);
 
        if (size)
-               reserve_early_overlap_ok(addr, addr + size, "ibft");
-}
-
-#ifdef CONFIG_X86_RESERVE_LOW_64K
-static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
-{
-       printk(KERN_NOTICE
-               "%s detected: BIOS may corrupt low RAM, working around it.\n",
-               d->ident);
-
-       e820_update_range(0, 0x10000, E820_RAM, E820_RESERVED);
-       sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
-
-       return 0;
+               memblock_x86_reserve_range(addr, addr + size, "* ibft");
 }
-#endif
 
-/* List of systems that have known low memory corruption BIOS problems */
-static struct dmi_system_id __initdata bad_bios_dmi_table[] = {
-#ifdef CONFIG_X86_RESERVE_LOW_64K
-       {
-               .callback = dmi_low_memory_corruption,
-               .ident = "AMI BIOS",
-               .matches = {
-                       DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
-               },
-       },
-       {
-               .callback = dmi_low_memory_corruption,
-               .ident = "Phoenix BIOS",
-               .matches = {
-                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies"),
-               },
-       },
-       {
-               .callback = dmi_low_memory_corruption,
-               .ident = "Phoenix/MSC BIOS",
-               .matches = {
-                       DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix/MSC"),
-               },
-       },
-       /*
-        * AMI BIOS with low memory corruption was found on Intel DG45ID and
-        * DG45FC boards.
-        * It has a different DMI_BIOS_VENDOR = "Intel Corp.", for now we will
-        * match only DMI_BOARD_NAME and see if there is more bad products
-        * with this vendor.
-        */
-       {
-               .callback = dmi_low_memory_corruption,
-               .ident = "AMI BIOS",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_NAME, "DG45ID"),
-               },
-       },
-       {
-               .callback = dmi_low_memory_corruption,
-               .ident = "AMI BIOS",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_NAME, "DG45FC"),
-               },
-       },
-       /*
-        * The Dell Inspiron Mini 1012 has DMI_BIOS_VENDOR = "Dell Inc.", so
-        * match on the product name.
-        */
-       {
-               .callback = dmi_low_memory_corruption,
-               .ident = "Phoenix BIOS",
-               .matches = {
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"),
-               },
-       },
-#endif
-       {}
-};
+static unsigned reserve_low = CONFIG_X86_RESERVE_LOW << 10;
 
 static void __init trim_bios_range(void)
 {
@@ -698,8 +630,14 @@ static void __init trim_bios_range(void)
         * A special case is the first 4Kb of memory;
         * This is a BIOS owned area, not kernel ram, but generally
         * not listed as such in the E820 table.
+        *
+        * This typically reserves additional memory (64KiB by default)
+        * since some BIOSes are known to corrupt low memory.  See the
+        * Kconfig help text for X86_RESERVE_LOW.
         */
-       e820_update_range(0, PAGE_SIZE, E820_RAM, E820_RESERVED);
+       e820_update_range(0, ALIGN(reserve_low, PAGE_SIZE),
+                         E820_RAM, E820_RESERVED);
+
        /*
         * special case: Some BIOSen report the PC BIOS
         * area (640->1Mb) as ram even though it is not.
@@ -709,6 +647,37 @@ static void __init trim_bios_range(void)
        sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
 }
 
+static int __init parse_reservelow(char *p)
+{
+       unsigned long long size;
+
+       if (!p)
+               return -EINVAL;
+
+       size = memparse(p, &p);
+
+       if (size < 4096)
+               size = 4096;
+
+       if (size > 640*1024)
+               size = 640*1024;
+
+       reserve_low = size;
+
+       return 0;
+}
+
+early_param("reservelow", parse_reservelow);
+
+static u64 __init get_max_mapped(void)
+{
+       u64 end = max_pfn_mapped;
+
+       end <<= PAGE_SHIFT;
+
+       return end;
+}
+
 /*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
@@ -726,6 +695,7 @@ void __init setup_arch(char **cmdline_p)
 {
        int acpi = 0;
        int k8 = 0;
+       unsigned long flags;
 
 #ifdef CONFIG_X86_32
        memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
@@ -734,10 +704,10 @@ void __init setup_arch(char **cmdline_p)
        printk(KERN_INFO "Command line: %s\n", boot_command_line);
 #endif
 
-       /* VMI may relocate the fixmap; do this before touching ioremap area */
-       vmi_init();
-
-       /* OFW also may relocate the fixmap */
+       /*
+        * If we have OLPC OFW, we might end up relocating the fixmap due to
+        * reserve_top(), so do this before touching the ioremap area.
+        */
        olpc_ofw_detect();
 
        early_trap_init();
@@ -782,7 +752,7 @@ void __init setup_arch(char **cmdline_p)
 #endif
         4)) {
                efi_enabled = 1;
-               efi_reserve_early();
+               efi_memblock_x86_reserve_range();
        }
 #endif
 
@@ -838,11 +808,8 @@ void __init setup_arch(char **cmdline_p)
 
        x86_report_nx();
 
-       /* Must be before kernel pagetables are setup */
-       vmi_activate();
-
        /* after early param, so could get panic from serial */
-       reserve_early_setup_data();
+       memblock_x86_reserve_range_setup_data();
 
        if (acpi_mps_check()) {
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -863,8 +830,6 @@ void __init setup_arch(char **cmdline_p)
 
        dmi_scan_machine();
 
-       dmi_check_system(bad_bios_dmi_table);
-
        /*
         * VMware detection requires dmi to be available, so this
         * needs to be done after dmi_scan_machine, for the BP.
@@ -897,8 +862,6 @@ void __init setup_arch(char **cmdline_p)
         */
        max_pfn = e820_end_of_ram_pfn();
 
-       /* preallocate 4k for mptable mpc */
-       early_reserve_e820_mpc_new();
        /* update e820 for memory not covered by WB MTRRs */
        mtrr_bp_init();
        if (mtrr_trim_uncached_memory(max_pfn))
@@ -920,18 +883,8 @@ void __init setup_arch(char **cmdline_p)
                max_low_pfn = max_pfn;
 
        high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
-       max_pfn_mapped = KERNEL_IMAGE_SIZE >> PAGE_SHIFT;
 #endif
 
-#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
-       setup_bios_corruption_check();
-#endif
-
-       printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n",
-                       max_pfn_mapped<<PAGE_SHIFT);
-
-       reserve_brk();
-
        /*
         * Find and reserve possible boot-time SMP configuration:
         */
@@ -939,6 +892,26 @@ void __init setup_arch(char **cmdline_p)
 
        reserve_ibft_region();
 
+       /*
+        * Need to conclude brk, before memblock_x86_fill()
+        *  it could use memblock_find_in_range, could overlap with
+        *  brk area.
+        */
+       reserve_brk();
+
+       memblock.current_limit = get_max_mapped();
+       memblock_x86_fill();
+
+       /* preallocate 4k for mptable mpc */
+       early_reserve_e820_mpc_new();
+
+#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
+       setup_bios_corruption_check();
+#endif
+
+       printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n",
+                       max_pfn_mapped<<PAGE_SHIFT);
+
        reserve_trampoline_memory();
 
 #ifdef CONFIG_ACPI_SLEEP
@@ -962,6 +935,7 @@ void __init setup_arch(char **cmdline_p)
                max_low_pfn = max_pfn;
        }
 #endif
+       memblock.current_limit = get_max_mapped();
 
        /*
         * NOTE: On x86-32, only from this point on, fixmaps are ready for use.
@@ -1000,10 +974,7 @@ void __init setup_arch(char **cmdline_p)
 #endif
 
        initmem_init(0, max_pfn, acpi, k8);
-#ifndef CONFIG_NO_BOOTMEM
-       early_res_to_bootmem(0, max_low_pfn<<PAGE_SHIFT);
-#endif
-
+       memblock_find_dma_reserve();
        dma32_reserve_bootmem();
 
 #ifdef CONFIG_KVM_CLOCK
@@ -1071,6 +1042,10 @@ void __init setup_arch(char **cmdline_p)
        x86_init.oem.banner();
 
        mcheck_init();
+
+       local_irq_save(flags);
+       arch_init_ideal_nop5();
+       local_irq_restore(flags);
 }
 
 #ifdef CONFIG_X86_32
index a60df9ae645440789181acd318e12bd4c450aeff..002b79685f738014a8cf9127f804851459a6216b 100644 (file)
@@ -131,13 +131,7 @@ static void * __init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
 
 static void __init pcpu_fc_free(void *ptr, size_t size)
 {
-#ifdef CONFIG_NO_BOOTMEM
-       u64 start = __pa(ptr);
-       u64 end = start + size;
-       free_early_partial(start, end);
-#else
        free_bootmem(__pa(ptr), size);
-#endif
 }
 
 static int __init pcpu_cpu_distance(unsigned int from, unsigned int to)
@@ -253,7 +247,7 @@ void __init setup_per_cpu_areas(void)
                 * Up to this point, the boot CPU has been using .init.data
                 * area.  Reload any changed state for the boot CPU.
                 */
-               if (cpu == boot_cpu_id)
+               if (!cpu)
                        switch_to_new_gdt(cpu);
        }
 
index cb22acf3ed099de3a256f2f482ae1cdcd5338320..dd4c281ffe5720c3ff15f1eceaa09759e17df7d1 100644 (file)
@@ -34,7 +34,7 @@
 #ifdef CONFIG_X86_LOCAL_APIC
 static unsigned long sfi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
 
-void __init mp_sfi_register_lapic_address(unsigned long address)
+static void __init mp_sfi_register_lapic_address(unsigned long address)
 {
        mp_lapic_addr = address;
 
@@ -46,7 +46,7 @@ void __init mp_sfi_register_lapic_address(unsigned long address)
 }
 
 /* All CPUs enumerated by SFI must be present and enabled */
-void __cpuinit mp_sfi_register_lapic(u8 id)
+static void __cpuinit mp_sfi_register_lapic(u8 id)
 {
        if (MAX_APICS - id <= 0) {
                pr_warning("Processor #%d invalid (max %d)\n",
index 8b3bfc4dd70872680ff4b451a8b03903bd68727b..dfb50890b5b78b59f3843e6087ebc0a7540cc578 100644 (file)
@@ -62,7 +62,7 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/mtrr.h>
-#include <asm/vmi.h>
+#include <asm/mwait.h>
 #include <asm/apic.h>
 #include <asm/setup.h>
 #include <asm/uv/uv.h>
@@ -311,7 +311,6 @@ notrace static void __cpuinit start_secondary(void *unused)
        __flush_tlb_all();
 #endif
 
-       vmi_bringup();
        cpu_init();
        preempt_disable();
        smp_callin();
@@ -324,9 +323,9 @@ notrace static void __cpuinit start_secondary(void *unused)
        check_tsc_sync_target();
 
        if (nmi_watchdog == NMI_IO_APIC) {
-               legacy_pic->chip->mask(0);
+               legacy_pic->mask(0);
                enable_NMI_through_LVT0();
-               legacy_pic->chip->unmask(0);
+               legacy_pic->unmask(0);
        }
 
        /* This must be done before setting cpu_online_mask */
@@ -397,6 +396,19 @@ void __cpuinit smp_store_cpu_info(int id)
                identify_secondary_cpu(c);
 }
 
+static void __cpuinit link_thread_siblings(int cpu1, int cpu2)
+{
+       struct cpuinfo_x86 *c1 = &cpu_data(cpu1);
+       struct cpuinfo_x86 *c2 = &cpu_data(cpu2);
+
+       cpumask_set_cpu(cpu1, cpu_sibling_mask(cpu2));
+       cpumask_set_cpu(cpu2, cpu_sibling_mask(cpu1));
+       cpumask_set_cpu(cpu1, cpu_core_mask(cpu2));
+       cpumask_set_cpu(cpu2, cpu_core_mask(cpu1));
+       cpumask_set_cpu(cpu1, c2->llc_shared_map);
+       cpumask_set_cpu(cpu2, c1->llc_shared_map);
+}
+
 
 void __cpuinit set_cpu_sibling_map(int cpu)
 {
@@ -409,14 +421,13 @@ void __cpuinit set_cpu_sibling_map(int cpu)
                for_each_cpu(i, cpu_sibling_setup_mask) {
                        struct cpuinfo_x86 *o = &cpu_data(i);
 
-                       if (c->phys_proc_id == o->phys_proc_id &&
-                           c->cpu_core_id == o->cpu_core_id) {
-                               cpumask_set_cpu(i, cpu_sibling_mask(cpu));
-                               cpumask_set_cpu(cpu, cpu_sibling_mask(i));
-                               cpumask_set_cpu(i, cpu_core_mask(cpu));
-                               cpumask_set_cpu(cpu, cpu_core_mask(i));
-                               cpumask_set_cpu(i, c->llc_shared_map);
-                               cpumask_set_cpu(cpu, o->llc_shared_map);
+                       if (cpu_has(c, X86_FEATURE_TOPOEXT)) {
+                               if (c->phys_proc_id == o->phys_proc_id &&
+                                   c->compute_unit_id == o->compute_unit_id)
+                                       link_thread_siblings(cpu, i);
+                       } else if (c->phys_proc_id == o->phys_proc_id &&
+                                  c->cpu_core_id == o->cpu_core_id) {
+                               link_thread_siblings(cpu, i);
                        }
                }
        } else {
@@ -1109,8 +1120,6 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
        }
        set_cpu_sibling_map(0);
 
-       enable_IR_x2apic();
-       default_setup_apic_routing();
 
        if (smp_sanity_check(max_cpus) < 0) {
                printk(KERN_INFO "SMP disabled\n");
@@ -1118,6 +1127,8 @@ void __init native_smp_prepare_cpus(unsigned int max_cpus)
                goto out;
        }
 
+       default_setup_apic_routing();
+
        preempt_disable();
        if (read_apic_id() != boot_cpu_physical_apicid) {
                panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
@@ -1383,11 +1394,88 @@ void play_dead_common(void)
        local_irq_disable();
 }
 
+/*
+ * We need to flush the caches before going to sleep, lest we have
+ * dirty data in our caches when we come back up.
+ */
+static inline void mwait_play_dead(void)
+{
+       unsigned int eax, ebx, ecx, edx;
+       unsigned int highest_cstate = 0;
+       unsigned int highest_subcstate = 0;
+       int i;
+       void *mwait_ptr;
+
+       if (!cpu_has(&current_cpu_data, X86_FEATURE_MWAIT))
+               return;
+       if (!cpu_has(&current_cpu_data, X86_FEATURE_CLFLSH))
+               return;
+       if (current_cpu_data.cpuid_level < CPUID_MWAIT_LEAF)
+               return;
+
+       eax = CPUID_MWAIT_LEAF;
+       ecx = 0;
+       native_cpuid(&eax, &ebx, &ecx, &edx);
+
+       /*
+        * eax will be 0 if EDX enumeration is not valid.
+        * Initialized below to cstate, sub_cstate value when EDX is valid.
+        */
+       if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED)) {
+               eax = 0;
+       } else {
+               edx >>= MWAIT_SUBSTATE_SIZE;
+               for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) {
+                       if (edx & MWAIT_SUBSTATE_MASK) {
+                               highest_cstate = i;
+                               highest_subcstate = edx & MWAIT_SUBSTATE_MASK;
+                       }
+               }
+               eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
+                       (highest_subcstate - 1);
+       }
+
+       /*
+        * This should be a memory location in a cache line which is
+        * unlikely to be touched by other processors.  The actual
+        * content is immaterial as it is not actually modified in any way.
+        */
+       mwait_ptr = &current_thread_info()->flags;
+
+       wbinvd();
+
+       while (1) {
+               /*
+                * The CLFLUSH is a workaround for erratum AAI65 for
+                * the Xeon 7400 series.  It's not clear it is actually
+                * needed, but it should be harmless in either case.
+                * The WBINVD is insufficient due to the spurious-wakeup
+                * case where we return around the loop.
+                */
+               clflush(mwait_ptr);
+               __monitor(mwait_ptr, 0, 0);
+               mb();
+               __mwait(eax, 0);
+       }
+}
+
+static inline void hlt_play_dead(void)
+{
+       if (current_cpu_data.x86 >= 4)
+               wbinvd();
+
+       while (1) {
+               native_halt();
+       }
+}
+
 void native_play_dead(void)
 {
        play_dead_common();
        tboot_shutdown(TB_SHUTDOWN_WFS);
-       wbinvd_halt();
+
+       mwait_play_dead();      /* Only returns on failure */
+       hlt_play_dead();
 }
 
 #else /* ... !CONFIG_HOTPLUG_CPU */
index d5e06624e34a556552585690b4532509fe21552f..0b0cb5fede1993d8dc45b54ffcf27ff8732c3082 100644 (file)
@@ -33,8 +33,8 @@ int kernel_execve(const char *filename,
                  const char *const envp[])
 {
        long __res;
-       asm volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx"
+       asm volatile ("int $0x80"
        : "=a" (__res)
-       : "0" (__NR_execve), "ri" (filename), "c" (argv), "d" (envp) : "memory");
+       : "0" (__NR_execve), "b" (filename), "c" (argv), "d" (envp) : "memory");
        return __res;
 }
index e2a5952573905b2eeac3d18060be54532dbfdfde..4c3da5674e677a14f67990959b1060381bad66f3 100644 (file)
@@ -1,8 +1,8 @@
 #include <linux/io.h>
+#include <linux/memblock.h>
 
 #include <asm/trampoline.h>
 #include <asm/pgtable.h>
-#include <asm/e820.h>
 
 #if defined(CONFIG_X86_64) && defined(CONFIG_ACPI_SLEEP)
 #define __trampinit
@@ -17,15 +17,15 @@ unsigned char *__trampinitdata trampoline_base;
 
 void __init reserve_trampoline_memory(void)
 {
-       unsigned long mem;
+       phys_addr_t mem;
 
        /* Has to be in very low memory so we can execute real-mode AP code. */
-       mem = find_e820_area(0, 1<<20, TRAMPOLINE_SIZE, PAGE_SIZE);
-       if (mem == -1L)
+       mem = memblock_find_in_range(0, 1<<20, TRAMPOLINE_SIZE, PAGE_SIZE);
+       if (mem == MEMBLOCK_ERROR)
                panic("Cannot allocate trampoline\n");
 
        trampoline_base = __va(mem);
-       reserve_early(mem, mem + TRAMPOLINE_SIZE, "TRAMPOLINE");
+       memblock_x86_reserve_range(mem, mem + TRAMPOLINE_SIZE, "TRAMPOLINE");
 }
 
 /*
index 60788dee0f8a74f53d547c462d5694201b6d609d..d43968503dd22fc67a35570fcf0b92b337637c09 100644 (file)
@@ -776,21 +776,10 @@ asmlinkage void math_state_restore(void)
 }
 EXPORT_SYMBOL_GPL(math_state_restore);
 
-#ifndef CONFIG_MATH_EMULATION
-void math_emulate(struct math_emu_info *info)
-{
-       printk(KERN_EMERG
-               "math-emulation not enabled and no coprocessor found.\n");
-       printk(KERN_EMERG "killing %s.\n", current->comm);
-       force_sig(SIGFPE, current);
-       schedule();
-}
-#endif /* CONFIG_MATH_EMULATION */
-
 dotraplinkage void __kprobes
 do_device_not_available(struct pt_regs *regs, long error_code)
 {
-#ifdef CONFIG_X86_32
+#ifdef CONFIG_MATH_EMULATION
        if (read_cr0() & X86_CR0_EM) {
                struct math_emu_info info = { };
 
@@ -798,12 +787,12 @@ do_device_not_available(struct pt_regs *regs, long error_code)
 
                info.regs = regs;
                math_emulate(&info);
-       } else {
-               math_state_restore(); /* interrupts still off */
-               conditional_sti(regs);
+               return;
        }
-#else
-       math_state_restore();
+#endif
+       math_state_restore(); /* interrupts still off */
+#ifdef CONFIG_X86_32
+       conditional_sti(regs);
 #endif
 }
 
@@ -881,18 +870,6 @@ void __init trap_init(void)
 #endif
 
 #ifdef CONFIG_X86_32
-       if (cpu_has_fxsr) {
-               printk(KERN_INFO "Enabling fast FPU save and restore... ");
-               set_in_cr4(X86_CR4_OSFXSR);
-               printk("done.\n");
-       }
-       if (cpu_has_xmm) {
-               printk(KERN_INFO
-                       "Enabling unmasked SIMD FPU exception support... ");
-               set_in_cr4(X86_CR4_OSXMMEXCPT);
-               printk("done.\n");
-       }
-
        set_system_trap_gate(SYSCALL_VECTOR, &system_call);
        set_bit(SYSCALL_VECTOR, used_vectors);
 #endif
index 26a863a9c2a815ec797b6211cd3de5e0b9cbed8e..0c40d8b72416ba2ef7e86bfd812b7bf6f1db2f8f 100644 (file)
@@ -104,10 +104,14 @@ int __init notsc_setup(char *str)
 
 __setup("notsc", notsc_setup);
 
+static int no_sched_irq_time;
+
 static int __init tsc_setup(char *str)
 {
        if (!strcmp(str, "reliable"))
                tsc_clocksource_reliable = 1;
+       if (!strncmp(str, "noirqtime", 9))
+               no_sched_irq_time = 1;
        return 1;
 }
 
@@ -801,6 +805,7 @@ void mark_tsc_unstable(char *reason)
        if (!tsc_unstable) {
                tsc_unstable = 1;
                sched_clock_stable = 0;
+               disable_sched_clock_irqtime();
                printk(KERN_INFO "Marking TSC unstable due to %s\n", reason);
                /* Change only the rating, when not registered */
                if (clocksource_tsc.mult)
@@ -892,60 +897,6 @@ static void __init init_tsc_clocksource(void)
        clocksource_register_khz(&clocksource_tsc, tsc_khz);
 }
 
-#ifdef CONFIG_X86_64
-/*
- * calibrate_cpu is used on systems with fixed rate TSCs to determine
- * processor frequency
- */
-#define TICK_COUNT 100000000
-static unsigned long __init calibrate_cpu(void)
-{
-       int tsc_start, tsc_now;
-       int i, no_ctr_free;
-       unsigned long evntsel3 = 0, pmc3 = 0, pmc_now = 0;
-       unsigned long flags;
-
-       for (i = 0; i < 4; i++)
-               if (avail_to_resrv_perfctr_nmi_bit(i))
-                       break;
-       no_ctr_free = (i == 4);
-       if (no_ctr_free) {
-               WARN(1, KERN_WARNING "Warning: AMD perfctrs busy ... "
-                    "cpu_khz value may be incorrect.\n");
-               i = 3;
-               rdmsrl(MSR_K7_EVNTSEL3, evntsel3);
-               wrmsrl(MSR_K7_EVNTSEL3, 0);
-               rdmsrl(MSR_K7_PERFCTR3, pmc3);
-       } else {
-               reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-               reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-       }
-       local_irq_save(flags);
-       /* start measuring cycles, incrementing from 0 */
-       wrmsrl(MSR_K7_PERFCTR0 + i, 0);
-       wrmsrl(MSR_K7_EVNTSEL0 + i, 1 << 22 | 3 << 16 | 0x76);
-       rdtscl(tsc_start);
-       do {
-               rdmsrl(MSR_K7_PERFCTR0 + i, pmc_now);
-               tsc_now = get_cycles();
-       } while ((tsc_now - tsc_start) < TICK_COUNT);
-
-       local_irq_restore(flags);
-       if (no_ctr_free) {
-               wrmsrl(MSR_K7_EVNTSEL3, 0);
-               wrmsrl(MSR_K7_PERFCTR3, pmc3);
-               wrmsrl(MSR_K7_EVNTSEL3, evntsel3);
-       } else {
-               release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
-               release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
-       }
-
-       return pmc_now * tsc_khz / (tsc_now - tsc_start);
-}
-#else
-static inline unsigned long calibrate_cpu(void) { return cpu_khz; }
-#endif
-
 void __init tsc_init(void)
 {
        u64 lpj;
@@ -964,10 +915,6 @@ void __init tsc_init(void)
                return;
        }
 
-       if (cpu_has(&boot_cpu_data, X86_FEATURE_CONSTANT_TSC) &&
-                       (boot_cpu_data.x86_vendor == X86_VENDOR_AMD))
-               cpu_khz = calibrate_cpu();
-
        printk("Detected %lu.%03lu MHz processor.\n",
                        (unsigned long)cpu_khz / 1000,
                        (unsigned long)cpu_khz % 1000);
@@ -987,6 +934,9 @@ void __init tsc_init(void)
        /* now allow native_sched_clock() to use rdtsc */
        tsc_disabled = 0;
 
+       if (!no_sched_irq_time)
+               enable_sched_clock_irqtime();
+
        lpj = ((u64)tsc_khz * 1000);
        do_div(lpj, HZ);
        lpj_fine = lpj;
index 1132129db792b704fe14f4adaf02fda8ffafaa24..7b24460917d551b540a337a0f7c74dbe4f65e297 100644 (file)
@@ -28,34 +28,21 @@ struct uv_irq_2_mmr_pnode{
 static spinlock_t              uv_irq_lock;
 static struct rb_root          uv_irq_root;
 
-static int uv_set_irq_affinity(unsigned int, const struct cpumask *);
+static int uv_set_irq_affinity(struct irq_data *, const struct cpumask *, bool);
 
-static void uv_noop(unsigned int irq)
-{
-}
-
-static unsigned int uv_noop_ret(unsigned int irq)
-{
-       return 0;
-}
+static void uv_noop(struct irq_data *data) { }
 
-static void uv_ack_apic(unsigned int irq)
+static void uv_ack_apic(struct irq_data *data)
 {
        ack_APIC_irq();
 }
 
 static struct irq_chip uv_irq_chip = {
-       .name           = "UV-CORE",
-       .startup        = uv_noop_ret,
-       .shutdown       = uv_noop,
-       .enable         = uv_noop,
-       .disable        = uv_noop,
-       .ack            = uv_noop,
-       .mask           = uv_noop,
-       .unmask         = uv_noop,
-       .eoi            = uv_ack_apic,
-       .end            = uv_noop,
-       .set_affinity   = uv_set_irq_affinity,
+       .name                   = "UV-CORE",
+       .irq_mask               = uv_noop,
+       .irq_unmask             = uv_noop,
+       .irq_eoi                = uv_ack_apic,
+       .irq_set_affinity       = uv_set_irq_affinity,
 };
 
 /*
@@ -144,26 +131,22 @@ arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
                       unsigned long mmr_offset, int limit)
 {
        const struct cpumask *eligible_cpu = cpumask_of(cpu);
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_cfg *cfg;
-       int mmr_pnode;
+       struct irq_cfg *cfg = get_irq_chip_data(irq);
        unsigned long mmr_value;
        struct uv_IO_APIC_route_entry *entry;
-       int err;
+       int mmr_pnode, err;
 
        BUILD_BUG_ON(sizeof(struct uv_IO_APIC_route_entry) !=
                        sizeof(unsigned long));
 
-       cfg = irq_cfg(irq);
-
        err = assign_irq_vector(irq, cfg, eligible_cpu);
        if (err != 0)
                return err;
 
        if (limit == UV_AFFINITY_CPU)
-               desc->status |= IRQ_NO_BALANCING;
+               irq_set_status_flags(irq, IRQ_NO_BALANCING);
        else
-               desc->status |= IRQ_MOVE_PCNTXT;
+               irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
 
        set_irq_chip_and_handler_name(irq, &uv_irq_chip, handle_percpu_irq,
                                      irq_name);
@@ -206,17 +189,17 @@ static void arch_disable_uv_irq(int mmr_pnode, unsigned long mmr_offset)
        uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
 }
 
-static int uv_set_irq_affinity(unsigned int irq, const struct cpumask *mask)
+static int
+uv_set_irq_affinity(struct irq_data *data, const struct cpumask *mask,
+                   bool force)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       struct irq_cfg *cfg = desc->chip_data;
+       struct irq_cfg *cfg = data->chip_data;
        unsigned int dest;
-       unsigned long mmr_value;
+       unsigned long mmr_value, mmr_offset;
        struct uv_IO_APIC_route_entry *entry;
-       unsigned long mmr_offset;
        int mmr_pnode;
 
-       if (set_desc_affinity(desc, mask, &dest))
+       if (__ioapic_set_affinity(data, mask, &dest))
                return -1;
 
        mmr_value = 0;
@@ -231,7 +214,7 @@ static int uv_set_irq_affinity(unsigned int irq, const struct cpumask *mask)
        entry->dest             = dest;
 
        /* Get previously stored MMR and pnode of hub sourcing interrupts */
-       if (uv_irq_2_mmr_info(irq, &mmr_offset, &mmr_pnode))
+       if (uv_irq_2_mmr_info(data->irq, &mmr_offset, &mmr_pnode))
                return -1;
 
        uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
index e680ea52db9b372fdd83b4954dd1774ad733f66c..3371bd053b89f29e14e5f55d88929d2427f123b2 100644 (file)
@@ -66,10 +66,7 @@ static void __init visws_time_init(void)
 }
 
 /* Replaces the default init_ISA_irqs in the generic setup */
-static void __init visws_pre_intr_init(void)
-{
-       init_VISWS_APIC_irqs();
-}
+static void __init visws_pre_intr_init(void);
 
 /* Quirk for machine specific memory setup. */
 
@@ -429,67 +426,34 @@ static int is_co_apic(unsigned int irq)
 /*
  * This is the SGI Cobalt (IO-)APIC:
  */
-
-static void enable_cobalt_irq(unsigned int irq)
+static void enable_cobalt_irq(struct irq_data *data)
 {
-       co_apic_set(is_co_apic(irq), irq);
+       co_apic_set(is_co_apic(data->irq), data->irq);
 }
 
-static void disable_cobalt_irq(unsigned int irq)
+static void disable_cobalt_irq(struct irq_data *data)
 {
-       int entry = is_co_apic(irq);
+       int entry = is_co_apic(data->irq);
 
        co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK);
        co_apic_read(CO_APIC_LO(entry));
 }
 
-/*
- * "irq" really just serves to identify the device.  Here is where we
- * map this to the Cobalt APIC entry where it's physically wired.
- * This is called via request_irq -> setup_irq -> irq_desc->startup()
- */
-static unsigned int startup_cobalt_irq(unsigned int irq)
+static void ack_cobalt_irq(struct irq_data *data)
 {
        unsigned long flags;
-       struct irq_desc *desc = irq_to_desc(irq);
 
        spin_lock_irqsave(&cobalt_lock, flags);
-       if ((desc->status & (IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING)))
-               desc->status &= ~(IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING);
-       enable_cobalt_irq(irq);
-       spin_unlock_irqrestore(&cobalt_lock, flags);
-       return 0;
-}
-
-static void ack_cobalt_irq(unsigned int irq)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&cobalt_lock, flags);
-       disable_cobalt_irq(irq);
+       disable_cobalt_irq(data);
        apic_write(APIC_EOI, APIC_EIO_ACK);
        spin_unlock_irqrestore(&cobalt_lock, flags);
 }
 
-static void end_cobalt_irq(unsigned int irq)
-{
-       unsigned long flags;
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       spin_lock_irqsave(&cobalt_lock, flags);
-       if (!(desc->status & (IRQ_DISABLED | IRQ_INPROGRESS)))
-               enable_cobalt_irq(irq);
-       spin_unlock_irqrestore(&cobalt_lock, flags);
-}
-
 static struct irq_chip cobalt_irq_type = {
-       .name =         "Cobalt-APIC",
-       .startup =      startup_cobalt_irq,
-       .shutdown =     disable_cobalt_irq,
-       .enable =       enable_cobalt_irq,
-       .disable =      disable_cobalt_irq,
-       .ack =          ack_cobalt_irq,
-       .end =          end_cobalt_irq,
+       .name           = "Cobalt-APIC",
+       .irq_enable     = enable_cobalt_irq,
+       .irq_disable    = disable_cobalt_irq,
+       .irq_ack        = ack_cobalt_irq,
 };
 
 
@@ -503,35 +467,34 @@ static struct irq_chip cobalt_irq_type = {
  * interrupt controller type, and through a special virtual interrupt-
  * controller. Device drivers only see the virtual interrupt sources.
  */
-static unsigned int startup_piix4_master_irq(unsigned int irq)
+static unsigned int startup_piix4_master_irq(struct irq_data *data)
 {
        legacy_pic->init(0);
-
-       return startup_cobalt_irq(irq);
+       enable_cobalt_irq(data);
 }
 
-static void end_piix4_master_irq(unsigned int irq)
+static void end_piix4_master_irq(struct irq_data *data)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&cobalt_lock, flags);
-       enable_cobalt_irq(irq);
+       enable_cobalt_irq(data);
        spin_unlock_irqrestore(&cobalt_lock, flags);
 }
 
 static struct irq_chip piix4_master_irq_type = {
-       .name =         "PIIX4-master",
-       .startup =      startup_piix4_master_irq,
-       .ack =          ack_cobalt_irq,
-       .end =          end_piix4_master_irq,
+       .name           = "PIIX4-master",
+       .irq_startup    = startup_piix4_master_irq,
+       .irq_ack        = ack_cobalt_irq,
 };
 
+static void pii4_mask(struct irq_data *data) { }
 
 static struct irq_chip piix4_virtual_irq_type = {
-       .name =         "PIIX4-virtual",
+       .name           = "PIIX4-virtual",
+       .mask           = pii4_mask,
 };
 
-
 /*
  * PIIX4-8259 master/virtual functions to handle interrupt requests
  * from legacy devices: floppy, parallel, serial, rtc.
@@ -549,9 +512,8 @@ static struct irq_chip piix4_virtual_irq_type = {
  */
 static irqreturn_t piix4_master_intr(int irq, void *dev_id)
 {
-       int realirq;
-       struct irq_desc *desc;
        unsigned long flags;
+       int realirq;
 
        raw_spin_lock_irqsave(&i8259A_lock, flags);
 
@@ -592,18 +554,10 @@ static irqreturn_t piix4_master_intr(int irq, void *dev_id)
 
        raw_spin_unlock_irqrestore(&i8259A_lock, flags);
 
-       desc = irq_to_desc(realirq);
-
        /*
         * handle this 'virtual interrupt' as a Cobalt one now.
         */
-       kstat_incr_irqs_this_cpu(realirq, desc);
-
-       if (likely(desc->action != NULL))
-               handle_IRQ_event(realirq, desc->action);
-
-       if (!(desc->status & IRQ_DISABLED))
-               legacy_pic->chip->unmask(realirq);
+       generic_handle_irq(realirq);
 
        return IRQ_HANDLED;
 
@@ -624,41 +578,35 @@ static struct irqaction cascade_action = {
 
 static inline void set_piix4_virtual_irq_type(void)
 {
-       piix4_virtual_irq_type.shutdown = i8259A_chip.mask;
        piix4_virtual_irq_type.enable = i8259A_chip.unmask;
        piix4_virtual_irq_type.disable = i8259A_chip.mask;
+       piix4_virtual_irq_type.unmask = i8259A_chip.unmask;
 }
 
-void init_VISWS_APIC_irqs(void)
+static void __init visws_pre_intr_init(void)
 {
        int i;
 
-       for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) {
-               struct irq_desc *desc = irq_to_desc(i);
-
-               desc->status = IRQ_DISABLED;
-               desc->action = 0;
-               desc->depth = 1;
+       set_piix4_virtual_irq_type();
 
-               if (i == 0) {
-                       desc->chip = &cobalt_irq_type;
-               }
-               else if (i == CO_IRQ_IDE0) {
-                       desc->chip = &cobalt_irq_type;
-               }
-               else if (i == CO_IRQ_IDE1) {
-                       desc->chip = &cobalt_irq_type;
-               }
-               else if (i == CO_IRQ_8259) {
-                       desc->chip = &piix4_master_irq_type;
-               }
-               else if (i < CO_IRQ_APIC0) {
-                       set_piix4_virtual_irq_type();
-                       desc->chip = &piix4_virtual_irq_type;
-               }
-               else if (IS_CO_APIC(i)) {
-                       desc->chip = &cobalt_irq_type;
-               }
+       for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) {
+               struct irq_chip *chip = NULL;
+
+               if (i == 0)
+                       chip = &cobalt_irq_type;
+               else if (i == CO_IRQ_IDE0)
+                       chip = &cobalt_irq_type;
+               else if (i == CO_IRQ_IDE1)
+                       >chip = &cobalt_irq_type;
+               else if (i == CO_IRQ_8259)
+                       chip = &piix4_master_irq_type;
+               else if (i < CO_IRQ_APIC0)
+                       chip = &piix4_virtual_irq_type;
+               else if (IS_CO_APIC(i))
+                       chip = &cobalt_irq_type;
+
+               if (chip)
+                       set_irq_chip(i, chip);
        }
 
        setup_irq(CO_IRQ_8259, &master_action);
diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c
deleted file mode 100644 (file)
index ce9fbac..0000000
+++ /dev/null
@@ -1,893 +0,0 @@
-/*
- * VMI specific paravirt-ops implementation
- *
- * Copyright (C) 2005, VMware, 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, GOOD TITLE or
- * NON INFRINGEMENT.  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.
- *
- * Send feedback to zach@vmware.com
- *
- */
-
-#include <linux/module.h>
-#include <linux/cpu.h>
-#include <linux/bootmem.h>
-#include <linux/mm.h>
-#include <linux/highmem.h>
-#include <linux/sched.h>
-#include <linux/gfp.h>
-#include <asm/vmi.h>
-#include <asm/io.h>
-#include <asm/fixmap.h>
-#include <asm/apicdef.h>
-#include <asm/apic.h>
-#include <asm/pgalloc.h>
-#include <asm/processor.h>
-#include <asm/timer.h>
-#include <asm/vmi_time.h>
-#include <asm/kmap_types.h>
-#include <asm/setup.h>
-
-/* Convenient for calling VMI functions indirectly in the ROM */
-typedef u32 __attribute__((regparm(1))) (VROMFUNC)(void);
-typedef u64 __attribute__((regparm(2))) (VROMLONGFUNC)(int);
-
-#define call_vrom_func(rom,func) \
-   (((VROMFUNC *)(rom->func))())
-
-#define call_vrom_long_func(rom,func,arg) \
-   (((VROMLONGFUNC *)(rom->func)) (arg))
-
-static struct vrom_header *vmi_rom;
-static int disable_pge;
-static int disable_pse;
-static int disable_sep;
-static int disable_tsc;
-static int disable_mtrr;
-static int disable_noidle;
-static int disable_vmi_timer;
-
-/* Cached VMI operations */
-static struct {
-       void (*cpuid)(void /* non-c */);
-       void (*_set_ldt)(u32 selector);
-       void (*set_tr)(u32 selector);
-       void (*write_idt_entry)(struct desc_struct *, int, u32, u32);
-       void (*write_gdt_entry)(struct desc_struct *, int, u32, u32);
-       void (*write_ldt_entry)(struct desc_struct *, int, u32, u32);
-       void (*set_kernel_stack)(u32 selector, u32 sp0);
-       void (*allocate_page)(u32, u32, u32, u32, u32);
-       void (*release_page)(u32, u32);
-       void (*set_pte)(pte_t, pte_t *, unsigned);
-       void (*update_pte)(pte_t *, unsigned);
-       void (*set_linear_mapping)(int, void *, u32, u32);
-       void (*_flush_tlb)(int);
-       void (*set_initial_ap_state)(int, int);
-       void (*halt)(void);
-       void (*set_lazy_mode)(int mode);
-} vmi_ops;
-
-/* Cached VMI operations */
-struct vmi_timer_ops vmi_timer_ops;
-
-/*
- * VMI patching routines.
- */
-#define MNEM_CALL 0xe8
-#define MNEM_JMP  0xe9
-#define MNEM_RET  0xc3
-
-#define IRQ_PATCH_INT_MASK 0
-#define IRQ_PATCH_DISABLE  5
-
-static inline void patch_offset(void *insnbuf,
-                               unsigned long ip, unsigned long dest)
-{
-        *(unsigned long *)(insnbuf+1) = dest-ip-5;
-}
-
-static unsigned patch_internal(int call, unsigned len, void *insnbuf,
-                              unsigned long ip)
-{
-       u64 reloc;
-       struct vmi_relocation_info *const rel = (struct vmi_relocation_info *)&reloc;
-       reloc = call_vrom_long_func(vmi_rom, get_reloc, call);
-       switch(rel->type) {
-               case VMI_RELOCATION_CALL_REL:
-                       BUG_ON(len < 5);
-                       *(char *)insnbuf = MNEM_CALL;
-                       patch_offset(insnbuf, ip, (unsigned long)rel->eip);
-                       return 5;
-
-               case VMI_RELOCATION_JUMP_REL:
-                       BUG_ON(len < 5);
-                       *(char *)insnbuf = MNEM_JMP;
-                       patch_offset(insnbuf, ip, (unsigned long)rel->eip);
-                       return 5;
-
-               case VMI_RELOCATION_NOP:
-                       /* obliterate the whole thing */
-                       return 0;
-
-               case VMI_RELOCATION_NONE:
-                       /* leave native code in place */
-                       break;
-
-               default:
-                       BUG();
-       }
-       return len;
-}
-
-/*
- * Apply patch if appropriate, return length of new instruction
- * sequence.  The callee does nop padding for us.
- */
-static unsigned vmi_patch(u8 type, u16 clobbers, void *insns,
-                         unsigned long ip, unsigned len)
-{
-       switch (type) {
-               case PARAVIRT_PATCH(pv_irq_ops.irq_disable):
-                       return patch_internal(VMI_CALL_DisableInterrupts, len,
-                                             insns, ip);
-               case PARAVIRT_PATCH(pv_irq_ops.irq_enable):
-                       return patch_internal(VMI_CALL_EnableInterrupts, len,
-                                             insns, ip);
-               case PARAVIRT_PATCH(pv_irq_ops.restore_fl):
-                       return patch_internal(VMI_CALL_SetInterruptMask, len,
-                                             insns, ip);
-               case PARAVIRT_PATCH(pv_irq_ops.save_fl):
-                       return patch_internal(VMI_CALL_GetInterruptMask, len,
-                                             insns, ip);
-               case PARAVIRT_PATCH(pv_cpu_ops.iret):
-                       return patch_internal(VMI_CALL_IRET, len, insns, ip);
-               case PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit):
-                       return patch_internal(VMI_CALL_SYSEXIT, len, insns, ip);
-               default:
-                       break;
-       }
-       return len;
-}
-
-/* CPUID has non-C semantics, and paravirt-ops API doesn't match hardware ISA */
-static void vmi_cpuid(unsigned int *ax, unsigned int *bx,
-                               unsigned int *cx, unsigned int *dx)
-{
-       int override = 0;
-       if (*ax == 1)
-               override = 1;
-        asm volatile ("call *%6"
-                      : "=a" (*ax),
-                        "=b" (*bx),
-                        "=c" (*cx),
-                        "=d" (*dx)
-                      : "0" (*ax), "2" (*cx), "r" (vmi_ops.cpuid));
-       if (override) {
-               if (disable_pse)
-                       *dx &= ~X86_FEATURE_PSE;
-               if (disable_pge)
-                       *dx &= ~X86_FEATURE_PGE;
-               if (disable_sep)
-                       *dx &= ~X86_FEATURE_SEP;
-               if (disable_tsc)
-                       *dx &= ~X86_FEATURE_TSC;
-               if (disable_mtrr)
-                       *dx &= ~X86_FEATURE_MTRR;
-       }
-}
-
-static inline void vmi_maybe_load_tls(struct desc_struct *gdt, int nr, struct desc_struct *new)
-{
-       if (gdt[nr].a != new->a || gdt[nr].b != new->b)
-               write_gdt_entry(gdt, nr, new, 0);
-}
-
-static void vmi_load_tls(struct thread_struct *t, unsigned int cpu)
-{
-       struct desc_struct *gdt = get_cpu_gdt_table(cpu);
-       vmi_maybe_load_tls(gdt, GDT_ENTRY_TLS_MIN + 0, &t->tls_array[0]);
-       vmi_maybe_load_tls(gdt, GDT_ENTRY_TLS_MIN + 1, &t->tls_array[1]);
-       vmi_maybe_load_tls(gdt, GDT_ENTRY_TLS_MIN + 2, &t->tls_array[2]);
-}
-
-static void vmi_set_ldt(const void *addr, unsigned entries)
-{
-       unsigned cpu = smp_processor_id();
-       struct desc_struct desc;
-
-       pack_descriptor(&desc, (unsigned long)addr,
-                       entries * sizeof(struct desc_struct) - 1,
-                       DESC_LDT, 0);
-       write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_LDT, &desc, DESC_LDT);
-       vmi_ops._set_ldt(entries ? GDT_ENTRY_LDT*sizeof(struct desc_struct) : 0);
-}
-
-static void vmi_set_tr(void)
-{
-       vmi_ops.set_tr(GDT_ENTRY_TSS*sizeof(struct desc_struct));
-}
-
-static void vmi_write_idt_entry(gate_desc *dt, int entry, const gate_desc *g)
-{
-       u32 *idt_entry = (u32 *)g;
-       vmi_ops.write_idt_entry(dt, entry, idt_entry[0], idt_entry[1]);
-}
-
-static void vmi_write_gdt_entry(struct desc_struct *dt, int entry,
-                               const void *desc, int type)
-{
-       u32 *gdt_entry = (u32 *)desc;
-       vmi_ops.write_gdt_entry(dt, entry, gdt_entry[0], gdt_entry[1]);
-}
-
-static void vmi_write_ldt_entry(struct desc_struct *dt, int entry,
-                               const void *desc)
-{
-       u32 *ldt_entry = (u32 *)desc;
-       vmi_ops.write_ldt_entry(dt, entry, ldt_entry[0], ldt_entry[1]);
-}
-
-static void vmi_load_sp0(struct tss_struct *tss,
-                                  struct thread_struct *thread)
-{
-       tss->x86_tss.sp0 = thread->sp0;
-
-       /* This can only happen when SEP is enabled, no need to test "SEP"arately */
-       if (unlikely(tss->x86_tss.ss1 != thread->sysenter_cs)) {
-               tss->x86_tss.ss1 = thread->sysenter_cs;
-               wrmsr(MSR_IA32_SYSENTER_CS, thread->sysenter_cs, 0);
-       }
-       vmi_ops.set_kernel_stack(__KERNEL_DS, tss->x86_tss.sp0);
-}
-
-static void vmi_flush_tlb_user(void)
-{
-       vmi_ops._flush_tlb(VMI_FLUSH_TLB);
-}
-
-static void vmi_flush_tlb_kernel(void)
-{
-       vmi_ops._flush_tlb(VMI_FLUSH_TLB | VMI_FLUSH_GLOBAL);
-}
-
-/* Stub to do nothing at all; used for delays and unimplemented calls */
-static void vmi_nop(void)
-{
-}
-
-static void vmi_allocate_pte(struct mm_struct *mm, unsigned long pfn)
-{
-       vmi_ops.allocate_page(pfn, VMI_PAGE_L1, 0, 0, 0);
-}
-
-static void vmi_allocate_pmd(struct mm_struct *mm, unsigned long pfn)
-{
-       /*
-        * This call comes in very early, before mem_map is setup.
-        * It is called only for swapper_pg_dir, which already has
-        * data on it.
-        */
-       vmi_ops.allocate_page(pfn, VMI_PAGE_L2, 0, 0, 0);
-}
-
-static void vmi_allocate_pmd_clone(unsigned long pfn, unsigned long clonepfn, unsigned long start, unsigned long count)
-{
-       vmi_ops.allocate_page(pfn, VMI_PAGE_L2 | VMI_PAGE_CLONE, clonepfn, start, count);
-}
-
-static void vmi_release_pte(unsigned long pfn)
-{
-       vmi_ops.release_page(pfn, VMI_PAGE_L1);
-}
-
-static void vmi_release_pmd(unsigned long pfn)
-{
-       vmi_ops.release_page(pfn, VMI_PAGE_L2);
-}
-
-/*
- * We use the pgd_free hook for releasing the pgd page:
- */
-static void vmi_pgd_free(struct mm_struct *mm, pgd_t *pgd)
-{
-       unsigned long pfn = __pa(pgd) >> PAGE_SHIFT;
-
-       vmi_ops.release_page(pfn, VMI_PAGE_L2);
-}
-
-/*
- * Helper macros for MMU update flags.  We can defer updates until a flush
- * or page invalidation only if the update is to the current address space
- * (otherwise, there is no flush).  We must check against init_mm, since
- * this could be a kernel update, which usually passes init_mm, although
- * sometimes this check can be skipped if we know the particular function
- * is only called on user mode PTEs.  We could change the kernel to pass
- * current->active_mm here, but in particular, I was unsure if changing
- * mm/highmem.c to do this would still be correct on other architectures.
- */
-#define is_current_as(mm, mustbeuser) ((mm) == current->active_mm ||    \
-                                       (!mustbeuser && (mm) == &init_mm))
-#define vmi_flags_addr(mm, addr, level, user)                           \
-        ((level) | (is_current_as(mm, user) ?                           \
-                (VMI_PAGE_CURRENT_AS | ((addr) & VMI_PAGE_VA_MASK)) : 0))
-#define vmi_flags_addr_defer(mm, addr, level, user)                     \
-        ((level) | (is_current_as(mm, user) ?                           \
-                (VMI_PAGE_DEFER | VMI_PAGE_CURRENT_AS | ((addr) & VMI_PAGE_VA_MASK)) : 0))
-
-static void vmi_update_pte(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
-       vmi_ops.update_pte(ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
-}
-
-static void vmi_update_pte_defer(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
-       vmi_ops.update_pte(ptep, vmi_flags_addr_defer(mm, addr, VMI_PAGE_PT, 0));
-}
-
-static void vmi_set_pte(pte_t *ptep, pte_t pte)
-{
-       /* XXX because of set_pmd_pte, this can be called on PT or PD layers */
-       vmi_ops.set_pte(pte, ptep, VMI_PAGE_PT);
-}
-
-static void vmi_set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
-{
-       vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
-}
-
-static void vmi_set_pmd(pmd_t *pmdp, pmd_t pmdval)
-{
-#ifdef CONFIG_X86_PAE
-       const pte_t pte = { .pte = pmdval.pmd };
-#else
-       const pte_t pte = { pmdval.pud.pgd.pgd };
-#endif
-       vmi_ops.set_pte(pte, (pte_t *)pmdp, VMI_PAGE_PD);
-}
-
-#ifdef CONFIG_X86_PAE
-
-static void vmi_set_pte_atomic(pte_t *ptep, pte_t pteval)
-{
-       /*
-        * XXX This is called from set_pmd_pte, but at both PT
-        * and PD layers so the VMI_PAGE_PT flag is wrong.  But
-        * it is only called for large page mapping changes,
-        * the Xen backend, doesn't support large pages, and the
-        * ESX backend doesn't depend on the flag.
-        */
-       set_64bit((unsigned long long *)ptep,pte_val(pteval));
-       vmi_ops.update_pte(ptep, VMI_PAGE_PT);
-}
-
-static void vmi_set_pud(pud_t *pudp, pud_t pudval)
-{
-       /* Um, eww */
-       const pte_t pte = { .pte = pudval.pgd.pgd };
-       vmi_ops.set_pte(pte, (pte_t *)pudp, VMI_PAGE_PDP);
-}
-
-static void vmi_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
-{
-       const pte_t pte = { .pte = 0 };
-       vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0));
-}
-
-static void vmi_pmd_clear(pmd_t *pmd)
-{
-       const pte_t pte = { .pte = 0 };
-       vmi_ops.set_pte(pte, (pte_t *)pmd, VMI_PAGE_PD);
-}
-#endif
-
-#ifdef CONFIG_SMP
-static void __devinit
-vmi_startup_ipi_hook(int phys_apicid, unsigned long start_eip,
-                    unsigned long start_esp)
-{
-       struct vmi_ap_state ap;
-
-       /* Default everything to zero.  This is fine for most GPRs. */
-       memset(&ap, 0, sizeof(struct vmi_ap_state));
-
-       ap.gdtr_limit = GDT_SIZE - 1;
-       ap.gdtr_base = (unsigned long) get_cpu_gdt_table(phys_apicid);
-
-       ap.idtr_limit = IDT_ENTRIES * 8 - 1;
-       ap.idtr_base = (unsigned long) idt_table;
-
-       ap.ldtr = 0;
-
-       ap.cs = __KERNEL_CS;
-       ap.eip = (unsigned long) start_eip;
-       ap.ss = __KERNEL_DS;
-       ap.esp = (unsigned long) start_esp;
-
-       ap.ds = __USER_DS;
-       ap.es = __USER_DS;
-       ap.fs = __KERNEL_PERCPU;
-       ap.gs = __KERNEL_STACK_CANARY;
-
-       ap.eflags = 0;
-
-#ifdef CONFIG_X86_PAE
-       /* efer should match BSP efer. */
-       if (cpu_has_nx) {
-               unsigned l, h;
-               rdmsr(MSR_EFER, l, h);
-               ap.efer = (unsigned long long) h << 32 | l;
-       }
-#endif
-
-       ap.cr3 = __pa(swapper_pg_dir);
-       /* Protected mode, paging, AM, WP, NE, MP. */
-       ap.cr0 = 0x80050023;
-       ap.cr4 = mmu_cr4_features;
-       vmi_ops.set_initial_ap_state((u32)&ap, phys_apicid);
-}
-#endif
-
-static void vmi_start_context_switch(struct task_struct *prev)
-{
-       paravirt_start_context_switch(prev);
-       vmi_ops.set_lazy_mode(2);
-}
-
-static void vmi_end_context_switch(struct task_struct *next)
-{
-       vmi_ops.set_lazy_mode(0);
-       paravirt_end_context_switch(next);
-}
-
-static void vmi_enter_lazy_mmu(void)
-{
-       paravirt_enter_lazy_mmu();
-       vmi_ops.set_lazy_mode(1);
-}
-
-static void vmi_leave_lazy_mmu(void)
-{
-       vmi_ops.set_lazy_mode(0);
-       paravirt_leave_lazy_mmu();
-}
-
-static inline int __init check_vmi_rom(struct vrom_header *rom)
-{
-       struct pci_header *pci;
-       struct pnp_header *pnp;
-       const char *manufacturer = "UNKNOWN";
-       const char *product = "UNKNOWN";
-       const char *license = "unspecified";
-
-       if (rom->rom_signature != 0xaa55)
-               return 0;
-       if (rom->vrom_signature != VMI_SIGNATURE)
-               return 0;
-       if (rom->api_version_maj != VMI_API_REV_MAJOR ||
-           rom->api_version_min+1 < VMI_API_REV_MINOR+1) {
-               printk(KERN_WARNING "VMI: Found mismatched rom version %d.%d\n",
-                               rom->api_version_maj,
-                               rom->api_version_min);
-               return 0;
-       }
-
-       /*
-        * Relying on the VMI_SIGNATURE field is not 100% safe, so check
-        * the PCI header and device type to make sure this is really a
-        * VMI device.
-        */
-       if (!rom->pci_header_offs) {
-               printk(KERN_WARNING "VMI: ROM does not contain PCI header.\n");
-               return 0;
-       }
-
-       pci = (struct pci_header *)((char *)rom+rom->pci_header_offs);
-       if (pci->vendorID != PCI_VENDOR_ID_VMWARE ||
-           pci->deviceID != PCI_DEVICE_ID_VMWARE_VMI) {
-               /* Allow it to run... anyways, but warn */
-               printk(KERN_WARNING "VMI: ROM from unknown manufacturer\n");
-       }
-
-       if (rom->pnp_header_offs) {
-               pnp = (struct pnp_header *)((char *)rom+rom->pnp_header_offs);
-               if (pnp->manufacturer_offset)
-                       manufacturer = (const char *)rom+pnp->manufacturer_offset;
-               if (pnp->product_offset)
-                       product = (const char *)rom+pnp->product_offset;
-       }
-
-       if (rom->license_offs)
-               license = (char *)rom+rom->license_offs;
-
-       printk(KERN_INFO "VMI: Found %s %s, API version %d.%d, ROM version %d.%d\n",
-               manufacturer, product,
-               rom->api_version_maj, rom->api_version_min,
-               pci->rom_version_maj, pci->rom_version_min);
-
-       /* Don't allow BSD/MIT here for now because we don't want to end up
-          with any binary only shim layers */
-       if (strcmp(license, "GPL") && strcmp(license, "GPL v2")) {
-               printk(KERN_WARNING "VMI: Non GPL license `%s' found for ROM. Not used.\n",
-                       license);
-               return 0;
-       }
-
-       return 1;
-}
-
-/*
- * Probe for the VMI option ROM
- */
-static inline int __init probe_vmi_rom(void)
-{
-       unsigned long base;
-
-       /* VMI ROM is in option ROM area, check signature */
-       for (base = 0xC0000; base < 0xE0000; base += 2048) {
-               struct vrom_header *romstart;
-               romstart = (struct vrom_header *)isa_bus_to_virt(base);
-               if (check_vmi_rom(romstart)) {
-                       vmi_rom = romstart;
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-/*
- * VMI setup common to all processors
- */
-void vmi_bringup(void)
-{
-       /* We must establish the lowmem mapping for MMU ops to work */
-       if (vmi_ops.set_linear_mapping)
-               vmi_ops.set_linear_mapping(0, (void *)__PAGE_OFFSET, MAXMEM_PFN, 0);
-}
-
-/*
- * Return a pointer to a VMI function or NULL if unimplemented
- */
-static void *vmi_get_function(int vmicall)
-{
-       u64 reloc;
-       const struct vmi_relocation_info *rel = (struct vmi_relocation_info *)&reloc;
-       reloc = call_vrom_long_func(vmi_rom, get_reloc, vmicall);
-       BUG_ON(rel->type == VMI_RELOCATION_JUMP_REL);
-       if (rel->type == VMI_RELOCATION_CALL_REL)
-               return (void *)rel->eip;
-       else
-               return NULL;
-}
-
-/*
- * Helper macro for making the VMI paravirt-ops fill code readable.
- * For unimplemented operations, fall back to default, unless nop
- * is returned by the ROM.
- */
-#define para_fill(opname, vmicall)                             \
-do {                                                           \
-       reloc = call_vrom_long_func(vmi_rom, get_reloc,         \
-                                   VMI_CALL_##vmicall);        \
-       if (rel->type == VMI_RELOCATION_CALL_REL)               \
-               opname = (void *)rel->eip;                      \
-       else if (rel->type == VMI_RELOCATION_NOP)               \
-               opname = (void *)vmi_nop;                       \
-       else if (rel->type != VMI_RELOCATION_NONE)              \
-               printk(KERN_WARNING "VMI: Unknown relocation "  \
-                                   "type %d for " #vmicall"\n",\
-                                       rel->type);             \
-} while (0)
-
-/*
- * Helper macro for making the VMI paravirt-ops fill code readable.
- * For cached operations which do not match the VMI ROM ABI and must
- * go through a tranlation stub.  Ignore NOPs, since it is not clear
- * a NOP * VMI function corresponds to a NOP paravirt-op when the
- * functions are not in 1-1 correspondence.
- */
-#define para_wrap(opname, wrapper, cache, vmicall)             \
-do {                                                           \
-       reloc = call_vrom_long_func(vmi_rom, get_reloc,         \
-                                   VMI_CALL_##vmicall);        \
-       BUG_ON(rel->type == VMI_RELOCATION_JUMP_REL);           \
-       if (rel->type == VMI_RELOCATION_CALL_REL) {             \
-               opname = wrapper;                               \
-               vmi_ops.cache = (void *)rel->eip;               \
-       }                                                       \
-} while (0)
-
-/*
- * Activate the VMI interface and switch into paravirtualized mode
- */
-static inline int __init activate_vmi(void)
-{
-       short kernel_cs;
-       u64 reloc;
-       const struct vmi_relocation_info *rel = (struct vmi_relocation_info *)&reloc;
-
-       /*
-        * Prevent page tables from being allocated in highmem, even if
-        * CONFIG_HIGHPTE is enabled.
-        */
-       __userpte_alloc_gfp &= ~__GFP_HIGHMEM;
-
-       if (call_vrom_func(vmi_rom, vmi_init) != 0) {
-               printk(KERN_ERR "VMI ROM failed to initialize!");
-               return 0;
-       }
-       savesegment(cs, kernel_cs);
-
-       pv_info.paravirt_enabled = 1;
-       pv_info.kernel_rpl = kernel_cs & SEGMENT_RPL_MASK;
-       pv_info.name = "vmi [deprecated]";
-
-       pv_init_ops.patch = vmi_patch;
-
-       /*
-        * Many of these operations are ABI compatible with VMI.
-        * This means we can fill in the paravirt-ops with direct
-        * pointers into the VMI ROM.  If the calling convention for
-        * these operations changes, this code needs to be updated.
-        *
-        * Exceptions
-        *  CPUID paravirt-op uses pointers, not the native ISA
-        *  halt has no VMI equivalent; all VMI halts are "safe"
-        *  no MSR support yet - just trap and emulate.  VMI uses the
-        *    same ABI as the native ISA, but Linux wants exceptions
-        *    from bogus MSR read / write handled
-        *  rdpmc is not yet used in Linux
-        */
-
-       /* CPUID is special, so very special it gets wrapped like a present */
-       para_wrap(pv_cpu_ops.cpuid, vmi_cpuid, cpuid, CPUID);
-
-       para_fill(pv_cpu_ops.clts, CLTS);
-       para_fill(pv_cpu_ops.get_debugreg, GetDR);
-       para_fill(pv_cpu_ops.set_debugreg, SetDR);
-       para_fill(pv_cpu_ops.read_cr0, GetCR0);
-       para_fill(pv_mmu_ops.read_cr2, GetCR2);
-       para_fill(pv_mmu_ops.read_cr3, GetCR3);
-       para_fill(pv_cpu_ops.read_cr4, GetCR4);
-       para_fill(pv_cpu_ops.write_cr0, SetCR0);
-       para_fill(pv_mmu_ops.write_cr2, SetCR2);
-       para_fill(pv_mmu_ops.write_cr3, SetCR3);
-       para_fill(pv_cpu_ops.write_cr4, SetCR4);
-
-       para_fill(pv_irq_ops.save_fl.func, GetInterruptMask);
-       para_fill(pv_irq_ops.restore_fl.func, SetInterruptMask);
-       para_fill(pv_irq_ops.irq_disable.func, DisableInterrupts);
-       para_fill(pv_irq_ops.irq_enable.func, EnableInterrupts);
-
-       para_fill(pv_cpu_ops.wbinvd, WBINVD);
-       para_fill(pv_cpu_ops.read_tsc, RDTSC);
-
-       /* The following we emulate with trap and emulate for now */
-       /* paravirt_ops.read_msr = vmi_rdmsr */
-       /* paravirt_ops.write_msr = vmi_wrmsr */
-       /* paravirt_ops.rdpmc = vmi_rdpmc */
-
-       /* TR interface doesn't pass TR value, wrap */
-       para_wrap(pv_cpu_ops.load_tr_desc, vmi_set_tr, set_tr, SetTR);
-
-       /* LDT is special, too */
-       para_wrap(pv_cpu_ops.set_ldt, vmi_set_ldt, _set_ldt, SetLDT);
-
-       para_fill(pv_cpu_ops.load_gdt, SetGDT);
-       para_fill(pv_cpu_ops.load_idt, SetIDT);
-       para_fill(pv_cpu_ops.store_gdt, GetGDT);
-       para_fill(pv_cpu_ops.store_idt, GetIDT);
-       para_fill(pv_cpu_ops.store_tr, GetTR);
-       pv_cpu_ops.load_tls = vmi_load_tls;
-       para_wrap(pv_cpu_ops.write_ldt_entry, vmi_write_ldt_entry,
-                 write_ldt_entry, WriteLDTEntry);
-       para_wrap(pv_cpu_ops.write_gdt_entry, vmi_write_gdt_entry,
-                 write_gdt_entry, WriteGDTEntry);
-       para_wrap(pv_cpu_ops.write_idt_entry, vmi_write_idt_entry,
-                 write_idt_entry, WriteIDTEntry);
-       para_wrap(pv_cpu_ops.load_sp0, vmi_load_sp0, set_kernel_stack, UpdateKernelStack);
-       para_fill(pv_cpu_ops.set_iopl_mask, SetIOPLMask);
-       para_fill(pv_cpu_ops.io_delay, IODelay);
-
-       para_wrap(pv_cpu_ops.start_context_switch, vmi_start_context_switch,
-                 set_lazy_mode, SetLazyMode);
-       para_wrap(pv_cpu_ops.end_context_switch, vmi_end_context_switch,
-                 set_lazy_mode, SetLazyMode);
-
-       para_wrap(pv_mmu_ops.lazy_mode.enter, vmi_enter_lazy_mmu,
-                 set_lazy_mode, SetLazyMode);
-       para_wrap(pv_mmu_ops.lazy_mode.leave, vmi_leave_lazy_mmu,
-                 set_lazy_mode, SetLazyMode);
-
-       /* user and kernel flush are just handled with different flags to FlushTLB */
-       para_wrap(pv_mmu_ops.flush_tlb_user, vmi_flush_tlb_user, _flush_tlb, FlushTLB);
-       para_wrap(pv_mmu_ops.flush_tlb_kernel, vmi_flush_tlb_kernel, _flush_tlb, FlushTLB);
-       para_fill(pv_mmu_ops.flush_tlb_single, InvalPage);
-
-       /*
-        * Until a standard flag format can be agreed on, we need to
-        * implement these as wrappers in Linux.  Get the VMI ROM
-        * function pointers for the two backend calls.
-        */
-#ifdef CONFIG_X86_PAE
-       vmi_ops.set_pte = vmi_get_function(VMI_CALL_SetPxELong);
-       vmi_ops.update_pte = vmi_get_function(VMI_CALL_UpdatePxELong);
-#else
-       vmi_ops.set_pte = vmi_get_function(VMI_CALL_SetPxE);
-       vmi_ops.update_pte = vmi_get_function(VMI_CALL_UpdatePxE);
-#endif
-
-       if (vmi_ops.set_pte) {
-               pv_mmu_ops.set_pte = vmi_set_pte;
-               pv_mmu_ops.set_pte_at = vmi_set_pte_at;
-               pv_mmu_ops.set_pmd = vmi_set_pmd;
-#ifdef CONFIG_X86_PAE
-               pv_mmu_ops.set_pte_atomic = vmi_set_pte_atomic;
-               pv_mmu_ops.set_pud = vmi_set_pud;
-               pv_mmu_ops.pte_clear = vmi_pte_clear;
-               pv_mmu_ops.pmd_clear = vmi_pmd_clear;
-#endif
-       }
-
-       if (vmi_ops.update_pte) {
-               pv_mmu_ops.pte_update = vmi_update_pte;
-               pv_mmu_ops.pte_update_defer = vmi_update_pte_defer;
-       }
-
-       vmi_ops.allocate_page = vmi_get_function(VMI_CALL_AllocatePage);
-       if (vmi_ops.allocate_page) {
-               pv_mmu_ops.alloc_pte = vmi_allocate_pte;
-               pv_mmu_ops.alloc_pmd = vmi_allocate_pmd;
-               pv_mmu_ops.alloc_pmd_clone = vmi_allocate_pmd_clone;
-       }
-
-       vmi_ops.release_page = vmi_get_function(VMI_CALL_ReleasePage);
-       if (vmi_ops.release_page) {
-               pv_mmu_ops.release_pte = vmi_release_pte;
-               pv_mmu_ops.release_pmd = vmi_release_pmd;
-               pv_mmu_ops.pgd_free = vmi_pgd_free;
-       }
-
-       /* Set linear is needed in all cases */
-       vmi_ops.set_linear_mapping = vmi_get_function(VMI_CALL_SetLinearMapping);
-
-       /*
-        * These MUST always be patched.  Don't support indirect jumps
-        * through these operations, as the VMI interface may use either
-        * a jump or a call to get to these operations, depending on
-        * the backend.  They are performance critical anyway, so requiring
-        * a patch is not a big problem.
-        */
-       pv_cpu_ops.irq_enable_sysexit = (void *)0xfeedbab0;
-       pv_cpu_ops.iret = (void *)0xbadbab0;
-
-#ifdef CONFIG_SMP
-       para_wrap(pv_apic_ops.startup_ipi_hook, vmi_startup_ipi_hook, set_initial_ap_state, SetInitialAPState);
-#endif
-
-#ifdef CONFIG_X86_LOCAL_APIC
-       para_fill(apic->read, APICRead);
-       para_fill(apic->write, APICWrite);
-#endif
-
-       /*
-        * Check for VMI timer functionality by probing for a cycle frequency method
-        */
-       reloc = call_vrom_long_func(vmi_rom, get_reloc, VMI_CALL_GetCycleFrequency);
-       if (!disable_vmi_timer && rel->type != VMI_RELOCATION_NONE) {
-               vmi_timer_ops.get_cycle_frequency = (void *)rel->eip;
-               vmi_timer_ops.get_cycle_counter =
-                       vmi_get_function(VMI_CALL_GetCycleCounter);
-               vmi_timer_ops.get_wallclock =
-                       vmi_get_function(VMI_CALL_GetWallclockTime);
-               vmi_timer_ops.wallclock_updated =
-                       vmi_get_function(VMI_CALL_WallclockUpdated);
-               vmi_timer_ops.set_alarm = vmi_get_function(VMI_CALL_SetAlarm);
-               vmi_timer_ops.cancel_alarm =
-                        vmi_get_function(VMI_CALL_CancelAlarm);
-               x86_init.timers.timer_init = vmi_time_init;
-#ifdef CONFIG_X86_LOCAL_APIC
-               x86_init.timers.setup_percpu_clockev = vmi_time_bsp_init;
-               x86_cpuinit.setup_percpu_clockev = vmi_time_ap_init;
-#endif
-               pv_time_ops.sched_clock = vmi_sched_clock;
-               x86_platform.calibrate_tsc = vmi_tsc_khz;
-               x86_platform.get_wallclock = vmi_get_wallclock;
-               x86_platform.set_wallclock = vmi_set_wallclock;
-
-               /* We have true wallclock functions; disable CMOS clock sync */
-               no_sync_cmos_clock = 1;
-       } else {
-               disable_noidle = 1;
-               disable_vmi_timer = 1;
-       }
-
-       para_fill(pv_irq_ops.safe_halt, Halt);
-
-       /*
-        * Alternative instruction rewriting doesn't happen soon enough
-        * to convert VMI_IRET to a call instead of a jump; so we have
-        * to do this before IRQs get reenabled.  Fortunately, it is
-        * idempotent.
-        */
-       apply_paravirt(__parainstructions, __parainstructions_end);
-
-       vmi_bringup();
-
-       return 1;
-}
-
-#undef para_fill
-
-void __init vmi_init(void)
-{
-       if (!vmi_rom)
-               probe_vmi_rom();
-       else
-               check_vmi_rom(vmi_rom);
-
-       /* In case probing for or validating the ROM failed, basil */
-       if (!vmi_rom)
-               return;
-
-       reserve_top_address(-vmi_rom->virtual_top);
-
-#ifdef CONFIG_X86_IO_APIC
-       /* This is virtual hardware; timer routing is wired correctly */
-       no_timer_check = 1;
-#endif
-}
-
-void __init vmi_activate(void)
-{
-       unsigned long flags;
-
-       if (!vmi_rom)
-               return;
-
-       local_irq_save(flags);
-       activate_vmi();
-       local_irq_restore(flags & X86_EFLAGS_IF);
-}
-
-static int __init parse_vmi(char *arg)
-{
-       if (!arg)
-               return -EINVAL;
-
-       if (!strcmp(arg, "disable_pge")) {
-               clear_cpu_cap(&boot_cpu_data, X86_FEATURE_PGE);
-               disable_pge = 1;
-       } else if (!strcmp(arg, "disable_pse")) {
-               clear_cpu_cap(&boot_cpu_data, X86_FEATURE_PSE);
-               disable_pse = 1;
-       } else if (!strcmp(arg, "disable_sep")) {
-               clear_cpu_cap(&boot_cpu_data, X86_FEATURE_SEP);
-               disable_sep = 1;
-       } else if (!strcmp(arg, "disable_tsc")) {
-               clear_cpu_cap(&boot_cpu_data, X86_FEATURE_TSC);
-               disable_tsc = 1;
-       } else if (!strcmp(arg, "disable_mtrr")) {
-               clear_cpu_cap(&boot_cpu_data, X86_FEATURE_MTRR);
-               disable_mtrr = 1;
-       } else if (!strcmp(arg, "disable_timer")) {
-               disable_vmi_timer = 1;
-               disable_noidle = 1;
-       } else if (!strcmp(arg, "disable_noidle"))
-               disable_noidle = 1;
-       return 0;
-}
-
-early_param("vmi", parse_vmi);
diff --git a/arch/x86/kernel/vmiclock_32.c b/arch/x86/kernel/vmiclock_32.c
deleted file mode 100644 (file)
index 5e1ff66..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * VMI paravirtual timer support routines.
- *
- * Copyright (C) 2007, VMware, 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, GOOD TITLE or
- * NON INFRINGEMENT.  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/smp.h>
-#include <linux/interrupt.h>
-#include <linux/cpumask.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-
-#include <asm/vmi.h>
-#include <asm/vmi_time.h>
-#include <asm/apicdef.h>
-#include <asm/apic.h>
-#include <asm/timer.h>
-#include <asm/i8253.h>
-#include <asm/irq_vectors.h>
-
-#define VMI_ONESHOT  (VMI_ALARM_IS_ONESHOT  | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
-#define VMI_PERIODIC (VMI_ALARM_IS_PERIODIC | VMI_CYCLES_REAL | vmi_get_alarm_wiring())
-
-static DEFINE_PER_CPU(struct clock_event_device, local_events);
-
-static inline u32 vmi_counter(u32 flags)
-{
-       /* Given VMI_ONESHOT or VMI_PERIODIC, return the corresponding
-        * cycle counter. */
-       return flags & VMI_ALARM_COUNTER_MASK;
-}
-
-/* paravirt_ops.get_wallclock = vmi_get_wallclock */
-unsigned long vmi_get_wallclock(void)
-{
-       unsigned long long wallclock;
-       wallclock = vmi_timer_ops.get_wallclock(); // nsec
-       (void)do_div(wallclock, 1000000000);       // sec
-
-       return wallclock;
-}
-
-/* paravirt_ops.set_wallclock = vmi_set_wallclock */
-int vmi_set_wallclock(unsigned long now)
-{
-       return 0;
-}
-
-/* paravirt_ops.sched_clock = vmi_sched_clock */
-unsigned long long vmi_sched_clock(void)
-{
-       return cycles_2_ns(vmi_timer_ops.get_cycle_counter(VMI_CYCLES_AVAILABLE));
-}
-
-/* x86_platform.calibrate_tsc = vmi_tsc_khz */
-unsigned long vmi_tsc_khz(void)
-{
-       unsigned long long khz;
-       khz = vmi_timer_ops.get_cycle_frequency();
-       (void)do_div(khz, 1000);
-       return khz;
-}
-
-static inline unsigned int vmi_get_timer_vector(void)
-{
-       return IRQ0_VECTOR;
-}
-
-/** vmi clockchip */
-#ifdef CONFIG_X86_LOCAL_APIC
-static unsigned int startup_timer_irq(unsigned int irq)
-{
-       unsigned long val = apic_read(APIC_LVTT);
-       apic_write(APIC_LVTT, vmi_get_timer_vector());
-
-       return (val & APIC_SEND_PENDING);
-}
-
-static void mask_timer_irq(unsigned int irq)
-{
-       unsigned long val = apic_read(APIC_LVTT);
-       apic_write(APIC_LVTT, val | APIC_LVT_MASKED);
-}
-
-static void unmask_timer_irq(unsigned int irq)
-{
-       unsigned long val = apic_read(APIC_LVTT);
-       apic_write(APIC_LVTT, val & ~APIC_LVT_MASKED);
-}
-
-static void ack_timer_irq(unsigned int irq)
-{
-       ack_APIC_irq();
-}
-
-static struct irq_chip vmi_chip __read_mostly = {
-       .name           = "VMI-LOCAL",
-       .startup        = startup_timer_irq,
-       .mask           = mask_timer_irq,
-       .unmask         = unmask_timer_irq,
-       .ack            = ack_timer_irq
-};
-#endif
-
-/** vmi clockevent */
-#define VMI_ALARM_WIRED_IRQ0    0x00000000
-#define VMI_ALARM_WIRED_LVTT    0x00010000
-static int vmi_wiring = VMI_ALARM_WIRED_IRQ0;
-
-static inline int vmi_get_alarm_wiring(void)
-{
-       return vmi_wiring;
-}
-
-static void vmi_timer_set_mode(enum clock_event_mode mode,
-                              struct clock_event_device *evt)
-{
-       cycle_t now, cycles_per_hz;
-       BUG_ON(!irqs_disabled());
-
-       switch (mode) {
-       case CLOCK_EVT_MODE_ONESHOT:
-       case CLOCK_EVT_MODE_RESUME:
-               break;
-       case CLOCK_EVT_MODE_PERIODIC:
-               cycles_per_hz = vmi_timer_ops.get_cycle_frequency();
-               (void)do_div(cycles_per_hz, HZ);
-               now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_PERIODIC));
-               vmi_timer_ops.set_alarm(VMI_PERIODIC, now, cycles_per_hz);
-               break;
-       case CLOCK_EVT_MODE_UNUSED:
-       case CLOCK_EVT_MODE_SHUTDOWN:
-               switch (evt->mode) {
-               case CLOCK_EVT_MODE_ONESHOT:
-                       vmi_timer_ops.cancel_alarm(VMI_ONESHOT);
-                       break;
-               case CLOCK_EVT_MODE_PERIODIC:
-                       vmi_timer_ops.cancel_alarm(VMI_PERIODIC);
-                       break;
-               default:
-                       break;
-               }
-               break;
-       default:
-               break;
-       }
-}
-
-static int vmi_timer_next_event(unsigned long delta,
-                               struct clock_event_device *evt)
-{
-       /* Unfortunately, set_next_event interface only passes relative
-        * expiry, but we want absolute expiry.  It'd be better if were
-        * were passed an absolute expiry, since a bunch of time may
-        * have been stolen between the time the delta is computed and
-        * when we set the alarm below. */
-       cycle_t now = vmi_timer_ops.get_cycle_counter(vmi_counter(VMI_ONESHOT));
-
-       BUG_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
-       vmi_timer_ops.set_alarm(VMI_ONESHOT, now + delta, 0);
-       return 0;
-}
-
-static struct clock_event_device vmi_clockevent = {
-       .name           = "vmi-timer",
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
-       .shift          = 22,
-       .set_mode       = vmi_timer_set_mode,
-       .set_next_event = vmi_timer_next_event,
-       .rating         = 1000,
-       .irq            = 0,
-};
-
-static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id)
-{
-       struct clock_event_device *evt = &__get_cpu_var(local_events);
-       evt->event_handler(evt);
-       return IRQ_HANDLED;
-}
-
-static struct irqaction vmi_clock_action  = {
-       .name           = "vmi-timer",
-       .handler        = vmi_timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
-};
-
-static void __devinit vmi_time_init_clockevent(void)
-{
-       cycle_t cycles_per_msec;
-       struct clock_event_device *evt;
-
-       int cpu = smp_processor_id();
-       evt = &__get_cpu_var(local_events);
-
-       /* Use cycles_per_msec since div_sc params are 32-bits. */
-       cycles_per_msec = vmi_timer_ops.get_cycle_frequency();
-       (void)do_div(cycles_per_msec, 1000);
-
-       memcpy(evt, &vmi_clockevent, sizeof(*evt));
-       /* Must pick .shift such that .mult fits in 32-bits.  Choosing
-        * .shift to be 22 allows 2^(32-22) cycles per nano-seconds
-        * before overflow. */
-       evt->mult = div_sc(cycles_per_msec, NSEC_PER_MSEC, evt->shift);
-       /* Upper bound is clockevent's use of ulong for cycle deltas. */
-       evt->max_delta_ns = clockevent_delta2ns(ULONG_MAX, evt);
-       evt->min_delta_ns = clockevent_delta2ns(1, evt);
-       evt->cpumask = cpumask_of(cpu);
-
-       printk(KERN_WARNING "vmi: registering clock event %s. mult=%u shift=%u\n",
-              evt->name, evt->mult, evt->shift);
-       clockevents_register_device(evt);
-}
-
-void __init vmi_time_init(void)
-{
-       unsigned int cpu;
-       /* Disable PIT: BIOSes start PIT CH0 with 18.2hz peridic. */
-       outb_pit(0x3a, PIT_MODE); /* binary, mode 5, LSB/MSB, ch 0 */
-
-       vmi_time_init_clockevent();
-       setup_irq(0, &vmi_clock_action);
-       for_each_possible_cpu(cpu)
-               per_cpu(vector_irq, cpu)[vmi_get_timer_vector()] = 0;
-}
-
-#ifdef CONFIG_X86_LOCAL_APIC
-void __devinit vmi_time_bsp_init(void)
-{
-       /*
-        * On APIC systems, we want local timers to fire on each cpu.  We do
-        * this by programming LVTT to deliver timer events to the IRQ handler
-        * for IRQ-0, since we can't re-use the APIC local timer handler
-        * without interfering with that code.
-        */
-       clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
-       local_irq_disable();
-#ifdef CONFIG_SMP
-       /*
-        * XXX handle_percpu_irq only defined for SMP; we need to switch over
-        * to using it, since this is a local interrupt, which each CPU must
-        * handle individually without locking out or dropping simultaneous
-        * local timers on other CPUs.  We also don't want to trigger the
-        * quirk workaround code for interrupts which gets invoked from
-        * handle_percpu_irq via eoi, so we use our own IRQ chip.
-        */
-       set_irq_chip_and_handler_name(0, &vmi_chip, handle_percpu_irq, "lvtt");
-#else
-       set_irq_chip_and_handler_name(0, &vmi_chip, handle_edge_irq, "lvtt");
-#endif
-       vmi_wiring = VMI_ALARM_WIRED_LVTT;
-       apic_write(APIC_LVTT, vmi_get_timer_vector());
-       local_irq_enable();
-       clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
-}
-
-void __devinit vmi_time_ap_init(void)
-{
-       vmi_time_init_clockevent();
-       apic_write(APIC_LVTT, vmi_get_timer_vector());
-}
-#endif
-
-/** vmi clocksource */
-static struct clocksource clocksource_vmi;
-
-static cycle_t read_real_cycles(struct clocksource *cs)
-{
-       cycle_t ret = (cycle_t)vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL);
-       return max(ret, clocksource_vmi.cycle_last);
-}
-
-static struct clocksource clocksource_vmi = {
-       .name                   = "vmi-timer",
-       .rating                 = 450,
-       .read                   = read_real_cycles,
-       .mask                   = CLOCKSOURCE_MASK(64),
-       .mult                   = 0, /* to be set */
-       .shift                  = 22,
-       .flags                  = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static int __init init_vmi_clocksource(void)
-{
-       cycle_t cycles_per_msec;
-
-       if (!vmi_timer_ops.get_cycle_frequency)
-               return 0;
-       /* Use khz2mult rather than hz2mult since hz arg is only 32-bits. */
-       cycles_per_msec = vmi_timer_ops.get_cycle_frequency();
-       (void)do_div(cycles_per_msec, 1000);
-
-       /* Note that clocksource.{mult, shift} converts in the opposite direction
-        * as clockevents.  */
-       clocksource_vmi.mult = clocksource_khz2mult(cycles_per_msec,
-                                                   clocksource_vmi.shift);
-
-       printk(KERN_WARNING "vmi: registering clock source khz=%lld\n", cycles_per_msec);
-       return clocksource_register(&clocksource_vmi);
-
-}
-module_init(init_vmi_clocksource);
index d0bb52296fa3a8f564cdb1964107e677494859ed..38e2b67807e14928290f32361a4a8eeb9dda33fe 100644 (file)
@@ -242,6 +242,12 @@ SECTIONS
                __x86_cpu_dev_end = .;
        }
 
+       /*
+        * start address and size of operations which during runtime
+        * can be patched with virtualization friendly instructions or
+        * baremetal native ones. Think page table operations.
+        * Details in paravirt_types.h
+        */
        . = ALIGN(8);
        .parainstructions : AT(ADDR(.parainstructions) - LOAD_OFFSET) {
                __parainstructions = .;
@@ -249,6 +255,11 @@ SECTIONS
                __parainstructions_end = .;
        }
 
+       /*
+        * struct alt_inst entries. From the header (alternative.h):
+        * "Alternative instructions for different CPU types or capabilities"
+        * Think locking instructions on spinlocks.
+        */
        . = ALIGN(8);
        .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
                __alt_instructions = .;
@@ -256,10 +267,27 @@ SECTIONS
                __alt_instructions_end = .;
        }
 
+       /*
+        * And here are the replacement instructions. The linker sticks
+        * them as binary blobs. The .altinstructions has enough data to
+        * get the address and the length of them to patch the kernel safely.
+        */
        .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
                *(.altinstr_replacement)
        }
 
+       /*
+        * struct iommu_table_entry entries are injected in this section.
+        * It is an array of IOMMUs which during run time gets sorted depending
+        * on its dependency order. After rootfs_initcall is complete
+        * this section can be safely removed.
+        */
+       .iommu_table : AT(ADDR(.iommu_table) - LOAD_OFFSET) {
+               __iommu_table = .;
+               *(.iommu_table)
+               __iommu_table_end = .;
+       }
+       . = ALIGN(8);
        /*
         * .exit.text is discard at runtime, not link time, to deal with
         *  references from .altinstructions and .eh_frame
index 77d8c0f4817d5f10f88e725ad49b22642c1172c5..22b06f7660f4f44459ef62568659f745d2d8dc83 100644 (file)
@@ -1056,14 +1056,13 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
 
        vcpu->arch.apic = apic;
 
-       apic->regs_page = alloc_page(GFP_KERNEL);
+       apic->regs_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
        if (apic->regs_page == NULL) {
                printk(KERN_ERR "malloc apic regs error for vcpu %x\n",
                       vcpu->vcpu_id);
                goto nomem_free_apic;
        }
        apic->regs = page_address(apic->regs_page);
-       memset(apic->regs, 0, PAGE_SIZE);
        apic->vcpu = vcpu;
 
        hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC,
index 81ed28cb36e692eb4413c294408d5498bee876e8..8a3f9f64f86f9e7fee5bc5112bf50a04fbe37b15 100644 (file)
@@ -3163,8 +3163,8 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
        sync_lapic_to_cr8(vcpu);
 
        save_host_msrs(vcpu);
-       fs_selector = kvm_read_fs();
-       gs_selector = kvm_read_gs();
+       savesegment(fs, fs_selector);
+       savesegment(gs, gs_selector);
        ldt_selector = kvm_read_ldt();
        svm->vmcb->save.cr2 = vcpu->arch.cr2;
        /* required for live migration with NPT */
@@ -3251,10 +3251,15 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
        vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
        vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
 
-       kvm_load_fs(fs_selector);
-       kvm_load_gs(gs_selector);
-       kvm_load_ldt(ldt_selector);
        load_host_msrs(vcpu);
+       loadsegment(fs, fs_selector);
+#ifdef CONFIG_X86_64
+       load_gs_index(gs_selector);
+       wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
+#else
+       loadsegment(gs, gs_selector);
+#endif
+       kvm_load_ldt(ldt_selector);
 
        reload_tss(vcpu);
 
index 49b25eee25acc075538a411fc24c23a326f02fd4..7bddfab120139435d1d10885520cc5293fefcc07 100644 (file)
@@ -803,7 +803,7 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
         */
        vmx->host_state.ldt_sel = kvm_read_ldt();
        vmx->host_state.gs_ldt_reload_needed = vmx->host_state.ldt_sel;
-       vmx->host_state.fs_sel = kvm_read_fs();
+       savesegment(fs, vmx->host_state.fs_sel);
        if (!(vmx->host_state.fs_sel & 7)) {
                vmcs_write16(HOST_FS_SELECTOR, vmx->host_state.fs_sel);
                vmx->host_state.fs_reload_needed = 0;
@@ -811,7 +811,7 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
                vmcs_write16(HOST_FS_SELECTOR, 0);
                vmx->host_state.fs_reload_needed = 1;
        }
-       vmx->host_state.gs_sel = kvm_read_gs();
+       savesegment(gs, vmx->host_state.gs_sel);
        if (!(vmx->host_state.gs_sel & 7))
                vmcs_write16(HOST_GS_SELECTOR, vmx->host_state.gs_sel);
        else {
@@ -841,27 +841,21 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
 
 static void __vmx_load_host_state(struct vcpu_vmx *vmx)
 {
-       unsigned long flags;
-
        if (!vmx->host_state.loaded)
                return;
 
        ++vmx->vcpu.stat.host_state_reload;
        vmx->host_state.loaded = 0;
        if (vmx->host_state.fs_reload_needed)
-               kvm_load_fs(vmx->host_state.fs_sel);
+               loadsegment(fs, vmx->host_state.fs_sel);
        if (vmx->host_state.gs_ldt_reload_needed) {
                kvm_load_ldt(vmx->host_state.ldt_sel);
-               /*
-                * If we have to reload gs, we must take care to
-                * preserve our gs base.
-                */
-               local_irq_save(flags);
-               kvm_load_gs(vmx->host_state.gs_sel);
 #ifdef CONFIG_X86_64
-               wrmsrl(MSR_GS_BASE, vmcs_readl(HOST_GS_BASE));
+               load_gs_index(vmx->host_state.gs_sel);
+               wrmsrl(MSR_KERNEL_GS_BASE, current->thread.gs);
+#else
+               loadsegment(gs, vmx->host_state.gs_sel);
 #endif
-               local_irq_restore(flags);
        }
        reload_tss();
 #ifdef CONFIG_X86_64
@@ -2589,8 +2583,8 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
        vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS);  /* 22.2.4 */
        vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
        vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
-       vmcs_write16(HOST_FS_SELECTOR, kvm_read_fs());    /* 22.2.4 */
-       vmcs_write16(HOST_GS_SELECTOR, kvm_read_gs());    /* 22.2.4 */
+       vmcs_write16(HOST_FS_SELECTOR, 0);            /* 22.2.4 */
+       vmcs_write16(HOST_GS_SELECTOR, 0);            /* 22.2.4 */
        vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
 #ifdef CONFIG_X86_64
        rdmsrl(MSR_FS_BASE, a);
index 3a09c625d5268ad4dc0f7a033d429c234babcb96..6c2ecf0a806d67040335f7c0c57c0b57fed3384d 100644 (file)
@@ -1991,13 +1991,14 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                0 /* Reserved */ | F(CX16) | 0 /* xTPR Update, PDCM */ |
                0 /* Reserved, DCA */ | F(XMM4_1) |
                F(XMM4_2) | F(X2APIC) | F(MOVBE) | F(POPCNT) |
-               0 /* Reserved, AES */ | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX);
+               0 /* Reserved*/ | F(AES) | F(XSAVE) | 0 /* OSXSAVE */ | F(AVX) |
+               F(F16C);
        /* cpuid 0x80000001.ecx */
        const u32 kvm_supported_word6_x86_features =
                F(LAHF_LM) | F(CMP_LEGACY) | F(SVM) | 0 /* ExtApicSpace */ |
                F(CR8_LEGACY) | F(ABM) | F(SSE4A) | F(MISALIGNSSE) |
-               F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(SSE5) |
-               0 /* SKINIT */ | 0 /* WDT */;
+               F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(XOP) |
+               0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM);
 
        /* all calls to cpuid_count() should be made on the same cpu */
        get_cpu();
index 9d5f5584845587acbf5f544d7405e260a5e16b95..73b1e1a1f4891708a8714570e36ce62b15ba6fc7 100644 (file)
@@ -791,22 +791,22 @@ static void lguest_flush_tlb_kernel(void)
  * simple as setting a bit.  We don't actually "ack" interrupts as such, we
  * just mask and unmask them.  I wonder if we should be cleverer?
  */
-static void disable_lguest_irq(unsigned int irq)
+static void disable_lguest_irq(struct irq_data *data)
 {
-       set_bit(irq, lguest_data.blocked_interrupts);
+       set_bit(data->irq, lguest_data.blocked_interrupts);
 }
 
-static void enable_lguest_irq(unsigned int irq)
+static void enable_lguest_irq(struct irq_data *data)
 {
-       clear_bit(irq, lguest_data.blocked_interrupts);
+       clear_bit(data->irq, lguest_data.blocked_interrupts);
 }
 
 /* This structure describes the lguest IRQ controller. */
 static struct irq_chip lguest_irq_controller = {
        .name           = "lguest",
-       .mask           = disable_lguest_irq,
-       .mask_ack       = disable_lguest_irq,
-       .unmask         = enable_lguest_irq,
+       .irq_mask       = disable_lguest_irq,
+       .irq_mask_ack   = disable_lguest_irq,
+       .irq_unmask     = enable_lguest_irq,
 };
 
 /*
@@ -838,12 +838,12 @@ static void __init lguest_init_IRQ(void)
  * rather than set them in lguest_init_IRQ we are called here every time an
  * lguest device needs an interrupt.
  *
- * FIXME: irq_to_desc_alloc_node() can fail due to lack of memory, we should
+ * FIXME: irq_alloc_desc_at() can fail due to lack of memory, we should
  * pass that up!
  */
 void lguest_setup_irq(unsigned int irq)
 {
-       irq_to_desc_alloc_node(irq, 0);
+       irq_alloc_desc_at(irq, 0);
        set_irq_chip_and_handler_name(irq, &lguest_irq_controller,
                                      handle_level_irq, "level");
 }
index 5415a9d06f53b75c4a993b0bbe96508502691142..b908a59eccf52fe4ab22382ae793cb2a9f023e4f 100644 (file)
@@ -22,22 +22,187 @@ EXPORT_SYMBOL(memset);
 
 void *memmove(void *dest, const void *src, size_t n)
 {
-       int d0, d1, d2;
-
-       if (dest < src) {
-               memcpy(dest, src, n);
-       } else {
-               __asm__ __volatile__(
-                       "std\n\t"
-                       "rep\n\t"
-                       "movsb\n\t"
-                       "cld"
-                       : "=&c" (d0), "=&S" (d1), "=&D" (d2)
-                       :"0" (n),
-                        "1" (n-1+src),
-                        "2" (n-1+dest)
-                       :"memory");
-       }
-       return dest;
+       int d0,d1,d2,d3,d4,d5;
+       char *ret = dest;
+
+       __asm__ __volatile__(
+               /* Handle more 16bytes in loop */
+               "cmp $0x10, %0\n\t"
+               "jb     1f\n\t"
+
+               /* Decide forward/backward copy mode */
+               "cmp %2, %1\n\t"
+               "jb     2f\n\t"
+
+               /*
+                * movs instruction have many startup latency
+                * so we handle small size by general register.
+                */
+               "cmp  $680, %0\n\t"
+               "jb 3f\n\t"
+               /*
+                * movs instruction is only good for aligned case.
+                */
+               "mov %1, %3\n\t"
+               "xor %2, %3\n\t"
+               "and $0xff, %3\n\t"
+               "jz 4f\n\t"
+               "3:\n\t"
+               "sub $0x10, %0\n\t"
+
+               /*
+                * We gobble 16byts forward in each loop.
+                */
+               "3:\n\t"
+               "sub $0x10, %0\n\t"
+               "mov 0*4(%1), %3\n\t"
+               "mov 1*4(%1), %4\n\t"
+               "mov  %3, 0*4(%2)\n\t"
+               "mov  %4, 1*4(%2)\n\t"
+               "mov 2*4(%1), %3\n\t"
+               "mov 3*4(%1), %4\n\t"
+               "mov  %3, 2*4(%2)\n\t"
+               "mov  %4, 3*4(%2)\n\t"
+               "lea  0x10(%1), %1\n\t"
+               "lea  0x10(%2), %2\n\t"
+               "jae 3b\n\t"
+               "add $0x10, %0\n\t"
+               "jmp 1f\n\t"
+
+               /*
+                * Handle data forward by movs.
+                */
+               ".p2align 4\n\t"
+               "4:\n\t"
+               "mov -4(%1, %0), %3\n\t"
+               "lea -4(%2, %0), %4\n\t"
+               "shr $2, %0\n\t"
+               "rep movsl\n\t"
+               "mov %3, (%4)\n\t"
+               "jmp 11f\n\t"
+               /*
+                * Handle data backward by movs.
+                */
+               ".p2align 4\n\t"
+               "6:\n\t"
+               "mov (%1), %3\n\t"
+               "mov %2, %4\n\t"
+               "lea -4(%1, %0), %1\n\t"
+               "lea -4(%2, %0), %2\n\t"
+               "shr $2, %0\n\t"
+               "std\n\t"
+               "rep movsl\n\t"
+               "mov %3,(%4)\n\t"
+               "cld\n\t"
+               "jmp 11f\n\t"
+
+               /*
+                * Start to prepare for backward copy.
+                */
+               ".p2align 4\n\t"
+               "2:\n\t"
+               "cmp  $680, %0\n\t"
+               "jb 5f\n\t"
+               "mov %1, %3\n\t"
+               "xor %2, %3\n\t"
+               "and $0xff, %3\n\t"
+               "jz 6b\n\t"
+
+               /*
+                * Calculate copy position to tail.
+                */
+               "5:\n\t"
+               "add %0, %1\n\t"
+               "add %0, %2\n\t"
+               "sub $0x10, %0\n\t"
+
+               /*
+                * We gobble 16byts backward in each loop.
+                */
+               "7:\n\t"
+               "sub $0x10, %0\n\t"
+
+               "mov -1*4(%1), %3\n\t"
+               "mov -2*4(%1), %4\n\t"
+               "mov  %3, -1*4(%2)\n\t"
+               "mov  %4, -2*4(%2)\n\t"
+               "mov -3*4(%1), %3\n\t"
+               "mov -4*4(%1), %4\n\t"
+               "mov  %3, -3*4(%2)\n\t"
+               "mov  %4, -4*4(%2)\n\t"
+               "lea  -0x10(%1), %1\n\t"
+               "lea  -0x10(%2), %2\n\t"
+               "jae 7b\n\t"
+               /*
+                * Calculate copy position to head.
+                */
+               "add $0x10, %0\n\t"
+               "sub %0, %1\n\t"
+               "sub %0, %2\n\t"
+
+               /*
+                * Move data from 8 bytes to 15 bytes.
+                */
+               ".p2align 4\n\t"
+               "1:\n\t"
+               "cmp $8, %0\n\t"
+               "jb 8f\n\t"
+               "mov 0*4(%1), %3\n\t"
+               "mov 1*4(%1), %4\n\t"
+               "mov -2*4(%1, %0), %5\n\t"
+               "mov -1*4(%1, %0), %1\n\t"
+
+               "mov  %3, 0*4(%2)\n\t"
+               "mov  %4, 1*4(%2)\n\t"
+               "mov  %5, -2*4(%2, %0)\n\t"
+               "mov  %1, -1*4(%2, %0)\n\t"
+               "jmp 11f\n\t"
+
+               /*
+                * Move data from 4 bytes to 7 bytes.
+                */
+               ".p2align 4\n\t"
+               "8:\n\t"
+               "cmp $4, %0\n\t"
+               "jb 9f\n\t"
+               "mov 0*4(%1), %3\n\t"
+               "mov -1*4(%1, %0), %4\n\t"
+               "mov  %3, 0*4(%2)\n\t"
+               "mov  %4, -1*4(%2, %0)\n\t"
+               "jmp 11f\n\t"
+
+               /*
+                * Move data from 2 bytes to 3 bytes.
+                */
+               ".p2align 4\n\t"
+               "9:\n\t"
+               "cmp $2, %0\n\t"
+               "jb 10f\n\t"
+               "movw 0*2(%1), %%dx\n\t"
+               "movw -1*2(%1, %0), %%bx\n\t"
+               "movw %%dx, 0*2(%2)\n\t"
+               "movw %%bx, -1*2(%2, %0)\n\t"
+               "jmp 11f\n\t"
+
+               /*
+                * Move data for 1 byte.
+                */
+               ".p2align 4\n\t"
+               "10:\n\t"
+               "cmp $1, %0\n\t"
+               "jb 11f\n\t"
+               "movb (%1), %%cl\n\t"
+               "movb %%cl, (%2)\n\t"
+               ".p2align 4\n\t"
+               "11:"
+               : "=&c" (d0), "=&S" (d1), "=&D" (d2),
+                 "=r" (d3),"=r" (d4), "=r"(d5)
+               :"0" (n),
+                "1" (src),
+                "2" (dest)
+               :"memory");
+
+       return ret;
+
 }
 EXPORT_SYMBOL(memmove);
index bcbcd1e0f7d57fe4b3972adc24785dc6837386f6..75ef61e35e38aee1cf62b05a48f1add62b148f98 100644 (file)
 ENTRY(__memcpy)
 ENTRY(memcpy)
        CFI_STARTPROC
+       movq %rdi, %rax
 
        /*
-        * Put the number of full 64-byte blocks into %ecx.
-        * Tail portion is handled at the end:
+        * Use 32bit CMP here to avoid long NOP padding.
         */
-       movq %rdi, %rax
-       movl %edx, %ecx
-       shrl   $6, %ecx
-       jz .Lhandle_tail
+       cmp  $0x20, %edx
+       jb .Lhandle_tail
 
-       .p2align 4
-.Lloop_64:
        /*
-        * We decrement the loop index here - and the zero-flag is
-        * checked at the end of the loop (instructions inbetween do
-        * not change the zero flag):
+        * We check whether memory false dependece could occur,
+        * then jump to corresponding copy mode.
         */
-       decl %ecx
+       cmp  %dil, %sil
+       jl .Lcopy_backward
+       subl $0x20, %edx
+.Lcopy_forward_loop:
+       subq $0x20,     %rdx
 
        /*
-        * Move in blocks of 4x16 bytes:
+        * Move in blocks of 4x8 bytes:
         */
-       movq 0*8(%rsi),         %r11
-       movq 1*8(%rsi),         %r8
-       movq %r11,              0*8(%rdi)
-       movq %r8,               1*8(%rdi)
-
-       movq 2*8(%rsi),         %r9
-       movq 3*8(%rsi),         %r10
-       movq %r9,               2*8(%rdi)
-       movq %r10,              3*8(%rdi)
-
-       movq 4*8(%rsi),         %r11
-       movq 5*8(%rsi),         %r8
-       movq %r11,              4*8(%rdi)
-       movq %r8,               5*8(%rdi)
-
-       movq 6*8(%rsi),         %r9
-       movq 7*8(%rsi),         %r10
-       movq %r9,               6*8(%rdi)
-       movq %r10,              7*8(%rdi)
-
-       leaq 64(%rsi), %rsi
-       leaq 64(%rdi), %rdi
-
-       jnz  .Lloop_64
+       movq 0*8(%rsi), %r8
+       movq 1*8(%rsi), %r9
+       movq 2*8(%rsi), %r10
+       movq 3*8(%rsi), %r11
+       leaq 4*8(%rsi), %rsi
+
+       movq %r8,       0*8(%rdi)
+       movq %r9,       1*8(%rdi)
+       movq %r10,      2*8(%rdi)
+       movq %r11,      3*8(%rdi)
+       leaq 4*8(%rdi), %rdi
+       jae  .Lcopy_forward_loop
+       addq $0x20,     %rdx
+       jmp  .Lhandle_tail
+
+.Lcopy_backward:
+       /*
+        * Calculate copy position to tail.
+        */
+       addq %rdx,      %rsi
+       addq %rdx,      %rdi
+       subq $0x20,     %rdx
+       /*
+        * At most 3 ALU operations in one cycle,
+        * so append NOPS in the same 16bytes trunk.
+        */
+       .p2align 4
+.Lcopy_backward_loop:
+       subq $0x20,     %rdx
+       movq -1*8(%rsi),        %r8
+       movq -2*8(%rsi),        %r9
+       movq -3*8(%rsi),        %r10
+       movq -4*8(%rsi),        %r11
+       leaq -4*8(%rsi),        %rsi
+       movq %r8,               -1*8(%rdi)
+       movq %r9,               -2*8(%rdi)
+       movq %r10,              -3*8(%rdi)
+       movq %r11,              -4*8(%rdi)
+       leaq -4*8(%rdi),        %rdi
+       jae  .Lcopy_backward_loop
 
+       /*
+        * Calculate copy position to head.
+        */
+       addq $0x20,     %rdx
+       subq %rdx,      %rsi
+       subq %rdx,      %rdi
 .Lhandle_tail:
-       movl %edx, %ecx
-       andl  $63, %ecx
-       shrl   $3, %ecx
-       jz   .Lhandle_7
+       cmpq $16,       %rdx
+       jb   .Lless_16bytes
 
+       /*
+        * Move data from 16 bytes to 31 bytes.
+        */
+       movq 0*8(%rsi), %r8
+       movq 1*8(%rsi), %r9
+       movq -2*8(%rsi, %rdx),  %r10
+       movq -1*8(%rsi, %rdx),  %r11
+       movq %r8,       0*8(%rdi)
+       movq %r9,       1*8(%rdi)
+       movq %r10,      -2*8(%rdi, %rdx)
+       movq %r11,      -1*8(%rdi, %rdx)
+       retq
        .p2align 4
-.Lloop_8:
-       decl %ecx
-       movq (%rsi),            %r8
-       movq %r8,               (%rdi)
-       leaq 8(%rdi),           %rdi
-       leaq 8(%rsi),           %rsi
-       jnz  .Lloop_8
-
-.Lhandle_7:
-       movl %edx, %ecx
-       andl $7, %ecx
-       jz .Lend
+.Lless_16bytes:
+       cmpq $8,        %rdx
+       jb   .Lless_8bytes
+       /*
+        * Move data from 8 bytes to 15 bytes.
+        */
+       movq 0*8(%rsi), %r8
+       movq -1*8(%rsi, %rdx),  %r9
+       movq %r8,       0*8(%rdi)
+       movq %r9,       -1*8(%rdi, %rdx)
+       retq
+       .p2align 4
+.Lless_8bytes:
+       cmpq $4,        %rdx
+       jb   .Lless_3bytes
 
+       /*
+        * Move data from 4 bytes to 7 bytes.
+        */
+       movl (%rsi), %ecx
+       movl -4(%rsi, %rdx), %r8d
+       movl %ecx, (%rdi)
+       movl %r8d, -4(%rdi, %rdx)
+       retq
        .p2align 4
+.Lless_3bytes:
+       cmpl $0, %edx
+       je .Lend
+       /*
+        * Move data from 1 bytes to 3 bytes.
+        */
 .Lloop_1:
        movb (%rsi), %r8b
        movb %r8b, (%rdi)
        incq %rdi
        incq %rsi
-       decl %ecx
+       decl %edx
        jnz .Lloop_1
 
 .Lend:
-       ret
+       retq
        CFI_ENDPROC
 ENDPROC(memcpy)
 ENDPROC(__memcpy)
index 0a33909bf12213dbb0945d057e5c7c537296074e..6d0f0ec41b348ad2a912fdb184303c094ce1a996 100644 (file)
 #undef memmove
 void *memmove(void *dest, const void *src, size_t count)
 {
-       if (dest < src) {
-               return memcpy(dest, src, count);
-       } else {
-               char *p = dest + count;
-               const char *s = src + count;
-               while (count--)
-                       *--p = *--s;
-       }
-       return dest;
+       unsigned long d0,d1,d2,d3,d4,d5,d6,d7;
+       char *ret;
+
+       __asm__ __volatile__(
+               /* Handle more 32bytes in loop */
+               "mov %2, %3\n\t"
+               "cmp $0x20, %0\n\t"
+               "jb     1f\n\t"
+
+               /* Decide forward/backward copy mode */
+               "cmp %2, %1\n\t"
+               "jb     2f\n\t"
+
+               /*
+                * movsq instruction have many startup latency
+                * so we handle small size by general register.
+                */
+               "cmp  $680, %0\n\t"
+               "jb 3f\n\t"
+               /*
+                * movsq instruction is only good for aligned case.
+                */
+               "cmpb %%dil, %%sil\n\t"
+               "je 4f\n\t"
+               "3:\n\t"
+               "sub $0x20, %0\n\t"
+               /*
+                * We gobble 32byts forward in each loop.
+                */
+               "5:\n\t"
+               "sub $0x20, %0\n\t"
+               "movq 0*8(%1), %4\n\t"
+               "movq 1*8(%1), %5\n\t"
+               "movq 2*8(%1), %6\n\t"
+               "movq 3*8(%1), %7\n\t"
+               "leaq 4*8(%1), %1\n\t"
+
+               "movq %4, 0*8(%2)\n\t"
+               "movq %5, 1*8(%2)\n\t"
+               "movq %6, 2*8(%2)\n\t"
+               "movq %7, 3*8(%2)\n\t"
+               "leaq 4*8(%2), %2\n\t"
+               "jae 5b\n\t"
+               "addq $0x20, %0\n\t"
+               "jmp 1f\n\t"
+               /*
+                * Handle data forward by movsq.
+                */
+               ".p2align 4\n\t"
+               "4:\n\t"
+               "movq %0, %8\n\t"
+               "movq -8(%1, %0), %4\n\t"
+               "lea -8(%2, %0), %5\n\t"
+               "shrq $3, %8\n\t"
+               "rep movsq\n\t"
+               "movq %4, (%5)\n\t"
+               "jmp 13f\n\t"
+               /*
+                * Handle data backward by movsq.
+                */
+               ".p2align 4\n\t"
+               "7:\n\t"
+               "movq %0, %8\n\t"
+               "movq (%1), %4\n\t"
+               "movq %2, %5\n\t"
+               "leaq -8(%1, %0), %1\n\t"
+               "leaq -8(%2, %0), %2\n\t"
+               "shrq $3, %8\n\t"
+               "std\n\t"
+               "rep movsq\n\t"
+               "cld\n\t"
+               "movq %4, (%5)\n\t"
+               "jmp 13f\n\t"
+
+               /*
+                * Start to prepare for backward copy.
+                */
+               ".p2align 4\n\t"
+               "2:\n\t"
+               "cmp $680, %0\n\t"
+               "jb 6f \n\t"
+               "cmp %%dil, %%sil\n\t"
+               "je 7b \n\t"
+               "6:\n\t"
+               /*
+                * Calculate copy position to tail.
+                */
+               "addq %0, %1\n\t"
+               "addq %0, %2\n\t"
+               "subq $0x20, %0\n\t"
+               /*
+                * We gobble 32byts backward in each loop.
+                */
+               "8:\n\t"
+               "subq $0x20, %0\n\t"
+               "movq -1*8(%1), %4\n\t"
+               "movq -2*8(%1), %5\n\t"
+               "movq -3*8(%1), %6\n\t"
+               "movq -4*8(%1), %7\n\t"
+               "leaq -4*8(%1), %1\n\t"
+
+               "movq %4, -1*8(%2)\n\t"
+               "movq %5, -2*8(%2)\n\t"
+               "movq %6, -3*8(%2)\n\t"
+               "movq %7, -4*8(%2)\n\t"
+               "leaq -4*8(%2), %2\n\t"
+               "jae 8b\n\t"
+               /*
+                * Calculate copy position to head.
+                */
+               "addq $0x20, %0\n\t"
+               "subq %0, %1\n\t"
+               "subq %0, %2\n\t"
+               "1:\n\t"
+               "cmpq $16, %0\n\t"
+               "jb 9f\n\t"
+               /*
+                * Move data from 16 bytes to 31 bytes.
+                */
+               "movq 0*8(%1), %4\n\t"
+               "movq 1*8(%1), %5\n\t"
+               "movq -2*8(%1, %0), %6\n\t"
+               "movq -1*8(%1, %0), %7\n\t"
+               "movq %4, 0*8(%2)\n\t"
+               "movq %5, 1*8(%2)\n\t"
+               "movq %6, -2*8(%2, %0)\n\t"
+               "movq %7, -1*8(%2, %0)\n\t"
+               "jmp 13f\n\t"
+               ".p2align 4\n\t"
+               "9:\n\t"
+               "cmpq $8, %0\n\t"
+               "jb 10f\n\t"
+               /*
+                * Move data from 8 bytes to 15 bytes.
+                */
+               "movq 0*8(%1), %4\n\t"
+               "movq -1*8(%1, %0), %5\n\t"
+               "movq %4, 0*8(%2)\n\t"
+               "movq %5, -1*8(%2, %0)\n\t"
+               "jmp 13f\n\t"
+               "10:\n\t"
+               "cmpq $4, %0\n\t"
+               "jb 11f\n\t"
+               /*
+                * Move data from 4 bytes to 7 bytes.
+                */
+               "movl (%1), %4d\n\t"
+               "movl -4(%1, %0), %5d\n\t"
+               "movl %4d, (%2)\n\t"
+               "movl %5d, -4(%2, %0)\n\t"
+               "jmp 13f\n\t"
+               "11:\n\t"
+               "cmp $2, %0\n\t"
+               "jb 12f\n\t"
+               /*
+                * Move data from 2 bytes to 3 bytes.
+                */
+               "movw (%1), %4w\n\t"
+               "movw -2(%1, %0), %5w\n\t"
+               "movw %4w, (%2)\n\t"
+               "movw %5w, -2(%2, %0)\n\t"
+               "jmp 13f\n\t"
+               "12:\n\t"
+               "cmp $1, %0\n\t"
+               "jb 13f\n\t"
+               /*
+                * Move data for 1 byte.
+                */
+               "movb (%1), %4b\n\t"
+               "movb %4b, (%2)\n\t"
+               "13:\n\t"
+               : "=&d" (d0), "=&S" (d1), "=&D" (d2), "=&a" (ret) ,
+                 "=r"(d3), "=r"(d4), "=r"(d5), "=r"(d6), "=&c" (d7)
+               :"0" (count),
+                "1" (src),
+                "2" (dest)
+               :"memory");
+
+               return ret;
+
 }
 EXPORT_SYMBOL(memmove);
index a4c768397baae6054f5938fc4170fb0876ccdb80..55543397a8a795f295ef6e3731e6b9373c953958 100644 (file)
@@ -26,4 +26,6 @@ obj-$(CONFIG_NUMA)            += numa.o numa_$(BITS).o
 obj-$(CONFIG_K8_NUMA)          += k8topology_64.o
 obj-$(CONFIG_ACPI_NUMA)                += srat_$(BITS).o
 
+obj-$(CONFIG_HAVE_MEMBLOCK)            += memblock.o
+
 obj-$(CONFIG_MEMTEST)          += memtest.o
index 4c4508e8a2043015c1cce3eb49a46c0c435e9297..79b0b372d2d033ca35a4bb83295a332c17bbb6c4 100644 (file)
@@ -229,7 +229,16 @@ void vmalloc_sync_all(void)
 
                spin_lock_irqsave(&pgd_lock, flags);
                list_for_each_entry(page, &pgd_list, lru) {
-                       if (!vmalloc_sync_one(page_address(page), address))
+                       spinlock_t *pgt_lock;
+                       pmd_t *ret;
+
+                       pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
+
+                       spin_lock(pgt_lock);
+                       ret = vmalloc_sync_one(page_address(page), address);
+                       spin_unlock(pgt_lock);
+
+                       if (!ret)
                                break;
                }
                spin_unlock_irqrestore(&pgd_lock, flags);
@@ -251,6 +260,8 @@ static noinline __kprobes int vmalloc_fault(unsigned long address)
        if (!(address >= VMALLOC_START && address < VMALLOC_END))
                return -1;
 
+       WARN_ON_ONCE(in_nmi());
+
        /*
         * Synchronize this task's top level page-table
         * with the 'reference' page table.
@@ -326,29 +337,7 @@ out:
 
 void vmalloc_sync_all(void)
 {
-       unsigned long address;
-
-       for (address = VMALLOC_START & PGDIR_MASK; address <= VMALLOC_END;
-            address += PGDIR_SIZE) {
-
-               const pgd_t *pgd_ref = pgd_offset_k(address);
-               unsigned long flags;
-               struct page *page;
-
-               if (pgd_none(*pgd_ref))
-                       continue;
-
-               spin_lock_irqsave(&pgd_lock, flags);
-               list_for_each_entry(page, &pgd_list, lru) {
-                       pgd_t *pgd;
-                       pgd = (pgd_t *)page_address(page) + pgd_index(address);
-                       if (pgd_none(*pgd))
-                               set_pgd(pgd, *pgd_ref);
-                       else
-                               BUG_ON(pgd_page_vaddr(*pgd) != pgd_page_vaddr(*pgd_ref));
-               }
-               spin_unlock_irqrestore(&pgd_lock, flags);
-       }
+       sync_global_pgds(VMALLOC_START & PGDIR_MASK, VMALLOC_END);
 }
 
 /*
@@ -369,6 +358,8 @@ static noinline __kprobes int vmalloc_fault(unsigned long address)
        if (!(address >= VMALLOC_START && address < VMALLOC_END))
                return -1;
 
+       WARN_ON_ONCE(in_nmi());
+
        /*
         * Copy kernel mappings over when needed. This can also
         * happen within a race in page table update. In the later
@@ -894,8 +885,14 @@ spurious_fault(unsigned long error_code, unsigned long address)
        if (pmd_large(*pmd))
                return spurious_fault_check(error_code, (pte_t *) pmd);
 
+       /*
+        * Note: don't use pte_present() here, since it returns true
+        * if the _PAGE_PROTNONE bit is set.  However, this aliases the
+        * _PAGE_GLOBAL bit, which for kernel pages give false positives
+        * when CONFIG_DEBUG_PAGEALLOC is used.
+        */
        pte = pte_offset_kernel(pmd, address);
-       if (!pte_present(*pte))
+       if (!(pte_flags(*pte) & _PAGE_PRESENT))
                return 0;
 
        ret = spurious_fault_check(error_code, pte);
index b278535b14aa00ce5b46de5e5bdd01cc75dc0c8a..c0e28a13de7df55c1ee1b173b61fd2d18c50e49c 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/initrd.h>
 #include <linux/ioport.h>
 #include <linux/swap.h>
+#include <linux/memblock.h>
 
 #include <asm/cacheflush.h>
 #include <asm/e820.h>
@@ -33,6 +34,7 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
                                          int use_gbpages)
 {
        unsigned long puds, pmds, ptes, tables, start;
+       phys_addr_t base;
 
        puds = (end + PUD_SIZE - 1) >> PUD_SHIFT;
        tables = roundup(puds * sizeof(pud_t), PAGE_SIZE);
@@ -75,12 +77,12 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
 #else
        start = 0x8000;
 #endif
-       e820_table_start = find_e820_area(start, max_pfn_mapped<<PAGE_SHIFT,
+       base = memblock_find_in_range(start, max_pfn_mapped<<PAGE_SHIFT,
                                        tables, PAGE_SIZE);
-       if (e820_table_start == -1UL)
+       if (base == MEMBLOCK_ERROR)
                panic("Cannot find space for the kernel page tables");
 
-       e820_table_start >>= PAGE_SHIFT;
+       e820_table_start = base >> PAGE_SHIFT;
        e820_table_end = e820_table_start;
        e820_table_top = e820_table_start + (tables >> PAGE_SHIFT);
 
@@ -299,7 +301,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
        __flush_tlb_all();
 
        if (!after_bootmem && e820_table_end > e820_table_start)
-               reserve_early(e820_table_start << PAGE_SHIFT,
+               memblock_x86_reserve_range(e820_table_start << PAGE_SHIFT,
                                 e820_table_end << PAGE_SHIFT, "PGTABLE");
 
        if (!after_bootmem)
index bca79091b9d6158bcab97bdba2d8b767babeea46..5d0a6711c2826fb543c999c8153a6a214e80033d 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/pfn.h>
 #include <linux/poison.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/proc_fs.h>
 #include <linux/memory_hotplug.h>
 #include <linux/initrd.h>
@@ -67,7 +68,7 @@ static __init void *alloc_low_page(void)
                panic("alloc_low_page: ran out of memory");
 
        adr = __va(pfn * PAGE_SIZE);
-       memset(adr, 0, PAGE_SIZE);
+       clear_page(adr);
        return adr;
 }
 
@@ -422,49 +423,28 @@ static void __init add_one_highpage_init(struct page *page)
        totalhigh_pages++;
 }
 
-struct add_highpages_data {
-       unsigned long start_pfn;
-       unsigned long end_pfn;
-};
-
-static int __init add_highpages_work_fn(unsigned long start_pfn,
-                                        unsigned long end_pfn, void *datax)
+void __init add_highpages_with_active_regions(int nid,
+                        unsigned long start_pfn, unsigned long end_pfn)
 {
-       int node_pfn;
-       struct page *page;
-       unsigned long final_start_pfn, final_end_pfn;
-       struct add_highpages_data *data;
+       struct range *range;
+       int nr_range;
+       int i;
 
-       data = (struct add_highpages_data *)datax;
+       nr_range = __get_free_all_memory_range(&range, nid, start_pfn, end_pfn);
 
-       final_start_pfn = max(start_pfn, data->start_pfn);
-       final_end_pfn = min(end_pfn, data->end_pfn);
-       if (final_start_pfn >= final_end_pfn)
-               return 0;
+       for (i = 0; i < nr_range; i++) {
+               struct page *page;
+               int node_pfn;
 
-       for (node_pfn = final_start_pfn; node_pfn < final_end_pfn;
-            node_pfn++) {
-               if (!pfn_valid(node_pfn))
-                       continue;
-               page = pfn_to_page(node_pfn);
-               add_one_highpage_init(page);
+               for (node_pfn = range[i].start; node_pfn < range[i].end;
+                    node_pfn++) {
+                       if (!pfn_valid(node_pfn))
+                               continue;
+                       page = pfn_to_page(node_pfn);
+                       add_one_highpage_init(page);
+               }
        }
-
-       return 0;
-
 }
-
-void __init add_highpages_with_active_regions(int nid, unsigned long start_pfn,
-                                             unsigned long end_pfn)
-{
-       struct add_highpages_data data;
-
-       data.start_pfn = start_pfn;
-       data.end_pfn = end_pfn;
-
-       work_with_active_regions(nid, add_highpages_work_fn, &data);
-}
-
 #else
 static inline void permanent_kmaps_init(pgd_t *pgd_base)
 {
@@ -558,7 +538,7 @@ char swsusp_pg_dir[PAGE_SIZE]
 
 static inline void save_pg_dir(void)
 {
-       memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE);
+       copy_page(swsusp_pg_dir, swapper_pg_dir);
 }
 #else /* !CONFIG_ACPI_SLEEP */
 static inline void save_pg_dir(void)
@@ -712,14 +692,14 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
        highstart_pfn = highend_pfn = max_pfn;
        if (max_pfn > max_low_pfn)
                highstart_pfn = max_low_pfn;
-       e820_register_active_regions(0, 0, highend_pfn);
+       memblock_x86_register_active_regions(0, 0, highend_pfn);
        sparse_memory_present_with_active_regions(0);
        printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
                pages_to_mb(highend_pfn - highstart_pfn));
        num_physpages = highend_pfn;
        high_memory = (void *) __va(highstart_pfn * PAGE_SIZE - 1) + 1;
 #else
-       e820_register_active_regions(0, 0, max_low_pfn);
+       memblock_x86_register_active_regions(0, 0, max_low_pfn);
        sparse_memory_present_with_active_regions(0);
        num_physpages = max_low_pfn;
        high_memory = (void *) __va(max_low_pfn * PAGE_SIZE - 1) + 1;
@@ -750,68 +730,12 @@ static void __init zone_sizes_init(void)
        free_area_init_nodes(max_zone_pfns);
 }
 
-#ifndef CONFIG_NO_BOOTMEM
-static unsigned long __init setup_node_bootmem(int nodeid,
-                                unsigned long start_pfn,
-                                unsigned long end_pfn,
-                                unsigned long bootmap)
-{
-       unsigned long bootmap_size;
-
-       /* don't touch min_low_pfn */
-       bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
-                                        bootmap >> PAGE_SHIFT,
-                                        start_pfn, end_pfn);
-       printk(KERN_INFO "  node %d low ram: %08lx - %08lx\n",
-               nodeid, start_pfn<<PAGE_SHIFT, end_pfn<<PAGE_SHIFT);
-       printk(KERN_INFO "  node %d bootmap %08lx - %08lx\n",
-                nodeid, bootmap, bootmap + bootmap_size);
-       free_bootmem_with_active_regions(nodeid, end_pfn);
-
-       return bootmap + bootmap_size;
-}
-#endif
-
 void __init setup_bootmem_allocator(void)
 {
-#ifndef CONFIG_NO_BOOTMEM
-       int nodeid;
-       unsigned long bootmap_size, bootmap;
-       /*
-        * Initialize the boot-time allocator (with low memory only):
-        */
-       bootmap_size = bootmem_bootmap_pages(max_low_pfn)<<PAGE_SHIFT;
-       bootmap = find_e820_area(0, max_pfn_mapped<<PAGE_SHIFT, bootmap_size,
-                                PAGE_SIZE);
-       if (bootmap == -1L)
-               panic("Cannot find bootmem map of size %ld\n", bootmap_size);
-       reserve_early(bootmap, bootmap + bootmap_size, "BOOTMAP");
-#endif
-
        printk(KERN_INFO "  mapped low ram: 0 - %08lx\n",
                 max_pfn_mapped<<PAGE_SHIFT);
        printk(KERN_INFO "  low ram: 0 - %08lx\n", max_low_pfn<<PAGE_SHIFT);
 
-#ifndef CONFIG_NO_BOOTMEM
-       for_each_online_node(nodeid) {
-                unsigned long start_pfn, end_pfn;
-
-#ifdef CONFIG_NEED_MULTIPLE_NODES
-               start_pfn = node_start_pfn[nodeid];
-               end_pfn = node_end_pfn[nodeid];
-               if (start_pfn > max_low_pfn)
-                       continue;
-               if (end_pfn > max_low_pfn)
-                       end_pfn = max_low_pfn;
-#else
-               start_pfn = 0;
-               end_pfn = max_low_pfn;
-#endif
-               bootmap = setup_node_bootmem(nodeid, start_pfn, end_pfn,
-                                                bootmap);
-       }
-#endif
-
        after_bootmem = 1;
 }
 
@@ -1070,8 +994,3 @@ void mark_rodata_ro(void)
 }
 #endif
 
-int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
-                                  int flags)
-{
-       return reserve_bootmem(phys, len, flags);
-}
index 9a6674689a20f8e491f0a0f845079de9febaac5f..84346200e783bee9a9caf37e1d9a46d7936d97ba 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/initrd.h>
 #include <linux/pagemap.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
 #include <linux/pfn.h>
@@ -52,8 +53,6 @@
 #include <asm/init.h>
 #include <linux/bootmem.h>
 
-static unsigned long dma_reserve __initdata;
-
 static int __init parse_direct_gbpages_off(char *arg)
 {
        direct_gbpages = 0;
@@ -97,6 +96,43 @@ static int __init nonx32_setup(char *str)
 }
 __setup("noexec32=", nonx32_setup);
 
+/*
+ * When memory was added/removed make sure all the processes MM have
+ * suitable PGD entries in the local PGD level page.
+ */
+void sync_global_pgds(unsigned long start, unsigned long end)
+{
+       unsigned long address;
+
+       for (address = start; address <= end; address += PGDIR_SIZE) {
+               const pgd_t *pgd_ref = pgd_offset_k(address);
+               unsigned long flags;
+               struct page *page;
+
+               if (pgd_none(*pgd_ref))
+                       continue;
+
+               spin_lock_irqsave(&pgd_lock, flags);
+               list_for_each_entry(page, &pgd_list, lru) {
+                       pgd_t *pgd;
+                       spinlock_t *pgt_lock;
+
+                       pgd = (pgd_t *)page_address(page) + pgd_index(address);
+                       pgt_lock = &pgd_page_get_mm(page)->page_table_lock;
+                       spin_lock(pgt_lock);
+
+                       if (pgd_none(*pgd))
+                               set_pgd(pgd, *pgd_ref);
+                       else
+                               BUG_ON(pgd_page_vaddr(*pgd)
+                                      != pgd_page_vaddr(*pgd_ref));
+
+                       spin_unlock(pgt_lock);
+               }
+               spin_unlock_irqrestore(&pgd_lock, flags);
+       }
+}
+
 /*
  * NOTE: This function is marked __ref because it calls __init function
  * (alloc_bootmem_pages). It's safe to do it ONLY when after_bootmem == 0.
@@ -293,7 +329,7 @@ static __ref void *alloc_low_page(unsigned long *phys)
                panic("alloc_low_page: ran out of memory");
 
        adr = early_memremap(pfn * PAGE_SIZE, PAGE_SIZE);
-       memset(adr, 0, PAGE_SIZE);
+       clear_page(adr);
        *phys  = pfn * PAGE_SIZE;
        return adr;
 }
@@ -534,11 +570,13 @@ kernel_physical_mapping_init(unsigned long start,
                             unsigned long end,
                             unsigned long page_size_mask)
 {
-
+       bool pgd_changed = false;
        unsigned long next, last_map_addr = end;
+       unsigned long addr;
 
        start = (unsigned long)__va(start);
        end = (unsigned long)__va(end);
+       addr = start;
 
        for (; start < end; start = next) {
                pgd_t *pgd = pgd_offset_k(start);
@@ -563,7 +601,12 @@ kernel_physical_mapping_init(unsigned long start,
                spin_lock(&init_mm.page_table_lock);
                pgd_populate(&init_mm, pgd, __va(pud_phys));
                spin_unlock(&init_mm.page_table_lock);
+               pgd_changed = true;
        }
+
+       if (pgd_changed)
+               sync_global_pgds(addr, end);
+
        __flush_tlb_all();
 
        return last_map_addr;
@@ -573,23 +616,7 @@ kernel_physical_mapping_init(unsigned long start,
 void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
                                int acpi, int k8)
 {
-#ifndef CONFIG_NO_BOOTMEM
-       unsigned long bootmap_size, bootmap;
-
-       bootmap_size = bootmem_bootmap_pages(end_pfn)<<PAGE_SHIFT;
-       bootmap = find_e820_area(0, end_pfn<<PAGE_SHIFT, bootmap_size,
-                                PAGE_SIZE);
-       if (bootmap == -1L)
-               panic("Cannot find bootmem map of size %ld\n", bootmap_size);
-       reserve_early(bootmap, bootmap + bootmap_size, "BOOTMAP");
-       /* don't touch min_low_pfn */
-       bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap >> PAGE_SHIFT,
-                                        0, end_pfn);
-       e820_register_active_regions(0, start_pfn, end_pfn);
-       free_bootmem_with_active_regions(0, end_pfn);
-#else
-       e820_register_active_regions(0, start_pfn, end_pfn);
-#endif
+       memblock_x86_register_active_regions(0, start_pfn, end_pfn);
 }
 #endif
 
@@ -799,52 +826,6 @@ void mark_rodata_ro(void)
 
 #endif
 
-int __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
-                                  int flags)
-{
-#ifdef CONFIG_NUMA
-       int nid, next_nid;
-       int ret;
-#endif
-       unsigned long pfn = phys >> PAGE_SHIFT;
-
-       if (pfn >= max_pfn) {
-               /*
-                * This can happen with kdump kernels when accessing
-                * firmware tables:
-                */
-               if (pfn < max_pfn_mapped)
-                       return -EFAULT;
-
-               printk(KERN_ERR "reserve_bootmem: illegal reserve %lx %lu\n",
-                               phys, len);
-               return -EFAULT;
-       }
-
-       /* Should check here against the e820 map to avoid double free */
-#ifdef CONFIG_NUMA
-       nid = phys_to_nid(phys);
-       next_nid = phys_to_nid(phys + len - 1);
-       if (nid == next_nid)
-               ret = reserve_bootmem_node(NODE_DATA(nid), phys, len, flags);
-       else
-               ret = reserve_bootmem(phys, len, flags);
-
-       if (ret != 0)
-               return ret;
-
-#else
-       reserve_bootmem(phys, len, flags);
-#endif
-
-       if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) {
-               dma_reserve += len / PAGE_SIZE;
-               set_dma_reserve(dma_reserve);
-       }
-
-       return 0;
-}
-
 int kern_addr_valid(unsigned long addr)
 {
        unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT;
@@ -1003,6 +984,7 @@ vmemmap_populate(struct page *start_page, unsigned long size, int node)
                }
 
        }
+       sync_global_pgds((unsigned long)start_page, end);
        return 0;
 }
 
index 3ba6e0608c55c3b81300db30e465093f58367f0a..0369843511dc34292b6b0e944fc53bcab7396f8d 100644 (file)
@@ -362,6 +362,11 @@ static inline pte_t * __init early_ioremap_pte(unsigned long addr)
        return &bm_pte[pte_index(addr)];
 }
 
+bool __init is_early_ioremap_ptep(pte_t *ptep)
+{
+       return ptep >= &bm_pte[0] && ptep < &bm_pte[PAGE_SIZE/sizeof(pte_t)];
+}
+
 static unsigned long slot_virt[FIX_BTMAPS_SLOTS] __initdata;
 
 void __init early_ioremap_init(void)
index 970ed579d4e4e86c6265828335b35e35024cfc38..804a3b6c6e14f6aba0cc36616d85ab882a121685 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/string.h>
 #include <linux/module.h>
 #include <linux/nodemask.h>
+#include <linux/memblock.h>
+
 #include <asm/io.h>
 #include <linux/pci_ids.h>
 #include <linux/acpi.h>
@@ -22,7 +24,7 @@
 #include <asm/numa.h>
 #include <asm/mpspec.h>
 #include <asm/apic.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 
 static struct bootnode __initdata nodes[8];
 static nodemask_t __initdata nodes_parsed = NODE_MASK_NONE;
@@ -54,8 +56,8 @@ static __init int find_northbridge(void)
 static __init void early_get_boot_cpu_id(void)
 {
        /*
-        * need to get boot_cpu_id so can use that to create apicid_to_node
-        * in k8_scan_nodes()
+        * need to get the APIC ID of the BSP so can use that to
+        * create apicid_to_node in k8_scan_nodes()
         */
 #ifdef CONFIG_X86_MPPARSE
        /*
@@ -212,7 +214,7 @@ int __init k8_scan_nodes(void)
        bits = boot_cpu_data.x86_coreid_bits;
        cores = (1<<bits);
        apicid_base = 0;
-       /* need to get boot_cpu_id early for system with apicid lifting */
+       /* get the APIC ID of the BSP early for systems with apicid lifting */
        early_get_boot_cpu_id();
        if (boot_cpu_physical_apicid > 0) {
                pr_info("BSP APIC ID: %02x\n", boot_cpu_physical_apicid);
@@ -222,7 +224,7 @@ int __init k8_scan_nodes(void)
        for_each_node_mask(i, node_possible_map) {
                int j;
 
-               e820_register_active_regions(i,
+               memblock_x86_register_active_regions(i,
                                nodes[i].start >> PAGE_SHIFT,
                                nodes[i].end >> PAGE_SHIFT);
                for (j = apicid_base; j < cores + apicid_base; j++)
index b3b531a4f8e587e3560b2087e9c483b2cb1b0f93..d87dd6d042d64309fedac698dd1a5b28a8448594 100644 (file)
@@ -631,6 +631,8 @@ bool kmemcheck_fault(struct pt_regs *regs, unsigned long address,
        if (!pte)
                return false;
 
+       WARN_ON_ONCE(in_nmi());
+
        if (error_code & 2)
                kmemcheck_access(regs, address, KMEMCHECK_WRITE);
        else
index 63c19e27aa6f115badc42f0df6a33ffb1610e6c0..324aa3f072379a46c1f21668680d3b83b9cf10cc 100644 (file)
@@ -9,7 +9,7 @@ static bool opcode_is_prefix(uint8_t b)
                b == 0xf0 || b == 0xf2 || b == 0xf3
                /* Group 2 */
                || b == 0x2e || b == 0x36 || b == 0x3e || b == 0x26
-               || b == 0x64 || b == 0x65 || b == 0x2e || b == 0x3e
+               || b == 0x64 || b == 0x65
                /* Group 3 */
                || b == 0x66
                /* Group 4 */
diff --git a/arch/x86/mm/memblock.c b/arch/x86/mm/memblock.c
new file mode 100644 (file)
index 0000000..aa11693
--- /dev/null
@@ -0,0 +1,348 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/memblock.h>
+#include <linux/bootmem.h>
+#include <linux/mm.h>
+#include <linux/range.h>
+
+/* Check for already reserved areas */
+static bool __init check_with_memblock_reserved_size(u64 *addrp, u64 *sizep, u64 align)
+{
+       struct memblock_region *r;
+       u64 addr = *addrp, last;
+       u64 size = *sizep;
+       bool changed = false;
+
+again:
+       last = addr + size;
+       for_each_memblock(reserved, r) {
+               if (last > r->base && addr < r->base) {
+                       size = r->base - addr;
+                       changed = true;
+                       goto again;
+               }
+               if (last > (r->base + r->size) && addr < (r->base + r->size)) {
+                       addr = round_up(r->base + r->size, align);
+                       size = last - addr;
+                       changed = true;
+                       goto again;
+               }
+               if (last <= (r->base + r->size) && addr >= r->base) {
+                       *sizep = 0;
+                       return false;
+               }
+       }
+       if (changed) {
+               *addrp = addr;
+               *sizep = size;
+       }
+       return changed;
+}
+
+/*
+ * Find next free range after start, and size is returned in *sizep
+ */
+u64 __init memblock_x86_find_in_range_size(u64 start, u64 *sizep, u64 align)
+{
+       struct memblock_region *r;
+
+       for_each_memblock(memory, r) {
+               u64 ei_start = r->base;
+               u64 ei_last = ei_start + r->size;
+               u64 addr;
+
+               addr = round_up(ei_start, align);
+               if (addr < start)
+                       addr = round_up(start, align);
+               if (addr >= ei_last)
+                       continue;
+               *sizep = ei_last - addr;
+               while (check_with_memblock_reserved_size(&addr, sizep, align))
+                       ;
+
+               if (*sizep)
+                       return addr;
+       }
+
+       return MEMBLOCK_ERROR;
+}
+
+static __init struct range *find_range_array(int count)
+{
+       u64 end, size, mem;
+       struct range *range;
+
+       size = sizeof(struct range) * count;
+       end = memblock.current_limit;
+
+       mem = memblock_find_in_range(0, end, size, sizeof(struct range));
+       if (mem == MEMBLOCK_ERROR)
+               panic("can not find more space for range array");
+
+       /*
+        * This range is tempoaray, so don't reserve it, it will not be
+        * overlapped because We will not alloccate new buffer before
+        * We discard this one
+        */
+       range = __va(mem);
+       memset(range, 0, size);
+
+       return range;
+}
+
+static void __init memblock_x86_subtract_reserved(struct range *range, int az)
+{
+       u64 final_start, final_end;
+       struct memblock_region *r;
+
+       /* Take out region array itself at first*/
+       memblock_free_reserved_regions();
+
+       memblock_dbg("Subtract (%ld early reservations)\n", memblock.reserved.cnt);
+
+       for_each_memblock(reserved, r) {
+               memblock_dbg("  [%010llx-%010llx]\n", (u64)r->base, (u64)r->base + r->size - 1);
+               final_start = PFN_DOWN(r->base);
+               final_end = PFN_UP(r->base + r->size);
+               if (final_start >= final_end)
+                       continue;
+               subtract_range(range, az, final_start, final_end);
+       }
+
+       /* Put region array back ? */
+       memblock_reserve_reserved_regions();
+}
+
+struct count_data {
+       int nr;
+};
+
+static int __init count_work_fn(unsigned long start_pfn,
+                               unsigned long end_pfn, void *datax)
+{
+       struct count_data *data = datax;
+
+       data->nr++;
+
+       return 0;
+}
+
+static int __init count_early_node_map(int nodeid)
+{
+       struct count_data data;
+
+       data.nr = 0;
+       work_with_active_regions(nodeid, count_work_fn, &data);
+
+       return data.nr;
+}
+
+int __init __get_free_all_memory_range(struct range **rangep, int nodeid,
+                        unsigned long start_pfn, unsigned long end_pfn)
+{
+       int count;
+       struct range *range;
+       int nr_range;
+
+       count = (memblock.reserved.cnt + count_early_node_map(nodeid)) * 2;
+
+       range = find_range_array(count);
+       nr_range = 0;
+
+       /*
+        * Use early_node_map[] and memblock.reserved.region to get range array
+        * at first
+        */
+       nr_range = add_from_early_node_map(range, count, nr_range, nodeid);
+       subtract_range(range, count, 0, start_pfn);
+       subtract_range(range, count, end_pfn, -1ULL);
+
+       memblock_x86_subtract_reserved(range, count);
+       nr_range = clean_sort_range(range, count);
+
+       *rangep = range;
+       return nr_range;
+}
+
+int __init get_free_all_memory_range(struct range **rangep, int nodeid)
+{
+       unsigned long end_pfn = -1UL;
+
+#ifdef CONFIG_X86_32
+       end_pfn = max_low_pfn;
+#endif
+       return __get_free_all_memory_range(rangep, nodeid, 0, end_pfn);
+}
+
+static u64 __init __memblock_x86_memory_in_range(u64 addr, u64 limit, bool get_free)
+{
+       int i, count;
+       struct range *range;
+       int nr_range;
+       u64 final_start, final_end;
+       u64 free_size;
+       struct memblock_region *r;
+
+       count = (memblock.reserved.cnt + memblock.memory.cnt) * 2;
+
+       range = find_range_array(count);
+       nr_range = 0;
+
+       addr = PFN_UP(addr);
+       limit = PFN_DOWN(limit);
+
+       for_each_memblock(memory, r) {
+               final_start = PFN_UP(r->base);
+               final_end = PFN_DOWN(r->base + r->size);
+               if (final_start >= final_end)
+                       continue;
+               if (final_start >= limit || final_end <= addr)
+                       continue;
+
+               nr_range = add_range(range, count, nr_range, final_start, final_end);
+       }
+       subtract_range(range, count, 0, addr);
+       subtract_range(range, count, limit, -1ULL);
+
+       /* Subtract memblock.reserved.region in range ? */
+       if (!get_free)
+               goto sort_and_count_them;
+       for_each_memblock(reserved, r) {
+               final_start = PFN_DOWN(r->base);
+               final_end = PFN_UP(r->base + r->size);
+               if (final_start >= final_end)
+                       continue;
+               if (final_start >= limit || final_end <= addr)
+                       continue;
+
+               subtract_range(range, count, final_start, final_end);
+       }
+
+sort_and_count_them:
+       nr_range = clean_sort_range(range, count);
+
+       free_size = 0;
+       for (i = 0; i < nr_range; i++)
+               free_size += range[i].end - range[i].start;
+
+       return free_size << PAGE_SHIFT;
+}
+
+u64 __init memblock_x86_free_memory_in_range(u64 addr, u64 limit)
+{
+       return __memblock_x86_memory_in_range(addr, limit, true);
+}
+
+u64 __init memblock_x86_memory_in_range(u64 addr, u64 limit)
+{
+       return __memblock_x86_memory_in_range(addr, limit, false);
+}
+
+void __init memblock_x86_reserve_range(u64 start, u64 end, char *name)
+{
+       if (start == end)
+               return;
+
+       if (WARN_ONCE(start > end, "memblock_x86_reserve_range: wrong range [%#llx, %#llx)\n", start, end))
+               return;
+
+       memblock_dbg("    memblock_x86_reserve_range: [%#010llx-%#010llx] %16s\n", start, end - 1, name);
+
+       memblock_reserve(start, end - start);
+}
+
+void __init memblock_x86_free_range(u64 start, u64 end)
+{
+       if (start == end)
+               return;
+
+       if (WARN_ONCE(start > end, "memblock_x86_free_range: wrong range [%#llx, %#llx)\n", start, end))
+               return;
+
+       memblock_dbg("       memblock_x86_free_range: [%#010llx-%#010llx]\n", start, end - 1);
+
+       memblock_free(start, end - start);
+}
+
+/*
+ * Need to call this function after memblock_x86_register_active_regions,
+ * so early_node_map[] is filled already.
+ */
+u64 __init memblock_x86_find_in_range_node(int nid, u64 start, u64 end, u64 size, u64 align)
+{
+       u64 addr;
+       addr = find_memory_core_early(nid, size, align, start, end);
+       if (addr != MEMBLOCK_ERROR)
+               return addr;
+
+       /* Fallback, should already have start end within node range */
+       return memblock_find_in_range(start, end, size, align);
+}
+
+/*
+ * Finds an active region in the address range from start_pfn to last_pfn and
+ * returns its range in ei_startpfn and ei_endpfn for the memblock entry.
+ */
+static int __init memblock_x86_find_active_region(const struct memblock_region *ei,
+                                 unsigned long start_pfn,
+                                 unsigned long last_pfn,
+                                 unsigned long *ei_startpfn,
+                                 unsigned long *ei_endpfn)
+{
+       u64 align = PAGE_SIZE;
+
+       *ei_startpfn = round_up(ei->base, align) >> PAGE_SHIFT;
+       *ei_endpfn = round_down(ei->base + ei->size, align) >> PAGE_SHIFT;
+
+       /* Skip map entries smaller than a page */
+       if (*ei_startpfn >= *ei_endpfn)
+               return 0;
+
+       /* Skip if map is outside the node */
+       if (*ei_endpfn <= start_pfn || *ei_startpfn >= last_pfn)
+               return 0;
+
+       /* Check for overlaps */
+       if (*ei_startpfn < start_pfn)
+               *ei_startpfn = start_pfn;
+       if (*ei_endpfn > last_pfn)
+               *ei_endpfn = last_pfn;
+
+       return 1;
+}
+
+/* Walk the memblock.memory map and register active regions within a node */
+void __init memblock_x86_register_active_regions(int nid, unsigned long start_pfn,
+                                        unsigned long last_pfn)
+{
+       unsigned long ei_startpfn;
+       unsigned long ei_endpfn;
+       struct memblock_region *r;
+
+       for_each_memblock(memory, r)
+               if (memblock_x86_find_active_region(r, start_pfn, last_pfn,
+                                          &ei_startpfn, &ei_endpfn))
+                       add_active_range(nid, ei_startpfn, ei_endpfn);
+}
+
+/*
+ * Find the hole size (in bytes) in the memory range.
+ * @start: starting address of the memory range to scan
+ * @end: ending address of the memory range to scan
+ */
+u64 __init memblock_x86_hole_size(u64 start, u64 end)
+{
+       unsigned long start_pfn = start >> PAGE_SHIFT;
+       unsigned long last_pfn = end >> PAGE_SHIFT;
+       unsigned long ei_startpfn, ei_endpfn, ram = 0;
+       struct memblock_region *r;
+
+       for_each_memblock(memory, r)
+               if (memblock_x86_find_active_region(r, start_pfn, last_pfn,
+                                          &ei_startpfn, &ei_endpfn))
+                       ram += ei_endpfn - ei_startpfn;
+
+       return end - start - ((u64)ram << PAGE_SHIFT);
+}
index 18d244f702059b59f88b94f8da6a7312f43d58cc..92faf3a1c53e29fbf82767356fdca0508f9b693c 100644 (file)
@@ -6,8 +6,7 @@
 #include <linux/smp.h>
 #include <linux/init.h>
 #include <linux/pfn.h>
-
-#include <asm/e820.h>
+#include <linux/memblock.h>
 
 static u64 patterns[] __initdata = {
        0,
@@ -35,7 +34,7 @@ static void __init reserve_bad_mem(u64 pattern, u64 start_bad, u64 end_bad)
               (unsigned long long) pattern,
               (unsigned long long) start_bad,
               (unsigned long long) end_bad);
-       reserve_early(start_bad, end_bad, "BAD RAM");
+       memblock_x86_reserve_range(start_bad, end_bad, "BAD RAM");
 }
 
 static void __init memtest(u64 pattern, u64 start_phys, u64 size)
@@ -74,7 +73,7 @@ static void __init do_one_pass(u64 pattern, u64 start, u64 end)
        u64 size = 0;
 
        while (start < end) {
-               start = find_e820_area_size(start, &size, 1);
+               start = memblock_x86_find_in_range_size(start, &size, 1);
 
                /* done ? */
                if (start >= end)
index 809baaaf48b18d9f24f953b602001a562f2769c7..84a3e4c9f277d82175b1603dae6b0c9c40dc0aef 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/mm.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/mmzone.h>
 #include <linux/highmem.h>
 #include <linux/initrd.h>
@@ -120,7 +121,7 @@ int __init get_memcfg_numa_flat(void)
 
        node_start_pfn[0] = 0;
        node_end_pfn[0] = max_pfn;
-       e820_register_active_regions(0, 0, max_pfn);
+       memblock_x86_register_active_regions(0, 0, max_pfn);
        memory_present(0, 0, max_pfn);
        node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn);
 
@@ -161,14 +162,14 @@ static void __init allocate_pgdat(int nid)
                NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid];
        else {
                unsigned long pgdat_phys;
-               pgdat_phys = find_e820_area(min_low_pfn<<PAGE_SHIFT,
+               pgdat_phys = memblock_find_in_range(min_low_pfn<<PAGE_SHIFT,
                                 max_pfn_mapped<<PAGE_SHIFT,
                                 sizeof(pg_data_t),
                                 PAGE_SIZE);
                NODE_DATA(nid) = (pg_data_t *)(pfn_to_kaddr(pgdat_phys>>PAGE_SHIFT));
                memset(buf, 0, sizeof(buf));
                sprintf(buf, "NODE_DATA %d",  nid);
-               reserve_early(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf);
+               memblock_x86_reserve_range(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf);
        }
        printk(KERN_DEBUG "allocate_pgdat: node %d NODE_DATA %08lx\n",
                nid, (unsigned long)NODE_DATA(nid));
@@ -291,15 +292,15 @@ static __init unsigned long calculate_numa_remap_pages(void)
                                                 PTRS_PER_PTE);
                node_kva_target <<= PAGE_SHIFT;
                do {
-                       node_kva_final = find_e820_area(node_kva_target,
+                       node_kva_final = memblock_find_in_range(node_kva_target,
                                        ((u64)node_end_pfn[nid])<<PAGE_SHIFT,
                                                ((u64)size)<<PAGE_SHIFT,
                                                LARGE_PAGE_BYTES);
                        node_kva_target -= LARGE_PAGE_BYTES;
-               } while (node_kva_final == -1ULL &&
+               } while (node_kva_final == MEMBLOCK_ERROR &&
                         (node_kva_target>>PAGE_SHIFT) > (node_start_pfn[nid]));
 
-               if (node_kva_final == -1ULL)
+               if (node_kva_final == MEMBLOCK_ERROR)
                        panic("Can not get kva ram\n");
 
                node_remap_size[nid] = size;
@@ -318,15 +319,13 @@ static __init unsigned long calculate_numa_remap_pages(void)
                 *  but we could have some hole in high memory, and it will only
                 *  check page_is_ram(pfn) && !page_is_reserved_early(pfn) to decide
                 *  to use it as free.
-                *  So reserve_early here, hope we don't run out of that array
+                *  So memblock_x86_reserve_range here, hope we don't run out of that array
                 */
-               reserve_early(node_kva_final,
+               memblock_x86_reserve_range(node_kva_final,
                              node_kva_final+(((u64)size)<<PAGE_SHIFT),
                              "KVA RAM");
 
                node_remap_start_pfn[nid] = node_kva_final>>PAGE_SHIFT;
-               remove_active_range(nid, node_remap_start_pfn[nid],
-                                        node_remap_start_pfn[nid] + size);
        }
        printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n",
                        reserve_pages);
@@ -367,14 +366,14 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
 
        kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE);
        do {
-               kva_start_pfn = find_e820_area(kva_target_pfn<<PAGE_SHIFT,
+               kva_start_pfn = memblock_find_in_range(kva_target_pfn<<PAGE_SHIFT,
                                        max_low_pfn<<PAGE_SHIFT,
                                        kva_pages<<PAGE_SHIFT,
                                        PTRS_PER_PTE<<PAGE_SHIFT) >> PAGE_SHIFT;
                kva_target_pfn -= PTRS_PER_PTE;
-       } while (kva_start_pfn == -1UL && kva_target_pfn > min_low_pfn);
+       } while (kva_start_pfn == MEMBLOCK_ERROR && kva_target_pfn > min_low_pfn);
 
-       if (kva_start_pfn == -1UL)
+       if (kva_start_pfn == MEMBLOCK_ERROR)
                panic("Can not get kva space\n");
 
        printk(KERN_INFO "kva_start_pfn ~ %lx max_low_pfn ~ %lx\n",
@@ -382,7 +381,7 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
        printk(KERN_INFO "max_pfn = %lx\n", max_pfn);
 
        /* avoid clash with initrd */
-       reserve_early(kva_start_pfn<<PAGE_SHIFT,
+       memblock_x86_reserve_range(kva_start_pfn<<PAGE_SHIFT,
                      (kva_start_pfn + kva_pages)<<PAGE_SHIFT,
                     "KVA PG");
 #ifdef CONFIG_HIGHMEM
@@ -419,9 +418,6 @@ void __init initmem_init(unsigned long start_pfn, unsigned long end_pfn,
        for_each_online_node(nid) {
                memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
                NODE_DATA(nid)->node_id = nid;
-#ifndef CONFIG_NO_BOOTMEM
-               NODE_DATA(nid)->bdata = &bootmem_node_data[nid];
-#endif
        }
 
        setup_bootmem_allocator();
index a7bcc23ef96c989f5fef986cbd7816dfd551d20e..60f498511dd60b01a9eee62fdc0a69ba80d3082c 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/mmzone.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
@@ -18,7 +19,7 @@
 #include <asm/dma.h>
 #include <asm/numa.h>
 #include <asm/acpi.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 
 struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
 EXPORT_SYMBOL(node_data);
@@ -86,16 +87,16 @@ static int __init allocate_cachealigned_memnodemap(void)
 
        addr = 0x8000;
        nodemap_size = roundup(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
-       nodemap_addr = find_e820_area(addr, max_pfn<<PAGE_SHIFT,
+       nodemap_addr = memblock_find_in_range(addr, max_pfn<<PAGE_SHIFT,
                                      nodemap_size, L1_CACHE_BYTES);
-       if (nodemap_addr == -1UL) {
+       if (nodemap_addr == MEMBLOCK_ERROR) {
                printk(KERN_ERR
                       "NUMA: Unable to allocate Memory to Node hash map\n");
                nodemap_addr = nodemap_size = 0;
                return -1;
        }
        memnodemap = phys_to_virt(nodemap_addr);
-       reserve_early(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP");
+       memblock_x86_reserve_range(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP");
 
        printk(KERN_DEBUG "NUMA: Allocated memnodemap from %lx - %lx\n",
               nodemap_addr, nodemap_addr + nodemap_size);
@@ -171,8 +172,8 @@ static void * __init early_node_mem(int nodeid, unsigned long start,
        if (start < (MAX_DMA32_PFN<<PAGE_SHIFT) &&
            end > (MAX_DMA32_PFN<<PAGE_SHIFT))
                start = MAX_DMA32_PFN<<PAGE_SHIFT;
-       mem = find_e820_area(start, end, size, align);
-       if (mem != -1L)
+       mem = memblock_x86_find_in_range_node(nodeid, start, end, size, align);
+       if (mem != MEMBLOCK_ERROR)
                return __va(mem);
 
        /* extend the search scope */
@@ -181,8 +182,8 @@ static void * __init early_node_mem(int nodeid, unsigned long start,
                start = MAX_DMA32_PFN<<PAGE_SHIFT;
        else
                start = MAX_DMA_PFN<<PAGE_SHIFT;
-       mem = find_e820_area(start, end, size, align);
-       if (mem != -1L)
+       mem = memblock_x86_find_in_range_node(nodeid, start, end, size, align);
+       if (mem != MEMBLOCK_ERROR)
                return __va(mem);
 
        printk(KERN_ERR "Cannot find %lu bytes in node %d\n",
@@ -198,10 +199,6 @@ setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
        unsigned long start_pfn, last_pfn, nodedata_phys;
        const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
        int nid;
-#ifndef CONFIG_NO_BOOTMEM
-       unsigned long bootmap_start, bootmap_pages, bootmap_size;
-       void *bootmap;
-#endif
 
        if (!end)
                return;
@@ -226,7 +223,7 @@ setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
        if (node_data[nodeid] == NULL)
                return;
        nodedata_phys = __pa(node_data[nodeid]);
-       reserve_early(nodedata_phys, nodedata_phys + pgdat_size, "NODE_DATA");
+       memblock_x86_reserve_range(nodedata_phys, nodedata_phys + pgdat_size, "NODE_DATA");
        printk(KERN_INFO "  NODE_DATA [%016lx - %016lx]\n", nodedata_phys,
                nodedata_phys + pgdat_size - 1);
        nid = phys_to_nid(nodedata_phys);
@@ -238,47 +235,6 @@ setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
        NODE_DATA(nodeid)->node_start_pfn = start_pfn;
        NODE_DATA(nodeid)->node_spanned_pages = last_pfn - start_pfn;
 
-#ifndef CONFIG_NO_BOOTMEM
-       NODE_DATA(nodeid)->bdata = &bootmem_node_data[nodeid];
-
-       /*
-        * Find a place for the bootmem map
-        * nodedata_phys could be on other nodes by alloc_bootmem,
-        * so need to sure bootmap_start not to be small, otherwise
-        * early_node_mem will get that with find_e820_area instead
-        * of alloc_bootmem, that could clash with reserved range
-        */
-       bootmap_pages = bootmem_bootmap_pages(last_pfn - start_pfn);
-       bootmap_start = roundup(nodedata_phys + pgdat_size, PAGE_SIZE);
-       /*
-        * SMP_CACHE_BYTES could be enough, but init_bootmem_node like
-        * to use that to align to PAGE_SIZE
-        */
-       bootmap = early_node_mem(nodeid, bootmap_start, end,
-                                bootmap_pages<<PAGE_SHIFT, PAGE_SIZE);
-       if (bootmap == NULL)  {
-               free_early(nodedata_phys, nodedata_phys + pgdat_size);
-               node_data[nodeid] = NULL;
-               return;
-       }
-       bootmap_start = __pa(bootmap);
-       reserve_early(bootmap_start, bootmap_start+(bootmap_pages<<PAGE_SHIFT),
-                       "BOOTMAP");
-
-       bootmap_size = init_bootmem_node(NODE_DATA(nodeid),
-                                        bootmap_start >> PAGE_SHIFT,
-                                        start_pfn, last_pfn);
-
-       printk(KERN_INFO "  bootmap [%016lx -  %016lx] pages %lx\n",
-                bootmap_start, bootmap_start + bootmap_size - 1,
-                bootmap_pages);
-       nid = phys_to_nid(bootmap_start);
-       if (nid != nodeid)
-               printk(KERN_INFO "    bootmap(%d) on node %d\n", nodeid, nid);
-
-       free_bootmem_with_active_regions(nodeid, end);
-#endif
-
        node_set_online(nodeid);
 }
 
@@ -416,7 +372,7 @@ static int __init split_nodes_interleave(u64 addr, u64 max_addr,
                nr_nodes = MAX_NUMNODES;
        }
 
-       size = (max_addr - addr - e820_hole_size(addr, max_addr)) / nr_nodes;
+       size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) / nr_nodes;
        /*
         * Calculate the number of big nodes that can be allocated as a result
         * of consolidating the remainder.
@@ -452,7 +408,7 @@ static int __init split_nodes_interleave(u64 addr, u64 max_addr,
                         * non-reserved memory is less than the per-node size.
                         */
                        while (end - physnodes[i].start -
-                               e820_hole_size(physnodes[i].start, end) < size) {
+                               memblock_x86_hole_size(physnodes[i].start, end) < size) {
                                end += FAKE_NODE_MIN_SIZE;
                                if (end > physnodes[i].end) {
                                        end = physnodes[i].end;
@@ -466,7 +422,7 @@ static int __init split_nodes_interleave(u64 addr, u64 max_addr,
                         * this one must extend to the boundary.
                         */
                        if (end < dma32_end && dma32_end - end -
-                           e820_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
+                           memblock_x86_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
                                end = dma32_end;
 
                        /*
@@ -475,7 +431,7 @@ static int __init split_nodes_interleave(u64 addr, u64 max_addr,
                         * physical node.
                         */
                        if (physnodes[i].end - end -
-                           e820_hole_size(end, physnodes[i].end) < size)
+                           memblock_x86_hole_size(end, physnodes[i].end) < size)
                                end = physnodes[i].end;
 
                        /*
@@ -503,7 +459,7 @@ static u64 __init find_end_of_node(u64 start, u64 max_addr, u64 size)
 {
        u64 end = start + size;
 
-       while (end - start - e820_hole_size(start, end) < size) {
+       while (end - start - memblock_x86_hole_size(start, end) < size) {
                end += FAKE_NODE_MIN_SIZE;
                if (end > max_addr) {
                        end = max_addr;
@@ -532,7 +488,7 @@ static int __init split_nodes_size_interleave(u64 addr, u64 max_addr, u64 size)
         * creates a uniform distribution of node sizes across the entire
         * machine (but not necessarily over physical nodes).
         */
-       min_size = (max_addr - addr - e820_hole_size(addr, max_addr)) /
+       min_size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) /
                                                MAX_NUMNODES;
        min_size = max(min_size, FAKE_NODE_MIN_SIZE);
        if ((min_size & FAKE_NODE_MIN_HASH_MASK) < min_size)
@@ -565,7 +521,7 @@ static int __init split_nodes_size_interleave(u64 addr, u64 max_addr, u64 size)
                         * this one must extend to the boundary.
                         */
                        if (end < dma32_end && dma32_end - end -
-                           e820_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
+                           memblock_x86_hole_size(end, dma32_end) < FAKE_NODE_MIN_SIZE)
                                end = dma32_end;
 
                        /*
@@ -574,7 +530,7 @@ static int __init split_nodes_size_interleave(u64 addr, u64 max_addr, u64 size)
                         * physical node.
                         */
                        if (physnodes[i].end - end -
-                           e820_hole_size(end, physnodes[i].end) < size)
+                           memblock_x86_hole_size(end, physnodes[i].end) < size)
                                end = physnodes[i].end;
 
                        /*
@@ -638,7 +594,7 @@ static int __init numa_emulation(unsigned long start_pfn,
         */
        remove_all_active_ranges();
        for_each_node_mask(i, node_possible_map) {
-               e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
+               memblock_x86_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
                                                nodes[i].end >> PAGE_SHIFT);
                setup_node_bootmem(i, nodes[i].start, nodes[i].end);
        }
@@ -691,7 +647,7 @@ void __init initmem_init(unsigned long start_pfn, unsigned long last_pfn,
        node_set(0, node_possible_map);
        for (i = 0; i < nr_cpu_ids; i++)
                numa_set_node(i, 0);
-       e820_register_active_regions(0, start_pfn, last_pfn);
+       memblock_x86_register_active_regions(0, start_pfn, last_pfn);
        setup_node_bootmem(0, start_pfn << PAGE_SHIFT, last_pfn << PAGE_SHIFT);
 }
 
@@ -703,9 +659,7 @@ unsigned long __init numa_free_all_bootmem(void)
        for_each_online_node(i)
                pages += free_all_bootmem_node(NODE_DATA(i));
 
-#ifdef CONFIG_NO_BOOTMEM
        pages += free_all_memory_core_early(MAX_NUMNODES);
-#endif
 
        return pages;
 }
index 5c4ee422590e5dc23aec0071e642bf246b627565..8be8c7d7bc89759a55059ea440af5b26e3d9e0c9 100644 (file)
@@ -87,7 +87,19 @@ static inline void pgd_list_del(pgd_t *pgd)
 #define UNSHARED_PTRS_PER_PGD                          \
        (SHARED_KERNEL_PMD ? KERNEL_PGD_BOUNDARY : PTRS_PER_PGD)
 
-static void pgd_ctor(pgd_t *pgd)
+
+static void pgd_set_mm(pgd_t *pgd, struct mm_struct *mm)
+{
+       BUILD_BUG_ON(sizeof(virt_to_page(pgd)->index) < sizeof(mm));
+       virt_to_page(pgd)->index = (pgoff_t)mm;
+}
+
+struct mm_struct *pgd_page_get_mm(struct page *page)
+{
+       return (struct mm_struct *)page->index;
+}
+
+static void pgd_ctor(struct mm_struct *mm, pgd_t *pgd)
 {
        /* If the pgd points to a shared pagetable level (either the
           ptes in non-PAE, or shared PMD in PAE), then just copy the
@@ -98,15 +110,13 @@ static void pgd_ctor(pgd_t *pgd)
                clone_pgd_range(pgd + KERNEL_PGD_BOUNDARY,
                                swapper_pg_dir + KERNEL_PGD_BOUNDARY,
                                KERNEL_PGD_PTRS);
-               paravirt_alloc_pmd_clone(__pa(pgd) >> PAGE_SHIFT,
-                                        __pa(swapper_pg_dir) >> PAGE_SHIFT,
-                                        KERNEL_PGD_BOUNDARY,
-                                        KERNEL_PGD_PTRS);
        }
 
        /* list required to sync kernel mapping updates */
-       if (!SHARED_KERNEL_PMD)
+       if (!SHARED_KERNEL_PMD) {
+               pgd_set_mm(pgd, mm);
                pgd_list_add(pgd);
+       }
 }
 
 static void pgd_dtor(pgd_t *pgd)
@@ -272,7 +282,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
         */
        spin_lock_irqsave(&pgd_lock, flags);
 
-       pgd_ctor(pgd);
+       pgd_ctor(mm, pgd);
        pgd_prepopulate_pmd(mm, pgd, pmds);
 
        spin_unlock_irqrestore(&pgd_lock, flags);
index 9324f13492d51bf005921e23bdef80bd67f2d2f1..a17dffd136c143898e91187cbd39d005b05779b6 100644 (file)
@@ -25,6 +25,7 @@
  */
 #include <linux/mm.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/mmzone.h>
 #include <linux/acpi.h>
 #include <linux/nodemask.h>
@@ -264,7 +265,7 @@ int __init get_memcfg_from_srat(void)
                if (node_read_chunk(chunk->nid, chunk))
                        continue;
 
-               e820_register_active_regions(chunk->nid, chunk->start_pfn,
+               memblock_x86_register_active_regions(chunk->nid, chunk->start_pfn,
                                             min(chunk->end_pfn, max_pfn));
        }
        /* for out of order entries in SRAT */
index 9c0d0d399c307678a09668155d9067139ab30416..a35cb9d8b0606bc8f7123cd15f0017972a5e8dda 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/topology.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/mm.h>
 #include <asm/proto.h>
 #include <asm/numa.h>
@@ -98,15 +99,15 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
        unsigned long phys;
 
        length = slit->header.length;
-       phys = find_e820_area(0, max_pfn_mapped<<PAGE_SHIFT, length,
+       phys = memblock_find_in_range(0, max_pfn_mapped<<PAGE_SHIFT, length,
                 PAGE_SIZE);
 
-       if (phys == -1L)
+       if (phys == MEMBLOCK_ERROR)
                panic(" Can not save slit!\n");
 
        acpi_slit = __va(phys);
        memcpy(acpi_slit, slit, length);
-       reserve_early(phys, phys + length, "ACPI SLIT");
+       memblock_x86_reserve_range(phys, phys + length, "ACPI SLIT");
 }
 
 /* Callback for Proximity Domain -> x2APIC mapping */
@@ -324,7 +325,7 @@ static int __init nodes_cover_memory(const struct bootnode *nodes)
                        pxmram = 0;
        }
 
-       e820ram = max_pfn - (e820_hole_size(0, max_pfn<<PAGE_SHIFT)>>PAGE_SHIFT);
+       e820ram = max_pfn - (memblock_x86_hole_size(0, max_pfn<<PAGE_SHIFT)>>PAGE_SHIFT);
        /* We seem to lose 3 pages somewhere. Allow 1M of slack. */
        if ((long)(e820ram - pxmram) >= (1<<(20 - PAGE_SHIFT))) {
                printk(KERN_ERR
@@ -421,7 +422,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
        }
 
        for (i = 0; i < num_node_memblks; i++)
-               e820_register_active_regions(memblk_nodeid[i],
+               memblock_x86_register_active_regions(memblk_nodeid[i],
                                node_memblk_range[i].start >> PAGE_SHIFT,
                                node_memblk_range[i].end >> PAGE_SHIFT);
 
index c03f14ab666742d6960ff3339ebcfe28a003308b..49358481c733235918cde7c576a3332fba50c364 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/smp.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/cpu.h>
 
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
@@ -52,6 +53,8 @@ union smp_flush_state {
    want false sharing in the per cpu data segment. */
 static union smp_flush_state flush_state[NUM_INVALIDATE_TLB_VECTORS];
 
+static DEFINE_PER_CPU_READ_MOSTLY(int, tlb_vector_offset);
+
 /*
  * We cannot call mmdrop() because we are in interrupt context,
  * instead update mm->cpu_vm_mask.
@@ -173,7 +176,7 @@ static void flush_tlb_others_ipi(const struct cpumask *cpumask,
        union smp_flush_state *f;
 
        /* Caller has disabled preemption */
-       sender = smp_processor_id() % NUM_INVALIDATE_TLB_VECTORS;
+       sender = this_cpu_read(tlb_vector_offset);
        f = &flush_state[sender];
 
        /*
@@ -218,6 +221,47 @@ void native_flush_tlb_others(const struct cpumask *cpumask,
        flush_tlb_others_ipi(cpumask, mm, va);
 }
 
+static void __cpuinit calculate_tlb_offset(void)
+{
+       int cpu, node, nr_node_vecs;
+       /*
+        * we are changing tlb_vector_offset for each CPU in runtime, but this
+        * will not cause inconsistency, as the write is atomic under X86. we
+        * might see more lock contentions in a short time, but after all CPU's
+        * tlb_vector_offset are changed, everything should go normal
+        *
+        * Note: if NUM_INVALIDATE_TLB_VECTORS % nr_online_nodes !=0, we might
+        * waste some vectors.
+        **/
+       if (nr_online_nodes > NUM_INVALIDATE_TLB_VECTORS)
+               nr_node_vecs = 1;
+       else
+               nr_node_vecs = NUM_INVALIDATE_TLB_VECTORS/nr_online_nodes;
+
+       for_each_online_node(node) {
+               int node_offset = (node % NUM_INVALIDATE_TLB_VECTORS) *
+                       nr_node_vecs;
+               int cpu_offset = 0;
+               for_each_cpu(cpu, cpumask_of_node(node)) {
+                       per_cpu(tlb_vector_offset, cpu) = node_offset +
+                               cpu_offset;
+                       cpu_offset++;
+                       cpu_offset = cpu_offset % nr_node_vecs;
+               }
+       }
+}
+
+static int tlb_cpuhp_notify(struct notifier_block *n,
+               unsigned long action, void *hcpu)
+{
+       switch (action & 0xf) {
+       case CPU_ONLINE:
+       case CPU_DEAD:
+               calculate_tlb_offset();
+       }
+       return NOTIFY_OK;
+}
+
 static int __cpuinit init_smp_flush(void)
 {
        int i;
@@ -225,6 +269,8 @@ static int __cpuinit init_smp_flush(void)
        for (i = 0; i < ARRAY_SIZE(flush_state); i++)
                raw_spin_lock_init(&flush_state[i].tlbstate_lock);
 
+       calculate_tlb_offset();
+       hotcpu_notifier(tlb_cpuhp_notify, 0);
        return 0;
 }
 core_initcall(init_smp_flush);
index 3855096c59b81910fe827c76151e84bbac836770..2d49d4e19a3619c0be2c7d17a892b8aea582048f 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/ptrace.h>
 #include <asm/uaccess.h>
 #include <asm/stacktrace.h>
+#include <linux/compat.h>
 
 static void backtrace_warning_symbol(void *data, char *msg,
                                     unsigned long symbol)
@@ -48,14 +49,12 @@ static struct stacktrace_ops backtrace_ops = {
        .walk_stack     = print_context_stack,
 };
 
-struct frame_head {
-       struct frame_head *bp;
-       unsigned long ret;
-} __attribute__((packed));
-
-static struct frame_head *dump_user_backtrace(struct frame_head *head)
+#ifdef CONFIG_COMPAT
+static struct stack_frame_ia32 *
+dump_user_backtrace_32(struct stack_frame_ia32 *head)
 {
-       struct frame_head bufhead[2];
+       struct stack_frame_ia32 bufhead[2];
+       struct stack_frame_ia32 *fp;
 
        /* Also check accessibility of one struct frame_head beyond */
        if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
@@ -63,20 +62,66 @@ static struct frame_head *dump_user_backtrace(struct frame_head *head)
        if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
                return NULL;
 
-       oprofile_add_trace(bufhead[0].ret);
+       fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame);
+
+       oprofile_add_trace(bufhead[0].return_address);
+
+       /* frame pointers should strictly progress back up the stack
+       * (towards higher addresses) */
+       if (head >= fp)
+               return NULL;
+
+       return fp;
+}
+
+static inline int
+x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
+{
+       struct stack_frame_ia32 *head;
+
+       /* User process is 32-bit */
+       if (!current || !test_thread_flag(TIF_IA32))
+               return 0;
+
+       head = (struct stack_frame_ia32 *) regs->bp;
+       while (depth-- && head)
+               head = dump_user_backtrace_32(head);
+
+       return 1;
+}
+
+#else
+static inline int
+x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
+{
+       return 0;
+}
+#endif /* CONFIG_COMPAT */
+
+static struct stack_frame *dump_user_backtrace(struct stack_frame *head)
+{
+       struct stack_frame bufhead[2];
+
+       /* Also check accessibility of one struct stack_frame beyond */
+       if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
+               return NULL;
+       if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+               return NULL;
+
+       oprofile_add_trace(bufhead[0].return_address);
 
        /* frame pointers should strictly progress back up the stack
         * (towards higher addresses) */
-       if (head >= bufhead[0].bp)
+       if (head >= bufhead[0].next_frame)
                return NULL;
 
-       return bufhead[0].bp;
+       return bufhead[0].next_frame;
 }
 
 void
 x86_backtrace(struct pt_regs * const regs, unsigned int depth)
 {
-       struct frame_head *head = (struct frame_head *)frame_pointer(regs);
+       struct stack_frame *head = (struct stack_frame *)frame_pointer(regs);
 
        if (!user_mode_vm(regs)) {
                unsigned long stack = kernel_stack_pointer(regs);
@@ -86,6 +131,9 @@ x86_backtrace(struct pt_regs * const regs, unsigned int depth)
                return;
        }
 
+       if (x86_backtrace_32(regs, depth))
+               return;
+
        while (depth-- && head)
                head = dump_user_backtrace(head);
 }
index f1575c9a2572074cad464ae2f9c51ee88e63bce3..4e8baad36d37739e32b71da0be2932924bacfe69 100644 (file)
@@ -695,9 +695,6 @@ static int __init ppro_init(char **cpu_type)
        return 1;
 }
 
-/* in order to get sysfs right */
-static int using_nmi;
-
 int __init op_nmi_init(struct oprofile_operations *ops)
 {
        __u8 vendor = boot_cpu_data.x86_vendor;
@@ -705,8 +702,6 @@ int __init op_nmi_init(struct oprofile_operations *ops)
        char *cpu_type = NULL;
        int ret = 0;
 
-       using_nmi = 0;
-
        if (!cpu_has_apic)
                return -ENODEV;
 
@@ -731,6 +726,12 @@ int __init op_nmi_init(struct oprofile_operations *ops)
                case 0x11:
                        cpu_type = "x86-64/family11h";
                        break;
+               case 0x12:
+                       cpu_type = "x86-64/family12h";
+                       break;
+               case 0x14:
+                       cpu_type = "x86-64/family14h";
+                       break;
                default:
                        return -ENODEV;
                }
@@ -790,13 +791,11 @@ int __init op_nmi_init(struct oprofile_operations *ops)
        if (ret)
                return ret;
 
-       using_nmi = 1;
        printk(KERN_INFO "oprofile: using NMI interrupt.\n");
        return 0;
 }
 
 void op_nmi_exit(void)
 {
-       if (using_nmi)
-               exit_sysfs();
+       exit_sysfs();
 }
index b67a6b5aa8d449ee06e0c22b586b6c51af4d2170..a011bcc0f94331d82c8abfa7d4afdbbd0c59eff5 100644 (file)
@@ -48,31 +48,53 @@ static unsigned long reset_value[NUM_VIRT_COUNTERS];
 
 static u32 ibs_caps;
 
-struct op_ibs_config {
+struct ibs_config {
        unsigned long op_enabled;
        unsigned long fetch_enabled;
        unsigned long max_cnt_fetch;
        unsigned long max_cnt_op;
        unsigned long rand_en;
        unsigned long dispatched_ops;
+       unsigned long branch_target;
 };
 
-static struct op_ibs_config ibs_config;
-static u64 ibs_op_ctl;
+struct ibs_state {
+       u64             ibs_op_ctl;
+       int             branch_target;
+       unsigned long   sample_size;
+};
+
+static struct ibs_config ibs_config;
+static struct ibs_state ibs_state;
 
 /*
  * IBS cpuid feature detection
  */
 
-#define IBS_CPUID_FEATURES      0x8000001b
+#define IBS_CPUID_FEATURES             0x8000001b
 
 /*
  * Same bit mask as for IBS cpuid feature flags (Fn8000_001B_EAX), but
  * bit 0 is used to indicate the existence of IBS.
  */
-#define IBS_CAPS_AVAIL                 (1LL<<0)
-#define IBS_CAPS_RDWROPCNT             (1LL<<3)
-#define IBS_CAPS_OPCNT                 (1LL<<4)
+#define IBS_CAPS_AVAIL                 (1U<<0)
+#define IBS_CAPS_FETCHSAM              (1U<<1)
+#define IBS_CAPS_OPSAM                 (1U<<2)
+#define IBS_CAPS_RDWROPCNT             (1U<<3)
+#define IBS_CAPS_OPCNT                 (1U<<4)
+#define IBS_CAPS_BRNTRGT               (1U<<5)
+#define IBS_CAPS_OPCNTEXT              (1U<<6)
+
+#define IBS_CAPS_DEFAULT               (IBS_CAPS_AVAIL         \
+                                        | IBS_CAPS_FETCHSAM    \
+                                        | IBS_CAPS_OPSAM)
+
+/*
+ * IBS APIC setup
+ */
+#define IBSCTL                         0x1cc
+#define IBSCTL_LVT_OFFSET_VALID                (1ULL<<8)
+#define IBSCTL_LVT_OFFSET_MASK         0x0F
 
 /*
  * IBS randomization macros
@@ -92,12 +114,12 @@ static u32 get_ibs_caps(void)
        /* check IBS cpuid feature flags */
        max_level = cpuid_eax(0x80000000);
        if (max_level < IBS_CPUID_FEATURES)
-               return IBS_CAPS_AVAIL;
+               return IBS_CAPS_DEFAULT;
 
        ibs_caps = cpuid_eax(IBS_CPUID_FEATURES);
        if (!(ibs_caps & IBS_CAPS_AVAIL))
                /* cpuid flags not valid */
-               return IBS_CAPS_AVAIL;
+               return IBS_CAPS_DEFAULT;
 
        return ibs_caps;
 }
@@ -190,8 +212,8 @@ op_amd_handle_ibs(struct pt_regs * const regs,
                rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
                if (ctl & IBS_OP_VAL) {
                        rdmsrl(MSR_AMD64_IBSOPRIP, val);
-                       oprofile_write_reserve(&entry, regs, val,
-                                              IBS_OP_CODE, IBS_OP_SIZE);
+                       oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE,
+                                              ibs_state.sample_size);
                        oprofile_add_data64(&entry, val);
                        rdmsrl(MSR_AMD64_IBSOPDATA, val);
                        oprofile_add_data64(&entry, val);
@@ -203,10 +225,14 @@ op_amd_handle_ibs(struct pt_regs * const regs,
                        oprofile_add_data64(&entry, val);
                        rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
                        oprofile_add_data64(&entry, val);
+                       if (ibs_state.branch_target) {
+                               rdmsrl(MSR_AMD64_IBSBRTARGET, val);
+                               oprofile_add_data(&entry, (unsigned long)val);
+                       }
                        oprofile_write_commit(&entry);
 
                        /* reenable the IRQ */
-                       ctl = op_amd_randomize_ibs_op(ibs_op_ctl);
+                       ctl = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
                        wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
                }
        }
@@ -219,21 +245,32 @@ static inline void op_amd_start_ibs(void)
        if (!ibs_caps)
                return;
 
+       memset(&ibs_state, 0, sizeof(ibs_state));
+
+       /*
+        * Note: Since the max count settings may out of range we
+        * write back the actual used values so that userland can read
+        * it.
+        */
+
        if (ibs_config.fetch_enabled) {
-               val = (ibs_config.max_cnt_fetch >> 4) & IBS_FETCH_MAX_CNT;
+               val = ibs_config.max_cnt_fetch >> 4;
+               val = min(val, IBS_FETCH_MAX_CNT);
+               ibs_config.max_cnt_fetch = val << 4;
                val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
                val |= IBS_FETCH_ENABLE;
                wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
        }
 
        if (ibs_config.op_enabled) {
-               ibs_op_ctl = ibs_config.max_cnt_op >> 4;
+               val = ibs_config.max_cnt_op >> 4;
                if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
                        /*
                         * IbsOpCurCnt not supported.  See
                         * op_amd_randomize_ibs_op() for details.
                         */
-                       ibs_op_ctl = clamp(ibs_op_ctl, 0x0081ULL, 0xFF80ULL);
+                       val = clamp(val, 0x0081ULL, 0xFF80ULL);
+                       ibs_config.max_cnt_op = val << 4;
                } else {
                        /*
                         * The start value is randomized with a
@@ -241,13 +278,24 @@ static inline void op_amd_start_ibs(void)
                         * with the half of the randomized range. Also
                         * avoid underflows.
                         */
-                       ibs_op_ctl = min(ibs_op_ctl + IBS_RANDOM_MAXCNT_OFFSET,
-                                        IBS_OP_MAX_CNT);
+                       val += IBS_RANDOM_MAXCNT_OFFSET;
+                       if (ibs_caps & IBS_CAPS_OPCNTEXT)
+                               val = min(val, IBS_OP_MAX_CNT_EXT);
+                       else
+                               val = min(val, IBS_OP_MAX_CNT);
+                       ibs_config.max_cnt_op =
+                               (val - IBS_RANDOM_MAXCNT_OFFSET) << 4;
+               }
+               val = ((val & ~IBS_OP_MAX_CNT) << 4) | (val & IBS_OP_MAX_CNT);
+               val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0;
+               val |= IBS_OP_ENABLE;
+               ibs_state.ibs_op_ctl = val;
+               ibs_state.sample_size = IBS_OP_SIZE;
+               if (ibs_config.branch_target) {
+                       ibs_state.branch_target = 1;
+                       ibs_state.sample_size++;
                }
-               if (ibs_caps & IBS_CAPS_OPCNT && ibs_config.dispatched_ops)
-                       ibs_op_ctl |= IBS_OP_CNT_CTL;
-               ibs_op_ctl |= IBS_OP_ENABLE;
-               val = op_amd_randomize_ibs_op(ibs_op_ctl);
+               val = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
                wrmsrl(MSR_AMD64_IBSOPCTL, val);
        }
 }
@@ -266,6 +314,70 @@ static void op_amd_stop_ibs(void)
                wrmsrl(MSR_AMD64_IBSOPCTL, 0);
 }
 
+static inline int eilvt_is_available(int offset)
+{
+       /* check if we may assign a vector */
+       return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1);
+}
+
+static inline int ibs_eilvt_valid(void)
+{
+       int offset;
+       u64 val;
+
+       rdmsrl(MSR_AMD64_IBSCTL, val);
+       offset = val & IBSCTL_LVT_OFFSET_MASK;
+
+       if (!(val & IBSCTL_LVT_OFFSET_VALID)) {
+               pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n",
+                      smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
+               return 0;
+       }
+
+       if (!eilvt_is_available(offset)) {
+               pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n",
+                      smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
+               return 0;
+       }
+
+       return 1;
+}
+
+static inline int get_ibs_offset(void)
+{
+       u64 val;
+
+       rdmsrl(MSR_AMD64_IBSCTL, val);
+       if (!(val & IBSCTL_LVT_OFFSET_VALID))
+               return -EINVAL;
+
+       return val & IBSCTL_LVT_OFFSET_MASK;
+}
+
+static void setup_APIC_ibs(void)
+{
+       int offset;
+
+       offset = get_ibs_offset();
+       if (offset < 0)
+               goto failed;
+
+       if (!setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 0))
+               return;
+failed:
+       pr_warn("oprofile: IBS APIC setup failed on cpu #%d\n",
+               smp_processor_id());
+}
+
+static void clear_APIC_ibs(void)
+{
+       int offset;
+
+       offset = get_ibs_offset();
+       if (offset >= 0)
+               setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_FIX, 1);
+}
+
 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
 
 static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
@@ -376,13 +488,13 @@ static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
        }
 
        if (ibs_caps)
-               setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
+               setup_APIC_ibs();
 }
 
 static void op_amd_cpu_shutdown(void)
 {
        if (ibs_caps)
-               setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
+               clear_APIC_ibs();
 }
 
 static int op_amd_check_ctrs(struct pt_regs * const regs,
@@ -445,16 +557,11 @@ static void op_amd_stop(struct op_msrs const * const msrs)
        op_amd_stop_ibs();
 }
 
-static int __init_ibs_nmi(void)
+static int setup_ibs_ctl(int ibs_eilvt_off)
 {
-#define IBSCTL_LVTOFFSETVAL            (1 << 8)
-#define IBSCTL                         0x1cc
        struct pci_dev *cpu_cfg;
        int nodes;
        u32 value = 0;
-       u8 ibs_eilvt_off;
-
-       ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
 
        nodes = 0;
        cpu_cfg = NULL;
@@ -466,24 +573,63 @@ static int __init_ibs_nmi(void)
                        break;
                ++nodes;
                pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
-                                      | IBSCTL_LVTOFFSETVAL);
+                                      | IBSCTL_LVT_OFFSET_VALID);
                pci_read_config_dword(cpu_cfg, IBSCTL, &value);
-               if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
+               if (value != (ibs_eilvt_off | IBSCTL_LVT_OFFSET_VALID)) {
                        pci_dev_put(cpu_cfg);
                        printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
-                               "IBSCTL = 0x%08x", value);
-                       return 1;
+                              "IBSCTL = 0x%08x\n", value);
+                       return -EINVAL;
                }
        } while (1);
 
        if (!nodes) {
-               printk(KERN_DEBUG "No CPU node configured for IBS");
-               return 1;
+               printk(KERN_DEBUG "No CPU node configured for IBS\n");
+               return -ENODEV;
        }
 
        return 0;
 }
 
+static int force_ibs_eilvt_setup(void)
+{
+       int i;
+       int ret;
+
+       /* find the next free available EILVT entry */
+       for (i = 1; i < 4; i++) {
+               if (!eilvt_is_available(i))
+                       continue;
+               ret = setup_ibs_ctl(i);
+               if (ret)
+                       return ret;
+               return 0;
+       }
+
+       printk(KERN_DEBUG "No EILVT entry available\n");
+
+       return -EBUSY;
+}
+
+static int __init_ibs_nmi(void)
+{
+       int ret;
+
+       if (ibs_eilvt_valid())
+               return 0;
+
+       ret = force_ibs_eilvt_setup();
+       if (ret)
+               return ret;
+
+       if (!ibs_eilvt_valid())
+               return -EFAULT;
+
+       pr_err(FW_BUG "workaround enabled for IBS LVT offset\n");
+
+       return 0;
+}
+
 /* initialize the APIC for the IBS interrupts if available */
 static void init_ibs(void)
 {
@@ -521,28 +667,33 @@ static int setup_ibs_files(struct super_block *sb, struct dentry *root)
        /* model specific files */
 
        /* setup some reasonable defaults */
+       memset(&ibs_config, 0, sizeof(ibs_config));
        ibs_config.max_cnt_fetch = 250000;
-       ibs_config.fetch_enabled = 0;
        ibs_config.max_cnt_op = 250000;
-       ibs_config.op_enabled = 0;
-       ibs_config.dispatched_ops = 0;
-
-       dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
-       oprofilefs_create_ulong(sb, dir, "enable",
-                               &ibs_config.fetch_enabled);
-       oprofilefs_create_ulong(sb, dir, "max_count",
-                               &ibs_config.max_cnt_fetch);
-       oprofilefs_create_ulong(sb, dir, "rand_enable",
-                               &ibs_config.rand_en);
-
-       dir = oprofilefs_mkdir(sb, root, "ibs_op");
-       oprofilefs_create_ulong(sb, dir, "enable",
-                               &ibs_config.op_enabled);
-       oprofilefs_create_ulong(sb, dir, "max_count",
-                               &ibs_config.max_cnt_op);
-       if (ibs_caps & IBS_CAPS_OPCNT)
-               oprofilefs_create_ulong(sb, dir, "dispatched_ops",
-                                       &ibs_config.dispatched_ops);
+
+       if (ibs_caps & IBS_CAPS_FETCHSAM) {
+               dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
+               oprofilefs_create_ulong(sb, dir, "enable",
+                                       &ibs_config.fetch_enabled);
+               oprofilefs_create_ulong(sb, dir, "max_count",
+                                       &ibs_config.max_cnt_fetch);
+               oprofilefs_create_ulong(sb, dir, "rand_enable",
+                                       &ibs_config.rand_en);
+       }
+
+       if (ibs_caps & IBS_CAPS_OPSAM) {
+               dir = oprofilefs_mkdir(sb, root, "ibs_op");
+               oprofilefs_create_ulong(sb, dir, "enable",
+                                       &ibs_config.op_enabled);
+               oprofilefs_create_ulong(sb, dir, "max_count",
+                                       &ibs_config.max_cnt_op);
+               if (ibs_caps & IBS_CAPS_OPCNT)
+                       oprofilefs_create_ulong(sb, dir, "dispatched_ops",
+                                               &ibs_config.dispatched_ops);
+               if (ibs_caps & IBS_CAPS_BRNTRGT)
+                       oprofilefs_create_ulong(sb, dir, "branch_target",
+                                               &ibs_config.branch_target);
+       }
 
        return 0;
 }
index b34815408f582bd002854d83c8e5736b6de37b24..13700ec8e2e43587010594fe4e361ac88d29cb85 100644 (file)
@@ -304,7 +304,7 @@ static struct pci_raw_ops pci_olpc_conf = {
 
 int __init pci_olpc_init(void)
 {
-       printk(KERN_INFO "PCI: Using configuration type OLPC\n");
+       printk(KERN_INFO "PCI: Using configuration type OLPC XO-1\n");
        raw_pci_ops = &pci_olpc_conf;
        is_lx = is_geode_lx();
        return 0;
index 7d46c84414188bf401777e4d65a9652e5cc09fa5..63b83ceebd1a0984403af50aaefe29331d5f3132 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/console.h>
 #include <linux/pci.h>
 #include <linux/gfp.h>
+#include <linux/memblock.h>
 
 #include <xen/xen.h>
 #include <xen/interface/xen.h>
@@ -1183,6 +1184,8 @@ asmlinkage void __init xen_start_kernel(void)
        local_irq_disable();
        early_boot_irqs_off();
 
+       memblock_init();
+
        xen_raw_console_write("mapping kernel into physical memory\n");
        pgd = xen_setup_kernel_pagetable(pgd, xen_start_info->nr_pages);
 
index 42086ac406af21da6d281687625684c0dddbe11c..f72d18c692217d67c45e57c16ea8585904097d1f 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/vmalloc.h>
 #include <linux/module.h>
 #include <linux/gfp.h>
+#include <linux/memblock.h>
 
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
@@ -55,6 +56,7 @@
 #include <asm/e820.h>
 #include <asm/linkage.h>
 #include <asm/page.h>
+#include <asm/init.h>
 
 #include <asm/xen/hypercall.h>
 #include <asm/xen/hypervisor.h>
@@ -359,7 +361,8 @@ void make_lowmem_page_readonly(void *vaddr)
        unsigned int level;
 
        pte = lookup_address(address, &level);
-       BUG_ON(pte == NULL);
+       if (pte == NULL)
+               return;         /* vaddr missing */
 
        ptev = pte_wrprotect(*pte);
 
@@ -374,7 +377,8 @@ void make_lowmem_page_readwrite(void *vaddr)
        unsigned int level;
 
        pte = lookup_address(address, &level);
-       BUG_ON(pte == NULL);
+       if (pte == NULL)
+               return;         /* vaddr missing */
 
        ptev = pte_mkwrite(*pte);
 
@@ -1508,13 +1512,25 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd)
 #endif
 }
 
-#ifdef CONFIG_X86_32
 static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
 {
+       unsigned long pfn = pte_pfn(pte);
+
+#ifdef CONFIG_X86_32
        /* If there's an existing pte, then don't allow _PAGE_RW to be set */
        if (pte_val_ma(*ptep) & _PAGE_PRESENT)
                pte = __pte_ma(((pte_val_ma(*ptep) & _PAGE_RW) | ~_PAGE_RW) &
                               pte_val_ma(pte));
+#endif
+
+       /*
+        * If the new pfn is within the range of the newly allocated
+        * kernel pagetable, and it isn't being mapped into an
+        * early_ioremap fixmap slot, make sure it is RO.
+        */
+       if (!is_early_ioremap_ptep(ptep) &&
+           pfn >= e820_table_start && pfn < e820_table_end)
+               pte = pte_wrprotect(pte);
 
        return pte;
 }
@@ -1527,7 +1543,6 @@ static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
 
        xen_set_pte(ptep, pte);
 }
-#endif
 
 static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
 {
@@ -1814,7 +1829,7 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
        __xen_write_cr3(true, __pa(pgd));
        xen_mc_issue(PARAVIRT_LAZY_CPU);
 
-       reserve_early(__pa(xen_start_info->pt_base),
+       memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
                      __pa(xen_start_info->pt_base +
                           xen_start_info->nr_pt_frames * PAGE_SIZE),
                      "XEN PAGETABLES");
@@ -1852,7 +1867,7 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
 
        pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(swapper_pg_dir)));
 
-       reserve_early(__pa(xen_start_info->pt_base),
+       memblock_x86_reserve_range(__pa(xen_start_info->pt_base),
                      __pa(xen_start_info->pt_base +
                           xen_start_info->nr_pt_frames * PAGE_SIZE),
                      "XEN PAGETABLES");
@@ -1969,14 +1984,9 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
        .alloc_pte = xen_alloc_pte_init,
        .release_pte = xen_release_pte_init,
        .alloc_pmd = xen_alloc_pmd_init,
-       .alloc_pmd_clone = paravirt_nop,
        .release_pmd = xen_release_pmd_init,
 
-#ifdef CONFIG_X86_64
-       .set_pte = xen_set_pte,
-#else
        .set_pte = xen_set_pte_init,
-#endif
        .set_pte_at = xen_set_pte_at,
        .set_pmd = xen_set_pmd_hyper,
 
index a013ec9d0c5410ebd8d1dbdaeec76fb182722d86..22471001b74c48dc26e499a549d4eb8549ed48e3 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <asm/xen/hypervisor.h>
 #include <xen/xen.h>
+#include <asm/iommu_table.h>
 
 int xen_swiotlb __read_mostly;
 
@@ -56,3 +57,7 @@ void __init pci_xen_swiotlb_init(void)
                dma_ops = &xen_swiotlb_dma_ops;
        }
 }
+IOMMU_INIT_FINISH(pci_xen_swiotlb_detect,
+                 0,
+                 pci_xen_swiotlb_init,
+                 0);
index 328b003054267d074610fdce51c39b063fae48e6..9729c903404b1633a0eaed2b06bd0cfadabf9aa7 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/pm.h>
+#include <linux/memblock.h>
 
 #include <asm/elf.h>
 #include <asm/vdso.h>
@@ -129,7 +130,7 @@ char * __init xen_memory_setup(void)
         *  - xen_start_info
         * See comment above "struct start_info" in <xen/interface/xen.h>
         */
-       reserve_early(__pa(xen_start_info->mfn_list),
+       memblock_x86_reserve_range(__pa(xen_start_info->mfn_list),
                      __pa(xen_start_info->pt_base),
                        "XEN START INFO");
 
index e0500646585d4a5d7bc64338798ba955494ab387..23e061b9327bc45b9ba64024559c87202f7602b0 100644 (file)
@@ -224,7 +224,7 @@ static noinline int xen_spin_lock_slow(struct arch_spinlock *lock, bool irq_enab
                        goto out;
                }
 
-               flags = __raw_local_save_flags();
+               flags = arch_local_save_flags();
                if (irq_enable) {
                        ADD_STATS(taken_slow_irqenable, 1);
                        raw_local_irq_enable();
diff --git a/arch/xtensa/include/asm/irqflags.h b/arch/xtensa/include/asm/irqflags.h
new file mode 100644 (file)
index 0000000..dae9a8b
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Xtensa IRQ flags handling functions
+ *
+ * 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.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IRQFLAGS_H
+#define _XTENSA_IRQFLAGS_H
+
+#include <linux/types.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+       unsigned long flags;
+       asm volatile("rsr %0,"__stringify(PS) : "=a" (flags));
+       return flags;
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+       unsigned long flags;
+       asm volatile("rsil %0, "__stringify(LOCKLEVEL)
+                    : "=a" (flags) :: "memory");
+       return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+       arch_local_irq_save();
+}
+
+static inline void arch_local_irq_enable(void)
+{
+       unsigned long flags;
+       asm volatile("rsil %0, 0" : "=a" (flags) :: "memory");
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+       asm volatile("wsr %0, "__stringify(PS)" ; rsync"
+                    :: "a" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+       return (flags & 0xf) != 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+       return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* _XTENSA_IRQFLAGS_H */
index 62b1e8f3c13c38bb99e23bd457cc61e858628abe..1e7e09ab6cd7836802b7442b5436e3a25a775640 100644 (file)
 #define _XTENSA_SYSTEM_H
 
 #include <linux/stringify.h>
+#include <linux/irqflags.h>
 
 #include <asm/processor.h>
 
-/* interrupt control */
-
-#define local_save_flags(x)                                            \
-       __asm__ __volatile__ ("rsr %0,"__stringify(PS) : "=a" (x));
-#define local_irq_restore(x)   do {                                    \
-       __asm__ __volatile__ ("wsr %0, "__stringify(PS)" ; rsync"       \
-                             :: "a" (x) : "memory"); } while(0);
-#define local_irq_save(x)      do {                                    \
-       __asm__ __volatile__ ("rsil %0, "__stringify(LOCKLEVEL)         \
-                             : "=a" (x) :: "memory");} while(0);
-
-static inline void local_irq_disable(void)
-{
-       unsigned long flags;
-       __asm__ __volatile__ ("rsil %0, "__stringify(LOCKLEVEL)
-                             : "=a" (flags) :: "memory");
-}
-static inline void local_irq_enable(void)
-{
-       unsigned long flags;
-       __asm__ __volatile__ ("rsil %0, 0" : "=a" (flags) :: "memory");
-
-}
-
-static inline int irqs_disabled(void)
-{
-       unsigned long flags;
-       local_save_flags(flags);
-       return flags & 0xf;
-}
-
-
 #define smp_read_barrier_depends() do { } while(0)
 #define read_barrier_depends() do { } while(0)
 
index c64a5d387de51d9e0e4c2225a8ae348c05b331e8..87508886cbbdadb28d2843047cdbbb90e7656b77 100644 (file)
@@ -92,7 +92,7 @@ int show_interrupts(struct seq_file *p, void *v)
                for_each_online_cpu(j)
                        seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
 #endif
-               seq_printf(p, " %14s", irq_desc[i].chip->typename);
+               seq_printf(p, " %14s", irq_desc[i].chip->name);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index 82d58829ba591eeef13a3ed4eca96b8a019c4d85..0c00870553a3fca2c58c325b780b92689fc677a6 100644 (file)
@@ -426,7 +426,7 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
        /*
         * fill in all the output members
         */
-       hdr->device_status = status_byte(rq->errors);
+       hdr->device_status = rq->errors & 0xff;
        hdr->transport_status = host_byte(rq->errors);
        hdr->driver_status = driver_byte(rq->errors);
        hdr->info = 0;
index 249f903cc453b201270bb2db5c33be1856a5d324..873818d48e86939b9492a158a3cd86a9d16b97b9 100644 (file)
@@ -614,7 +614,7 @@ static const u32 S8[64] = {
 #define T3(x) pt[2 * (x) + 2]
 #define T4(x) pt[2 * (x) + 3]
 
-#define PC2(a, b, c, d) (T4(d) | T3(c) | T2(b) | T1(a))
+#define DES_PC2(a, b, c, d) (T4(d) | T3(c) | T2(b) | T1(a))
 
 /*
  * Encryption key expansion
@@ -639,22 +639,22 @@ unsigned long des_ekey(u32 *pe, const u8 *k)
        b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b];
        a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a];
 
-       pe[15 * 2 + 0] = PC2(a, b, c, d); d = rs[d];
-       pe[14 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[13 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[12 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[11 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[10 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[ 9 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[ 8 * 2 + 0] = PC2(d, a, b, c); c = rs[c];
-       pe[ 7 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[ 6 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[ 5 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[ 4 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[ 3 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[ 2 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[ 1 * 2 + 0] = PC2(c, d, a, b); b = rs[b];
-       pe[ 0 * 2 + 0] = PC2(b, c, d, a);
+       pe[15 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d];
+       pe[14 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[13 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[12 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[11 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[10 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[ 9 * 2 + 0] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[ 8 * 2 + 0] = DES_PC2(d, a, b, c); c = rs[c];
+       pe[ 7 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[ 6 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[ 5 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[ 4 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[ 3 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[ 2 * 2 + 0] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[ 1 * 2 + 0] = DES_PC2(c, d, a, b); b = rs[b];
+       pe[ 0 * 2 + 0] = DES_PC2(b, c, d, a);
 
        /* Check if first half is weak */
        w  = (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]);
@@ -670,22 +670,22 @@ unsigned long des_ekey(u32 *pe, const u8 *k)
        /* Check if second half is weak */
        w |= (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]);
 
-       pe[15 * 2 + 1] = PC2(a, b, c, d); d = rs[d];
-       pe[14 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[13 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[12 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[11 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[10 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[ 9 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[ 8 * 2 + 1] = PC2(d, a, b, c); c = rs[c];
-       pe[ 7 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[ 6 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[ 5 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[ 4 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[ 3 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[ 2 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[ 1 * 2 + 1] = PC2(c, d, a, b); b = rs[b];
-       pe[ 0 * 2 + 1] = PC2(b, c, d, a);
+       pe[15 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d];
+       pe[14 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[13 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[12 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[11 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[10 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[ 9 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[ 8 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c];
+       pe[ 7 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[ 6 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[ 5 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[ 4 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[ 3 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[ 2 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[ 1 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b];
+       pe[ 0 * 2 + 1] = DES_PC2(b, c, d, a);
 
        /* Fixup: 2413 5768 -> 1357 2468 */
        for (d = 0; d < 16; ++d) {
@@ -722,22 +722,22 @@ static void dkey(u32 *pe, const u8 *k)
        b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b];
        a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a];
 
-       pe[ 0 * 2] = PC2(a, b, c, d); d = rs[d];
-       pe[ 1 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[ 2 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[ 3 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[ 4 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[ 5 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[ 6 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[ 7 * 2] = PC2(d, a, b, c); c = rs[c];
-       pe[ 8 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[ 9 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[10 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[11 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[12 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[13 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[14 * 2] = PC2(c, d, a, b); b = rs[b];
-       pe[15 * 2] = PC2(b, c, d, a);
+       pe[ 0 * 2] = DES_PC2(a, b, c, d); d = rs[d];
+       pe[ 1 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[ 2 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[ 3 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[ 4 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[ 5 * 2] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[ 6 * 2] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[ 7 * 2] = DES_PC2(d, a, b, c); c = rs[c];
+       pe[ 8 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[ 9 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[10 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[11 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[12 * 2] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[13 * 2] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[14 * 2] = DES_PC2(c, d, a, b); b = rs[b];
+       pe[15 * 2] = DES_PC2(b, c, d, a);
 
        /* Skip to next table set */
        pt += 512;
@@ -747,22 +747,22 @@ static void dkey(u32 *pe, const u8 *k)
        b = k[2]; b &= 0xe0; b >>= 4; b |= k[6] & 0xf0; b = pc1[b + 1];
        a = k[3]; a &= 0xe0; a >>= 4; a |= k[7] & 0xf0; a = pc1[a + 1];
 
-       pe[ 0 * 2 + 1] = PC2(a, b, c, d); d = rs[d];
-       pe[ 1 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[ 2 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[ 3 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[ 4 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[ 5 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
-       pe[ 6 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
-       pe[ 7 * 2 + 1] = PC2(d, a, b, c); c = rs[c];
-       pe[ 8 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[ 9 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[10 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[11 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[12 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
-       pe[13 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
-       pe[14 * 2 + 1] = PC2(c, d, a, b); b = rs[b];
-       pe[15 * 2 + 1] = PC2(b, c, d, a);
+       pe[ 0 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d];
+       pe[ 1 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[ 2 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[ 3 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[ 4 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[ 5 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c]; b = rs[b];
+       pe[ 6 * 2 + 1] = DES_PC2(b, c, d, a); a = rs[a]; d = rs[d];
+       pe[ 7 * 2 + 1] = DES_PC2(d, a, b, c); c = rs[c];
+       pe[ 8 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[ 9 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[10 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[11 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[12 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b]; a = rs[a];
+       pe[13 * 2 + 1] = DES_PC2(a, b, c, d); d = rs[d]; c = rs[c];
+       pe[14 * 2 + 1] = DES_PC2(c, d, a, b); b = rs[b];
+       pe[15 * 2 + 1] = DES_PC2(b, c, d, a);
 
        /* Fixup: 2413 5768 -> 1357 2468 */
        for (d = 0; d < 16; ++d) {
index 6b115f6c43133c211acd79c68a83785506a4357a..6afceb3d4034edef3a868722e41af82873057e74 100644 (file)
 #include <linux/slab.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
+#include <asm/mwait.h>
 
 #define ACPI_PROCESSOR_AGGREGATOR_CLASS        "acpi_pad"
 #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
 #define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
 static DEFINE_MUTEX(isolated_cpus_lock);
 
-#define MWAIT_SUBSTATE_MASK    (0xf)
-#define MWAIT_CSTATE_MASK      (0xf)
-#define MWAIT_SUBSTATE_SIZE    (4)
-#define CPUID_MWAIT_LEAF (5)
-#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
-#define CPUID5_ECX_INTERRUPT_BREAK     (0x2)
 static unsigned long power_saving_mwait_eax;
 
 static unsigned char tsc_detected_unstable;
index d31590e7011bf895092535d15af5df6cc2e62df5..2737b97522052e7a653eb9c7622132a07a6bcded 100644 (file)
@@ -298,7 +298,7 @@ int amba_device_register(struct amba_device *dev, struct resource *parent)
 
                amba_put_disable_pclk(dev);
 
-               if (cid == 0xb105f00d)
+               if (cid == AMBA_CID)
                        dev->periphid = pid;
 
                if (!dev->periphid)
index d5df04a395ca6e9eb057cfb7496b3101ffee69b7..c501af5b12b959209bde413d9b8bbe35f7be5068 100644 (file)
@@ -99,7 +99,7 @@ obj-$(CONFIG_ATA_GENERIC)     += ata_generic.o
 # Should be last libata driver
 obj-$(CONFIG_PATA_LEGACY)      += pata_legacy.o
 
-libata-objs    := libata-core.o libata-scsi.o libata-eh.o
+libata-y       := libata-core.o libata-scsi.o libata-eh.o libata-transport.o
 libata-$(CONFIG_ATA_SFF)       += libata-sff.o
 libata-$(CONFIG_SATA_PMP)      += libata-pmp.o
 libata-$(CONFIG_ATA_ACPI)      += libata-acpi.o
index 99d0e5a511482215a7b3c59ffaed9f0827cfa2b1..328826381a2dc38def47aba259e78da11b24b5b0 100644 (file)
@@ -1208,9 +1208,6 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
                ata_port_pbar_desc(ap, AHCI_PCI_BAR,
                                   0x100 + ap->port_no * 0x80, "port");
 
-               /* set initial link pm policy */
-               ap->pm_policy = NOT_AVAILABLE;
-
                /* set enclosure management message type */
                if (ap->flags & ATA_FLAG_EM)
                        ap->em_message_type = hpriv->em_msg_type;
index e5fdeebf9ef0610d6f43999baefc4fd06fcd354b..329cbbb91284ad4dd3b7e4f486ea82f2737ae1b3 100644 (file)
@@ -72,6 +72,7 @@ enum {
        AHCI_CMD_RESET          = (1 << 8),
        AHCI_CMD_CLR_BUSY       = (1 << 10),
 
+       RX_FIS_PIO_SETUP        = 0x20, /* offset of PIO Setup FIS data */
        RX_FIS_D2H_REG          = 0x40, /* offset of D2H Register FIS data */
        RX_FIS_SDB              = 0x58, /* offset of SDB FIS data */
        RX_FIS_UNK              = 0x60, /* offset of Unknown FIS data */
@@ -201,7 +202,6 @@ enum {
        AHCI_HFLAG_MV_PATA              = (1 << 4), /* PATA port */
        AHCI_HFLAG_NO_MSI               = (1 << 5), /* no PCI MSI */
        AHCI_HFLAG_NO_PMP               = (1 << 6), /* no PMP */
-       AHCI_HFLAG_NO_HOTPLUG           = (1 << 7), /* ignore PxSERR.DIAG.N */
        AHCI_HFLAG_SECT255              = (1 << 8), /* max 255 sectors */
        AHCI_HFLAG_YES_NCQ              = (1 << 9), /* force NCQ cap on */
        AHCI_HFLAG_NO_SUSPEND           = (1 << 10), /* don't suspend */
@@ -216,7 +216,7 @@ enum {
        AHCI_FLAG_COMMON                = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
                                          ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
                                          ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
-                                         ATA_FLAG_IPM,
+                                         ATA_FLAG_LPM,
 
        ICH_MAP                         = 0x90, /* ICH MAP register */
 
index 84b643270e7af5c49d8a73db78f6e6230ceabf7b..6fef1fa75c549ea3a442f617693882313c826844 100644 (file)
@@ -129,9 +129,6 @@ static int __init ahci_probe(struct platform_device *pdev)
                ata_port_desc(ap, "mmio %pR", mem);
                ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
 
-               /* set initial link pm policy */
-               ap->pm_policy = NOT_AVAILABLE;
-
                /* set enclosure management message type */
                if (ap->flags & ATA_FLAG_EM)
                        ap->em_message_type = hpriv->em_msg_type;
index cc5f7726bde704bb4931bfce4d58666e41555db5..6981f7680a006493c66ba66c5e90fff9b05985b3 100644 (file)
@@ -35,6 +35,7 @@
 enum {
        ATA_GEN_CLASS_MATCH             = (1 << 0),
        ATA_GEN_FORCE_DMA               = (1 << 1),
+       ATA_GEN_INTEL_IDER              = (1 << 2),
 };
 
 /**
@@ -108,6 +109,49 @@ static struct ata_port_operations generic_port_ops = {
 
 static int all_generic_ide;            /* Set to claim all devices */
 
+/**
+ *     is_intel_ider           -       identify intel IDE-R devices
+ *     @dev: PCI device
+ *
+ *     Distinguish Intel IDE-R controller devices from other Intel IDE
+ *     devices. IDE-R devices have no timing registers and are in
+ *     most respects virtual. They should be driven by the ata_generic
+ *     driver.
+ *
+ *     IDE-R devices have PCI offset 0xF8.L as zero, later Intel ATA has
+ *     it non zero. All Intel ATA has 0x40 writable (timing), but it is
+ *     not writable on IDE-R devices (this is guaranteed).
+ */
+
+static int is_intel_ider(struct pci_dev *dev)
+{
+       /* For Intel IDE the value at 0xF8 is only zero on IDE-R
+          interfaces */
+       u32 r;
+       u16 t;
+
+       /* Check the manufacturing ID, it will be zero for IDE-R */
+       pci_read_config_dword(dev, 0xF8, &r);
+       /* Not IDE-R: punt so that ata_(old)piix gets it */
+       if (r != 0)
+               return 0;
+       /* 0xF8 will also be zero on some early Intel IDE devices
+          but they will have a sane timing register */
+       pci_read_config_word(dev, 0x40, &t);
+       if (t != 0)
+               return 0;
+       /* Finally check if the timing register is writable so that
+          we eliminate any early devices hot-docked in a docking
+          station */
+       pci_write_config_word(dev, 0x40, 1);
+       pci_read_config_word(dev, 0x40, &t);
+       if (t) {
+               pci_write_config_word(dev, 0x40, 0);
+               return 0;
+       }
+       return 1;
+}
+
 /**
  *     ata_generic_init                -       attach generic IDE
  *     @dev: PCI device found
@@ -134,6 +178,10 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
        if ((id->driver_data & ATA_GEN_CLASS_MATCH) && all_generic_ide == 0)
                return -ENODEV;
 
+       if (id->driver_data & ATA_GEN_INTEL_IDER)
+               if (!is_intel_ider(dev))
+                       return -ENODEV;
+
        /* Devices that need care */
        if (dev->vendor == PCI_VENDOR_ID_UMC &&
            dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
@@ -186,7 +234,11 @@ static struct pci_device_id ata_generic[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2),  },
        { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_3),  },
        { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_5),  },
-#endif 
+#endif
+       /* Intel, IDE class device */
+       { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+         PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 
+         .driver_data = ATA_GEN_INTEL_IDER },
        /* Must come last. If you add entries adjust this table appropriately */
        { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL),
          .driver_data = ATA_GEN_CLASS_MATCH },
index d712675d0a9657d3cc7742b74220aaf05d0fa537..6cb14ca8ee853f44683062c9b5b1274afa50e336 100644 (file)
@@ -158,7 +158,6 @@ struct piix_map_db {
 struct piix_host_priv {
        const int *map;
        u32 saved_iocfg;
-       spinlock_t sidpr_lock;  /* FIXME: remove once locking in EH is fixed */
        void __iomem *sidpr;
 };
 
@@ -175,6 +174,8 @@ static int piix_sidpr_scr_read(struct ata_link *link,
                               unsigned int reg, u32 *val);
 static int piix_sidpr_scr_write(struct ata_link *link,
                                unsigned int reg, u32 val);
+static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                             unsigned hints);
 static bool piix_irq_check(struct ata_port *ap);
 #ifdef CONFIG_PM
 static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
@@ -209,6 +210,8 @@ static const struct pci_device_id piix_pci_tbl[] = {
        { 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        /* Intel ICH3 (E7500/1) UDMA 100 */
        { 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+       /* Intel ICH4-L */
+       { 0x8086, 0x24C1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        /* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */
        { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
        { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
@@ -348,11 +351,22 @@ static struct ata_port_operations ich_pata_ops = {
        .set_dmamode            = ich_set_dmamode,
 };
 
+static struct device_attribute *piix_sidpr_shost_attrs[] = {
+       &dev_attr_link_power_management_policy,
+       NULL
+};
+
+static struct scsi_host_template piix_sidpr_sht = {
+       ATA_BMDMA_SHT(DRV_NAME),
+       .shost_attrs            = piix_sidpr_shost_attrs,
+};
+
 static struct ata_port_operations piix_sidpr_sata_ops = {
        .inherits               = &piix_sata_ops,
        .hardreset              = sata_std_hardreset,
        .scr_read               = piix_sidpr_scr_read,
        .scr_write              = piix_sidpr_scr_write,
+       .set_lpm                = piix_sidpr_set_lpm,
 };
 
 static const struct piix_map_db ich5_map_db = {
@@ -956,15 +970,12 @@ static int piix_sidpr_scr_read(struct ata_link *link,
                               unsigned int reg, u32 *val)
 {
        struct piix_host_priv *hpriv = link->ap->host->private_data;
-       unsigned long flags;
 
        if (reg >= ARRAY_SIZE(piix_sidx_map))
                return -EINVAL;
 
-       spin_lock_irqsave(&hpriv->sidpr_lock, flags);
        piix_sidpr_sel(link, reg);
        *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
-       spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
        return 0;
 }
 
@@ -972,18 +983,21 @@ static int piix_sidpr_scr_write(struct ata_link *link,
                                unsigned int reg, u32 val)
 {
        struct piix_host_priv *hpriv = link->ap->host->private_data;
-       unsigned long flags;
 
        if (reg >= ARRAY_SIZE(piix_sidx_map))
                return -EINVAL;
 
-       spin_lock_irqsave(&hpriv->sidpr_lock, flags);
        piix_sidpr_sel(link, reg);
        iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
-       spin_unlock_irqrestore(&hpriv->sidpr_lock, flags);
        return 0;
 }
 
+static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                             unsigned hints)
+{
+       return sata_link_scr_lpm(link, policy, false);
+}
+
 static bool piix_irq_check(struct ata_port *ap)
 {
        if (unlikely(!ap->ioaddr.bmdma_addr))
@@ -1543,6 +1557,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
        struct device *dev = &pdev->dev;
        struct ata_port_info port_info[2];
        const struct ata_port_info *ppi[] = { &port_info[0], &port_info[1] };
+       struct scsi_host_template *sht = &piix_sht;
        unsigned long port_flags;
        struct ata_host *host;
        struct piix_host_priv *hpriv;
@@ -1577,7 +1592,6 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
        hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
        if (!hpriv)
                return -ENOMEM;
-       spin_lock_init(&hpriv->sidpr_lock);
 
        /* Save IOCFG, this will be used for cable detection, quirk
         * detection and restoration on detach.  This is necessary
@@ -1612,6 +1626,8 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
                rc = piix_init_sidpr(host);
                if (rc)
                        return rc;
+               if (host->ports[0]->ops == &piix_sidpr_sata_ops)
+                       sht = &piix_sidpr_sht;
        }
 
        /* apply IOCFG bit18 quirk */
@@ -1638,7 +1654,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
        host->flags |= ATA_HOST_PARALLEL_SCAN;
 
        pci_set_master(pdev);
-       return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, &piix_sht);
+       return ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht);
 }
 
 static void piix_remove_one(struct pci_dev *pdev)
index 8eea309ea21231fcb50ff0498a366ff8a8a1dcf7..ebc08d65b3dd04c9af94da0d7146d3a165ce9803 100644 (file)
@@ -56,9 +56,8 @@ MODULE_PARM_DESC(skip_host_reset, "skip global host reset (0=don't skip, 1=skip)
 module_param_named(ignore_sss, ahci_ignore_sss, int, 0444);
 MODULE_PARM_DESC(ignore_sss, "Ignore staggered spinup flag (0=don't ignore, 1=ignore)");
 
-static int ahci_enable_alpm(struct ata_port *ap,
-               enum link_pm policy);
-static void ahci_disable_alpm(struct ata_port *ap);
+static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                       unsigned hints);
 static ssize_t ahci_led_show(struct ata_port *ap, char *buf);
 static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
                              size_t size);
@@ -164,8 +163,7 @@ struct ata_port_operations ahci_ops = {
        .pmp_attach             = ahci_pmp_attach,
        .pmp_detach             = ahci_pmp_detach,
 
-       .enable_pm              = ahci_enable_alpm,
-       .disable_pm             = ahci_disable_alpm,
+       .set_lpm                = ahci_set_lpm,
        .em_show                = ahci_led_show,
        .em_store               = ahci_led_store,
        .sw_activity_show       = ahci_activity_show,
@@ -569,7 +567,7 @@ int ahci_stop_engine(struct ata_port *ap)
        writel(tmp, port_mmio + PORT_CMD);
 
        /* wait for engine to stop. This could be as long as 500 msec */
-       tmp = ata_wait_register(port_mmio + PORT_CMD,
+       tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
                                PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
        if (tmp & PORT_CMD_LIST_ON)
                return -EIO;
@@ -616,7 +614,7 @@ static int ahci_stop_fis_rx(struct ata_port *ap)
        writel(tmp, port_mmio + PORT_CMD);
 
        /* wait for completion, spec says 500ms, give it 1000 */
-       tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
+       tmp = ata_wait_register(ap, port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
                                PORT_CMD_FIS_ON, 10, 1000);
        if (tmp & PORT_CMD_FIS_ON)
                return -EBUSY;
@@ -642,127 +640,56 @@ static void ahci_power_up(struct ata_port *ap)
        writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
 }
 
-static void ahci_disable_alpm(struct ata_port *ap)
+static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                       unsigned int hints)
 {
+       struct ata_port *ap = link->ap;
        struct ahci_host_priv *hpriv = ap->host->private_data;
-       void __iomem *port_mmio = ahci_port_base(ap);
-       u32 cmd;
        struct ahci_port_priv *pp = ap->private_data;
-
-       /* IPM bits should be disabled by libata-core */
-       /* get the existing command bits */
-       cmd = readl(port_mmio + PORT_CMD);
-
-       /* disable ALPM and ASP */
-       cmd &= ~PORT_CMD_ASP;
-       cmd &= ~PORT_CMD_ALPE;
-
-       /* force the interface back to active */
-       cmd |= PORT_CMD_ICC_ACTIVE;
-
-       /* write out new cmd value */
-       writel(cmd, port_mmio + PORT_CMD);
-       cmd = readl(port_mmio + PORT_CMD);
-
-       /* wait 10ms to be sure we've come out of any low power state */
-       msleep(10);
-
-       /* clear out any PhyRdy stuff from interrupt status */
-       writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
-
-       /* go ahead and clean out PhyRdy Change from Serror too */
-       ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
-
-       /*
-        * Clear flag to indicate that we should ignore all PhyRdy
-        * state changes
-        */
-       hpriv->flags &= ~AHCI_HFLAG_NO_HOTPLUG;
-
-       /*
-        * Enable interrupts on Phy Ready.
-        */
-       pp->intr_mask |= PORT_IRQ_PHYRDY;
-       writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
-
-       /*
-        * don't change the link pm policy - we can be called
-        * just to turn of link pm temporarily
-        */
-}
-
-static int ahci_enable_alpm(struct ata_port *ap,
-       enum link_pm policy)
-{
-       struct ahci_host_priv *hpriv = ap->host->private_data;
        void __iomem *port_mmio = ahci_port_base(ap);
-       u32 cmd;
-       struct ahci_port_priv *pp = ap->private_data;
-       u32 asp;
 
-       /* Make sure the host is capable of link power management */
-       if (!(hpriv->cap & HOST_CAP_ALPM))
-               return -EINVAL;
-
-       switch (policy) {
-       case MAX_PERFORMANCE:
-       case NOT_AVAILABLE:
+       if (policy != ATA_LPM_MAX_POWER) {
                /*
-                * if we came here with NOT_AVAILABLE,
-                * it just means this is the first time we
-                * have tried to enable - default to max performance,
-                * and let the user go to lower power modes on request.
+                * Disable interrupts on Phy Ready. This keeps us from
+                * getting woken up due to spurious phy ready
+                * interrupts.
                 */
-               ahci_disable_alpm(ap);
-               return 0;
-       case MIN_POWER:
-               /* configure HBA to enter SLUMBER */
-               asp = PORT_CMD_ASP;
-               break;
-       case MEDIUM_POWER:
-               /* configure HBA to enter PARTIAL */
-               asp = 0;
-               break;
-       default:
-               return -EINVAL;
+               pp->intr_mask &= ~PORT_IRQ_PHYRDY;
+               writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+
+               sata_link_scr_lpm(link, policy, false);
        }
 
-       /*
-        * Disable interrupts on Phy Ready. This keeps us from
-        * getting woken up due to spurious phy ready interrupts
-        * TBD - Hot plug should be done via polling now, is
-        * that even supported?
-        */
-       pp->intr_mask &= ~PORT_IRQ_PHYRDY;
-       writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+       if (hpriv->cap & HOST_CAP_ALPM) {
+               u32 cmd = readl(port_mmio + PORT_CMD);
 
-       /*
-        * Set a flag to indicate that we should ignore all PhyRdy
-        * state changes since these can happen now whenever we
-        * change link state
-        */
-       hpriv->flags |= AHCI_HFLAG_NO_HOTPLUG;
+               if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
+                       cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
+                       cmd |= PORT_CMD_ICC_ACTIVE;
 
-       /* get the existing command bits */
-       cmd = readl(port_mmio + PORT_CMD);
+                       writel(cmd, port_mmio + PORT_CMD);
+                       readl(port_mmio + PORT_CMD);
 
-       /*
-        * Set ASP based on Policy
-        */
-       cmd |= asp;
+                       /* wait 10ms to be sure we've come out of LPM state */
+                       ata_msleep(ap, 10);
+               } else {
+                       cmd |= PORT_CMD_ALPE;
+                       if (policy == ATA_LPM_MIN_POWER)
+                               cmd |= PORT_CMD_ASP;
 
-       /*
-        * Setting this bit will instruct the HBA to aggressively
-        * enter a lower power link state when it's appropriate and
-        * based on the value set above for ASP
-        */
-       cmd |= PORT_CMD_ALPE;
+                       /* write out new cmd value */
+                       writel(cmd, port_mmio + PORT_CMD);
+               }
+       }
 
-       /* write out new cmd value */
-       writel(cmd, port_mmio + PORT_CMD);
-       cmd = readl(port_mmio + PORT_CMD);
+       if (policy == ATA_LPM_MAX_POWER) {
+               sata_link_scr_lpm(link, policy, false);
+
+               /* turn PHYRDY IRQ back on */
+               pp->intr_mask |= PORT_IRQ_PHYRDY;
+               writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+       }
 
-       /* IPM bits should be set by libata-core */
        return 0;
 }
 
@@ -813,7 +740,7 @@ static void ahci_start_port(struct ata_port *ap)
                                                               emp->led_state,
                                                               4);
                                if (rc == -EBUSY)
-                                       msleep(1);
+                                       ata_msleep(ap, 1);
                                else
                                        break;
                        }
@@ -872,7 +799,7 @@ int ahci_reset_controller(struct ata_host *host)
                 * reset must complete within 1 second, or
                 * the hardware should be considered fried.
                 */
-               tmp = ata_wait_register(mmio + HOST_CTL, HOST_RESET,
+               tmp = ata_wait_register(NULL, mmio + HOST_CTL, HOST_RESET,
                                        HOST_RESET, 10, 1000);
 
                if (tmp & HOST_RESET) {
@@ -1252,7 +1179,7 @@ int ahci_kick_engine(struct ata_port *ap)
        writel(tmp, port_mmio + PORT_CMD);
 
        rc = 0;
-       tmp = ata_wait_register(port_mmio + PORT_CMD,
+       tmp = ata_wait_register(ap, port_mmio + PORT_CMD,
                                PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
        if (tmp & PORT_CMD_CLO)
                rc = -EIO;
@@ -1282,8 +1209,8 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
        writel(1, port_mmio + PORT_CMD_ISSUE);
 
        if (timeout_msec) {
-               tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
-                                       1, timeout_msec);
+               tmp = ata_wait_register(ap, port_mmio + PORT_CMD_ISSUE,
+                                       0x1, 0x1, 1, timeout_msec);
                if (tmp & 0x1) {
                        ahci_kick_engine(ap);
                        return -EBUSY;
@@ -1330,7 +1257,7 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
        }
 
        /* spec says at least 5us, but be generous and sleep for 1ms */
-       msleep(1);
+       ata_msleep(ap, 1);
 
        /* issue the second D2H Register FIS */
        tf.ctl &= ~ATA_SRST;
@@ -1660,15 +1587,10 @@ static void ahci_port_intr(struct ata_port *ap)
        if (unlikely(resetting))
                status &= ~PORT_IRQ_BAD_PMP;
 
-       /* If we are getting PhyRdy, this is
-        * just a power state change, we should
-        * clear out this, plus the PhyRdy/Comm
-        * Wake bits from Serror
-        */
-       if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
-               (status & PORT_IRQ_PHYRDY)) {
+       /* if LPM is enabled, PHYRDY doesn't mean anything */
+       if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) {
                status &= ~PORT_IRQ_PHYRDY;
-               ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
+               ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
        }
 
        if (unlikely(status & PORT_IRQ_ERROR)) {
@@ -1830,12 +1752,24 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
 static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc)
 {
        struct ahci_port_priv *pp = qc->ap->private_data;
-       u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+       u8 *rx_fis = pp->rx_fis;
 
        if (pp->fbs_enabled)
-               d2h_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
+               rx_fis += qc->dev->link->pmp * AHCI_RX_FIS_SZ;
+
+       /*
+        * After a successful execution of an ATA PIO data-in command,
+        * the device doesn't send D2H Reg FIS to update the TF and
+        * the host should take TF and E_Status from the preceding PIO
+        * Setup FIS.
+        */
+       if (qc->tf.protocol == ATA_PROT_PIO && qc->dma_dir == DMA_FROM_DEVICE &&
+           !(qc->flags & ATA_QCFLAG_FAILED)) {
+               ata_tf_from_fis(rx_fis + RX_FIS_PIO_SETUP, &qc->result_tf);
+               qc->result_tf.command = (rx_fis + RX_FIS_PIO_SETUP)[15];
+       } else
+               ata_tf_from_fis(rx_fis + RX_FIS_D2H_REG, &qc->result_tf);
 
-       ata_tf_from_fis(d2h_fis, &qc->result_tf);
        return true;
 }
 
index 932eaee5024527f4e617064726e39db808c17e87..7f77c67d267ca454f63b5501ab1bb82d5fe9f16d 100644 (file)
@@ -68,7 +68,7 @@
 #include <linux/ratelimit.h>
 
 #include "libata.h"
-
+#include "libata-transport.h"
 
 /* debounce timing parameters in msecs { interval, duration, timeout } */
 const unsigned long sata_deb_timing_normal[]           = {   5,  100, 2000 };
@@ -91,8 +91,6 @@ const struct ata_port_operations sata_port_ops = {
 static unsigned int ata_dev_init_params(struct ata_device *dev,
                                        u16 heads, u16 sectors);
 static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
-static unsigned int ata_dev_set_feature(struct ata_device *dev,
-                                       u8 enable, u8 feature);
 static void ata_dev_xfermask(struct ata_device *dev);
 static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
 
@@ -1017,7 +1015,7 @@ const char *ata_mode_string(unsigned long xfer_mask)
        return "<n/a>";
 }
 
-static const char *sata_spd_string(unsigned int spd)
+const char *sata_spd_string(unsigned int spd)
 {
        static const char * const spd_str[] = {
                "1.5 Gbps",
@@ -1030,182 +1028,6 @@ static const char *sata_spd_string(unsigned int spd)
        return spd_str[spd - 1];
 }
 
-static int ata_dev_set_dipm(struct ata_device *dev, enum link_pm policy)
-{
-       struct ata_link *link = dev->link;
-       struct ata_port *ap = link->ap;
-       u32 scontrol;
-       unsigned int err_mask;
-       int rc;
-
-       /*
-        * disallow DIPM for drivers which haven't set
-        * ATA_FLAG_IPM.  This is because when DIPM is enabled,
-        * phy ready will be set in the interrupt status on
-        * state changes, which will cause some drivers to
-        * think there are errors - additionally drivers will
-        * need to disable hot plug.
-        */
-       if (!(ap->flags & ATA_FLAG_IPM) || !ata_dev_enabled(dev)) {
-               ap->pm_policy = NOT_AVAILABLE;
-               return -EINVAL;
-       }
-
-       /*
-        * For DIPM, we will only enable it for the
-        * min_power setting.
-        *
-        * Why?  Because Disks are too stupid to know that
-        * If the host rejects a request to go to SLUMBER
-        * they should retry at PARTIAL, and instead it
-        * just would give up.  So, for medium_power to
-        * work at all, we need to only allow HIPM.
-        */
-       rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
-       if (rc)
-               return rc;
-
-       switch (policy) {
-       case MIN_POWER:
-               /* no restrictions on IPM transitions */
-               scontrol &= ~(0x3 << 8);
-               rc = sata_scr_write(link, SCR_CONTROL, scontrol);
-               if (rc)
-                       return rc;
-
-               /* enable DIPM */
-               if (dev->flags & ATA_DFLAG_DIPM)
-                       err_mask = ata_dev_set_feature(dev,
-                                       SETFEATURES_SATA_ENABLE, SATA_DIPM);
-               break;
-       case MEDIUM_POWER:
-               /* allow IPM to PARTIAL */
-               scontrol &= ~(0x1 << 8);
-               scontrol |= (0x2 << 8);
-               rc = sata_scr_write(link, SCR_CONTROL, scontrol);
-               if (rc)
-                       return rc;
-
-               /*
-                * we don't have to disable DIPM since IPM flags
-                * disallow transitions to SLUMBER, which effectively
-                * disable DIPM if it does not support PARTIAL
-                */
-               break;
-       case NOT_AVAILABLE:
-       case MAX_PERFORMANCE:
-               /* disable all IPM transitions */
-               scontrol |= (0x3 << 8);
-               rc = sata_scr_write(link, SCR_CONTROL, scontrol);
-               if (rc)
-                       return rc;
-
-               /*
-                * we don't have to disable DIPM since IPM flags
-                * disallow all transitions which effectively
-                * disable DIPM anyway.
-                */
-               break;
-       }
-
-       /* FIXME: handle SET FEATURES failure */
-       (void) err_mask;
-
-       return 0;
-}
-
-/**
- *     ata_dev_enable_pm - enable SATA interface power management
- *     @dev:  device to enable power management
- *     @policy: the link power management policy
- *
- *     Enable SATA Interface power management.  This will enable
- *     Device Interface Power Management (DIPM) for min_power
- *     policy, and then call driver specific callbacks for
- *     enabling Host Initiated Power management.
- *
- *     Locking: Caller.
- *     Returns: -EINVAL if IPM is not supported, 0 otherwise.
- */
-void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy)
-{
-       int rc = 0;
-       struct ata_port *ap = dev->link->ap;
-
-       /* set HIPM first, then DIPM */
-       if (ap->ops->enable_pm)
-               rc = ap->ops->enable_pm(ap, policy);
-       if (rc)
-               goto enable_pm_out;
-       rc = ata_dev_set_dipm(dev, policy);
-
-enable_pm_out:
-       if (rc)
-               ap->pm_policy = MAX_PERFORMANCE;
-       else
-               ap->pm_policy = policy;
-       return /* rc */;        /* hopefully we can use 'rc' eventually */
-}
-
-#ifdef CONFIG_PM
-/**
- *     ata_dev_disable_pm - disable SATA interface power management
- *     @dev: device to disable power management
- *
- *     Disable SATA Interface power management.  This will disable
- *     Device Interface Power Management (DIPM) without changing
- *     policy,  call driver specific callbacks for disabling Host
- *     Initiated Power management.
- *
- *     Locking: Caller.
- *     Returns: void
- */
-static void ata_dev_disable_pm(struct ata_device *dev)
-{
-       struct ata_port *ap = dev->link->ap;
-
-       ata_dev_set_dipm(dev, MAX_PERFORMANCE);
-       if (ap->ops->disable_pm)
-               ap->ops->disable_pm(ap);
-}
-#endif /* CONFIG_PM */
-
-void ata_lpm_schedule(struct ata_port *ap, enum link_pm policy)
-{
-       ap->pm_policy = policy;
-       ap->link.eh_info.action |= ATA_EH_LPM;
-       ap->link.eh_info.flags |= ATA_EHI_NO_AUTOPSY;
-       ata_port_schedule_eh(ap);
-}
-
-#ifdef CONFIG_PM
-static void ata_lpm_enable(struct ata_host *host)
-{
-       struct ata_link *link;
-       struct ata_port *ap;
-       struct ata_device *dev;
-       int i;
-
-       for (i = 0; i < host->n_ports; i++) {
-               ap = host->ports[i];
-               ata_for_each_link(link, ap, EDGE) {
-                       ata_for_each_dev(dev, link, ALL)
-                               ata_dev_disable_pm(dev);
-               }
-       }
-}
-
-static void ata_lpm_disable(struct ata_host *host)
-{
-       int i;
-
-       for (i = 0; i < host->n_ports; i++) {
-               struct ata_port *ap = host->ports[i];
-               ata_lpm_schedule(ap, ap->pm_policy);
-       }
-}
-#endif /* CONFIG_PM */
-
 /**
  *     ata_dev_classify - determine device type based on ATA-spec signature
  *     @tf: ATA taskfile register set for device to be identified
@@ -1806,8 +1628,14 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
                }
        }
 
+       if (ap->ops->error_handler)
+               ata_eh_release(ap);
+
        rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout));
 
+       if (ap->ops->error_handler)
+               ata_eh_acquire(ap);
+
        ata_sff_flush_pio_task(ap);
 
        if (!rc) {
@@ -2564,13 +2392,6 @@ int ata_dev_configure(struct ata_device *dev)
        if (dev->flags & ATA_DFLAG_LBA48)
                dev->max_sectors = ATA_MAX_SECTORS_LBA48;
 
-       if (!(dev->horkage & ATA_HORKAGE_IPM)) {
-               if (ata_id_has_hipm(dev->id))
-                       dev->flags |= ATA_DFLAG_HIPM;
-               if (ata_id_has_dipm(dev->id))
-                       dev->flags |= ATA_DFLAG_DIPM;
-       }
-
        /* Limit PATA drive on SATA cable bridge transfers to udma5,
           200 sectors */
        if (ata_dev_knobble(dev)) {
@@ -2591,13 +2412,6 @@ int ata_dev_configure(struct ata_device *dev)
                dev->max_sectors = min_t(unsigned int, ATA_MAX_SECTORS_128,
                                         dev->max_sectors);
 
-       if (ata_dev_blacklisted(dev) & ATA_HORKAGE_IPM) {
-               dev->horkage |= ATA_HORKAGE_IPM;
-
-               /* reset link pm_policy for this port to no pm */
-               ap->pm_policy = MAX_PERFORMANCE;
-       }
-
        if (ap->ops->dev_config)
                ap->ops->dev_config(dev);
 
@@ -3596,7 +3410,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
                        warned = 1;
                }
 
-               msleep(50);
+               ata_msleep(link->ap, 50);
        }
 }
 
@@ -3617,7 +3431,7 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
 int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
                                int (*check_ready)(struct ata_link *link))
 {
-       msleep(ATA_WAIT_AFTER_RESET);
+       ata_msleep(link->ap, ATA_WAIT_AFTER_RESET);
 
        return ata_wait_ready(link, deadline, check_ready);
 }
@@ -3628,7 +3442,7 @@ int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
  *     @params: timing parameters { interval, duratinon, timeout } in msec
  *     @deadline: deadline jiffies for the operation
  *
-     Make sure SStatus of @link reaches stable state, determined by
+ *     Make sure SStatus of @link reaches stable state, determined by
  *     holding the same value where DET is not 1 for @duration polled
  *     every @interval, before @timeout.  Timeout constraints the
  *     beginning of the stable state.  Because DET gets stuck at 1 on
@@ -3665,7 +3479,7 @@ int sata_link_debounce(struct ata_link *link, const unsigned long *params,
        last_jiffies = jiffies;
 
        while (1) {
-               msleep(interval);
+               ata_msleep(link->ap, interval);
                if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
                        return rc;
                cur &= 0xf;
@@ -3730,7 +3544,7 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
                 * immediately after resuming.  Delay 200ms before
                 * debouncing.
                 */
-               msleep(200);
+               ata_msleep(link->ap, 200);
 
                /* is SControl restored correctly? */
                if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
@@ -3759,6 +3573,72 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
        return rc != -EINVAL ? rc : 0;
 }
 
+/**
+ *     sata_link_scr_lpm - manipulate SControl IPM and SPM fields
+ *     @link: ATA link to manipulate SControl for
+ *     @policy: LPM policy to configure
+ *     @spm_wakeup: initiate LPM transition to active state
+ *
+ *     Manipulate the IPM field of the SControl register of @link
+ *     according to @policy.  If @policy is ATA_LPM_MAX_POWER and
+ *     @spm_wakeup is %true, the SPM field is manipulated to wake up
+ *     the link.  This function also clears PHYRDY_CHG before
+ *     returning.
+ *
+ *     LOCKING:
+ *     EH context.
+ *
+ *     RETURNS:
+ *     0 on succes, -errno otherwise.
+ */
+int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                     bool spm_wakeup)
+{
+       struct ata_eh_context *ehc = &link->eh_context;
+       bool woken_up = false;
+       u32 scontrol;
+       int rc;
+
+       rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+       if (rc)
+               return rc;
+
+       switch (policy) {
+       case ATA_LPM_MAX_POWER:
+               /* disable all LPM transitions */
+               scontrol |= (0x3 << 8);
+               /* initiate transition to active state */
+               if (spm_wakeup) {
+                       scontrol |= (0x4 << 12);
+                       woken_up = true;
+               }
+               break;
+       case ATA_LPM_MED_POWER:
+               /* allow LPM to PARTIAL */
+               scontrol &= ~(0x1 << 8);
+               scontrol |= (0x2 << 8);
+               break;
+       case ATA_LPM_MIN_POWER:
+               /* no restrictions on LPM transitions */
+               scontrol &= ~(0x3 << 8);
+               break;
+       default:
+               WARN_ON(1);
+       }
+
+       rc = sata_scr_write(link, SCR_CONTROL, scontrol);
+       if (rc)
+               return rc;
+
+       /* give the link time to transit out of LPM state */
+       if (woken_up)
+               msleep(10);
+
+       /* clear PHYRDY_CHG from SError */
+       ehc->i.serror &= ~SERR_PHYRDY_CHG;
+       return sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
+}
+
 /**
  *     ata_std_prereset - prepare for reset
  *     @link: ATA link to be reset
@@ -3868,7 +3748,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
        /* Couldn't find anything in SATA I/II specs, but AHCI-1.1
         * 10.4.2 says at least 1 ms.
         */
-       msleep(1);
+       ata_msleep(link->ap, 1);
 
        /* bring link back */
        rc = sata_link_resume(link, timing, deadline);
@@ -4551,6 +4431,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
        DPRINTK("EXIT, err_mask=%x\n", err_mask);
        return err_mask;
 }
+
 /**
  *     ata_dev_set_feature - Issue SET FEATURES - SATA FEATURES
  *     @dev: Device to which command will be sent
@@ -4566,8 +4447,7 @@ static unsigned int ata_dev_set_xfermode(struct ata_device *dev)
  *     RETURNS:
  *     0 on success, AC_ERR_* mask otherwise.
  */
-static unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable,
-                                       u8 feature)
+unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature)
 {
        struct ata_taskfile tf;
        unsigned int err_mask;
@@ -4943,8 +4823,13 @@ static void ata_verify_xfer(struct ata_queued_cmd *qc)
  *     ata_qc_complete - Complete an active ATA command
  *     @qc: Command to complete
  *
- *     Indicate to the mid and upper layers that an ATA
- *     command has completed, with either an ok or not-ok status.
+ *     Indicate to the mid and upper layers that an ATA command has
+ *     completed, with either an ok or not-ok status.
+ *
+ *     Refrain from calling this function multiple times when
+ *     successfully completing multiple NCQ commands.
+ *     ata_qc_complete_multiple() should be used instead, which will
+ *     properly update IRQ expect state.
  *
  *     LOCKING:
  *     spin_lock_irqsave(host lock)
@@ -5037,6 +4922,10 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
  *     requests normally.  ap->qc_active and @qc_active is compared
  *     and commands are completed accordingly.
  *
+ *     Always use this function when completing multiple NCQ commands
+ *     from IRQ handlers instead of calling ata_qc_complete()
+ *     multiple times to keep IRQ expect status properly in sync.
+ *
  *     LOCKING:
  *     spin_lock_irqsave(host lock)
  *
@@ -5421,12 +5310,6 @@ int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
        unsigned int ehi_flags = ATA_EHI_QUIET;
        int rc;
 
-       /*
-        * disable link pm on all ports before requesting
-        * any pm activity
-        */
-       ata_lpm_enable(host);
-
        /*
         * On some hardware, device fails to respond after spun down
         * for suspend.  As the device won't be used before being
@@ -5460,9 +5343,6 @@ void ata_host_resume(struct ata_host *host)
        ata_host_request_pm(host, PMSG_ON, ATA_EH_RESET,
                            ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
        host->dev->power.power_state = PMSG_ON;
-
-       /* reenable link pm */
-       ata_lpm_disable(host);
 }
 #endif
 
@@ -5517,7 +5397,8 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
        int i;
 
        /* clear everything except for devices */
-       memset(link, 0, offsetof(struct ata_link, device[0]));
+       memset((void *)link + ATA_LINK_CLEAR_BEGIN, 0,
+              ATA_LINK_CLEAR_END - ATA_LINK_CLEAR_BEGIN);
 
        link->ap = ap;
        link->pmp = pmp;
@@ -5591,7 +5472,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
        ap = kzalloc(sizeof(*ap), GFP_KERNEL);
        if (!ap)
                return NULL;
-
+       
        ap->pflags |= ATA_PFLAG_INITIALIZING;
        ap->lock = &host->lock;
        ap->print_id = -1;
@@ -5695,6 +5576,7 @@ struct ata_host *ata_host_alloc(struct device *dev, int max_ports)
        dev_set_drvdata(dev, host);
 
        spin_lock_init(&host->lock);
+       mutex_init(&host->eh_mutex);
        host->dev = dev;
        host->n_ports = max_ports;
 
@@ -5992,6 +5874,7 @@ void ata_host_init(struct ata_host *host, struct device *dev,
                   unsigned long flags, struct ata_port_operations *ops)
 {
        spin_lock_init(&host->lock);
+       mutex_init(&host->eh_mutex);
        host->dev = dev;
        host->flags = flags;
        host->ops = ops;
@@ -6022,7 +5905,7 @@ static void async_port_probe(void *data, async_cookie_t cookie)
                spin_lock_irqsave(ap->lock, flags);
 
                ehi->probe_mask |= ATA_ALL_DEVICES;
-               ehi->action |= ATA_EH_RESET | ATA_EH_LPM;
+               ehi->action |= ATA_EH_RESET;
                ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
 
                ap->pflags &= ~ATA_PFLAG_INITIALIZING;
@@ -6093,9 +5976,18 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
        for (i = 0; i < host->n_ports; i++)
                host->ports[i]->print_id = ata_print_id++;
 
+       
+       /* Create associated sysfs transport objects  */
+       for (i = 0; i < host->n_ports; i++) {
+               rc = ata_tport_add(host->dev,host->ports[i]);
+               if (rc) {
+                       goto err_tadd;
+               }
+       }
+
        rc = ata_scsi_add_hosts(host, sht);
        if (rc)
-               return rc;
+               goto err_tadd;
 
        /* associate with ACPI nodes */
        ata_acpi_associate(host);
@@ -6136,6 +6028,13 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
        }
 
        return 0;
+
+ err_tadd:
+       while (--i >= 0) {
+               ata_tport_delete(host->ports[i]);
+       }
+       return rc;
+
 }
 
 /**
@@ -6226,6 +6125,13 @@ static void ata_port_detach(struct ata_port *ap)
        cancel_rearming_delayed_work(&ap->hotplug_task);
 
  skip_eh:
+       if (ap->pmp_link) {
+               int i;
+               for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+                       ata_tlink_delete(&ap->pmp_link[i]);
+       }
+       ata_tport_delete(ap);
+
        /* remove the associated SCSI host */
        scsi_remove_host(ap->scsi_host);
 }
@@ -6542,7 +6448,7 @@ static void __init ata_parse_force_param(void)
 
 static int __init ata_init(void)
 {
-       int rc = -ENOMEM;
+       int rc;
 
        ata_parse_force_param();
 
@@ -6552,12 +6458,25 @@ static int __init ata_init(void)
                return rc;
        }
 
+       libata_transport_init();
+       ata_scsi_transport_template = ata_attach_transport();
+       if (!ata_scsi_transport_template) {
+               ata_sff_exit();
+               rc = -ENOMEM;
+               goto err_out;
+       }               
+
        printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
        return 0;
+
+err_out:
+       return rc;
 }
 
 static void __exit ata_exit(void)
 {
+       ata_release_transport(ata_scsi_transport_template);
+       libata_transport_exit();
        ata_sff_exit();
        kfree(ata_force_tbl);
 }
@@ -6572,8 +6491,36 @@ int ata_ratelimit(void)
        return __ratelimit(&ratelimit);
 }
 
+/**
+ *     ata_msleep - ATA EH owner aware msleep
+ *     @ap: ATA port to attribute the sleep to
+ *     @msecs: duration to sleep in milliseconds
+ *
+ *     Sleeps @msecs.  If the current task is owner of @ap's EH, the
+ *     ownership is released before going to sleep and reacquired
+ *     after the sleep is complete.  IOW, other ports sharing the
+ *     @ap->host will be allowed to own the EH while this task is
+ *     sleeping.
+ *
+ *     LOCKING:
+ *     Might sleep.
+ */
+void ata_msleep(struct ata_port *ap, unsigned int msecs)
+{
+       bool owns_eh = ap && ap->host->eh_owner == current;
+
+       if (owns_eh)
+               ata_eh_release(ap);
+
+       msleep(msecs);
+
+       if (owns_eh)
+               ata_eh_acquire(ap);
+}
+
 /**
  *     ata_wait_register - wait until register value changes
+ *     @ap: ATA port to wait register for, can be NULL
  *     @reg: IO-mapped register
  *     @mask: Mask to apply to read register value
  *     @val: Wait condition
@@ -6595,7 +6542,7 @@ int ata_ratelimit(void)
  *     RETURNS:
  *     The final register value.
  */
-u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
+u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val,
                      unsigned long interval, unsigned long timeout)
 {
        unsigned long deadline;
@@ -6610,7 +6557,7 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
        deadline = ata_deadline(jiffies, timeout);
 
        while ((tmp & mask) == val && time_before(jiffies, deadline)) {
-               msleep(interval);
+               ata_msleep(ap, interval);
                tmp = ioread32(reg);
        }
 
@@ -6686,6 +6633,7 @@ EXPORT_SYMBOL_GPL(sata_set_spd);
 EXPORT_SYMBOL_GPL(ata_wait_after_reset);
 EXPORT_SYMBOL_GPL(sata_link_debounce);
 EXPORT_SYMBOL_GPL(sata_link_resume);
+EXPORT_SYMBOL_GPL(sata_link_scr_lpm);
 EXPORT_SYMBOL_GPL(ata_std_prereset);
 EXPORT_SYMBOL_GPL(sata_link_hardreset);
 EXPORT_SYMBOL_GPL(sata_std_hardreset);
@@ -6693,6 +6641,7 @@ EXPORT_SYMBOL_GPL(ata_std_postreset);
 EXPORT_SYMBOL_GPL(ata_dev_classify);
 EXPORT_SYMBOL_GPL(ata_dev_pair);
 EXPORT_SYMBOL_GPL(ata_ratelimit);
+EXPORT_SYMBOL_GPL(ata_msleep);
 EXPORT_SYMBOL_GPL(ata_wait_register);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
index e48302eae55fcd2ad619564c9cd8237c722efb29..5e590504f3aa15c6c3c73450327a0494c264d20f 100644 (file)
@@ -57,6 +57,7 @@ enum {
        /* error flags */
        ATA_EFLAG_IS_IO                 = (1 << 0),
        ATA_EFLAG_DUBIOUS_XFER          = (1 << 1),
+       ATA_EFLAG_OLD_ER                = (1 << 31),
 
        /* error categories */
        ATA_ECAT_NONE                   = 0,
@@ -396,14 +397,9 @@ static struct ata_ering_entry *ata_ering_top(struct ata_ering *ering)
        return NULL;
 }
 
-static void ata_ering_clear(struct ata_ering *ering)
-{
-       memset(ering, 0, sizeof(*ering));
-}
-
-static int ata_ering_map(struct ata_ering *ering,
-                        int (*map_fn)(struct ata_ering_entry *, void *),
-                        void *arg)
+int ata_ering_map(struct ata_ering *ering,
+                 int (*map_fn)(struct ata_ering_entry *, void *),
+                 void *arg)
 {
        int idx, rc = 0;
        struct ata_ering_entry *ent;
@@ -422,6 +418,17 @@ static int ata_ering_map(struct ata_ering *ering,
        return rc;
 }
 
+int ata_ering_clear_cb(struct ata_ering_entry *ent, void *void_arg)
+{
+       ent->eflags |= ATA_EFLAG_OLD_ER;
+       return 0;
+}
+
+static void ata_ering_clear(struct ata_ering *ering)
+{
+       ata_ering_map(ering, ata_ering_clear_cb, NULL);
+}
+
 static unsigned int ata_eh_dev_action(struct ata_device *dev)
 {
        struct ata_eh_context *ehc = &dev->link->eh_context;
@@ -455,6 +462,41 @@ static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
        }
 }
 
+/**
+ *     ata_eh_acquire - acquire EH ownership
+ *     @ap: ATA port to acquire EH ownership for
+ *
+ *     Acquire EH ownership for @ap.  This is the basic exclusion
+ *     mechanism for ports sharing a host.  Only one port hanging off
+ *     the same host can claim the ownership of EH.
+ *
+ *     LOCKING:
+ *     EH context.
+ */
+void ata_eh_acquire(struct ata_port *ap)
+{
+       mutex_lock(&ap->host->eh_mutex);
+       WARN_ON_ONCE(ap->host->eh_owner);
+       ap->host->eh_owner = current;
+}
+
+/**
+ *     ata_eh_release - release EH ownership
+ *     @ap: ATA port to release EH ownership for
+ *
+ *     Release EH ownership for @ap if the caller.  The caller must
+ *     have acquired EH ownership using ata_eh_acquire() previously.
+ *
+ *     LOCKING:
+ *     EH context.
+ */
+void ata_eh_release(struct ata_port *ap)
+{
+       WARN_ON_ONCE(ap->host->eh_owner != current);
+       ap->host->eh_owner = NULL;
+       mutex_unlock(&ap->host->eh_mutex);
+}
+
 /**
  *     ata_scsi_timed_out - SCSI layer time out callback
  *     @cmd: timed out SCSI command
@@ -572,19 +614,19 @@ void ata_scsi_error(struct Scsi_Host *host)
                int nr_timedout = 0;
 
                spin_lock_irqsave(ap->lock, flags);
-               
+
                /* This must occur under the ap->lock as we don't want
                   a polled recovery to race the real interrupt handler
-                  
+
                   The lost_interrupt handler checks for any completed but
                   non-notified command and completes much like an IRQ handler.
-                  
+
                   We then fall into the error recovery code which will treat
                   this as if normal completion won the race */
 
                if (ap->ops->lost_interrupt)
                        ap->ops->lost_interrupt(ap);
-                       
+
                list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
                        struct ata_queued_cmd *qc;
 
@@ -628,15 +670,17 @@ void ata_scsi_error(struct Scsi_Host *host)
                ap->eh_tries = ATA_EH_MAX_TRIES;
        } else
                spin_unlock_wait(ap->lock);
-               
+
        /* If we timed raced normal completion and there is nothing to
           recover nr_timedout == 0 why exactly are we doing error recovery ? */
 
- repeat:
        /* invoke error handler */
        if (ap->ops->error_handler) {
                struct ata_link *link;
 
+               /* acquire EH ownership */
+               ata_eh_acquire(ap);
+ repeat:
                /* kill fast drain timer */
                del_timer_sync(&ap->fastdrain_timer);
 
@@ -711,6 +755,7 @@ void ata_scsi_error(struct Scsi_Host *host)
                host->host_eh_scheduled = 0;
 
                spin_unlock_irqrestore(ap->lock, flags);
+               ata_eh_release(ap);
        } else {
                WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
                ap->ops->eng_timeout(ap);
@@ -772,7 +817,7 @@ void ata_port_wait_eh(struct ata_port *ap)
 
        /* make sure SCSI EH is complete */
        if (scsi_host_in_recovery(ap->scsi_host)) {
-               msleep(10);
+               ata_msleep(ap, 10);
                goto retry;
        }
 }
@@ -1573,9 +1618,9 @@ static void ata_eh_analyze_serror(struct ata_link *link)
         * host links.  For disabled PMP links, only N bit is
         * considered as X bit is left at 1 for link plugging.
         */
-       hotplug_mask = 0;
-
-       if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
+       if (link->lpm_policy != ATA_LPM_MAX_POWER)
+               hotplug_mask = 0;       /* hotplug doesn't work w/ LPM */
+       else if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
                hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
        else
                hotplug_mask = SERR_PHYRDY_CHG;
@@ -1755,7 +1800,7 @@ static int speed_down_verdict_cb(struct ata_ering_entry *ent, void *void_arg)
        struct speed_down_verdict_arg *arg = void_arg;
        int cat;
 
-       if (ent->timestamp < arg->since)
+       if ((ent->eflags & ATA_EFLAG_OLD_ER) || (ent->timestamp < arg->since))
                return -1;
 
        cat = ata_eh_categorize_error(ent->eflags, ent->err_mask,
@@ -2777,8 +2822,9 @@ int ata_eh_reset(struct ata_link *link, int classify,
        ata_eh_done(link, NULL, ATA_EH_RESET);
        if (slave)
                ata_eh_done(slave, NULL, ATA_EH_RESET);
-       ehc->last_reset = jiffies;      /* update to completion time */
+       ehc->last_reset = jiffies;              /* update to completion time */
        ehc->i.action |= ATA_EH_REVALIDATE;
+       link->lpm_policy = ATA_LPM_UNKNOWN;     /* reset LPM state */
 
        rc = 0;
  out:
@@ -2810,8 +2856,10 @@ int ata_eh_reset(struct ata_link *link, int classify,
                        "reset failed (errno=%d), retrying in %u secs\n",
                        rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000));
 
+               ata_eh_release(ap);
                while (delta)
                        delta = schedule_timeout_uninterruptible(delta);
+               ata_eh_acquire(ap);
        }
 
        if (try == max_tries - 1) {
@@ -3204,6 +3252,124 @@ static int ata_eh_maybe_retry_flush(struct ata_device *dev)
        return rc;
 }
 
+/**
+ *     ata_eh_set_lpm - configure SATA interface power management
+ *     @link: link to configure power management
+ *     @policy: the link power management policy
+ *     @r_failed_dev: out parameter for failed device
+ *
+ *     Enable SATA Interface power management.  This will enable
+ *     Device Interface Power Management (DIPM) for min_power
+ *     policy, and then call driver specific callbacks for
+ *     enabling Host Initiated Power management.
+ *
+ *     LOCKING:
+ *     EH context.
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                         struct ata_device **r_failed_dev)
+{
+       struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL;
+       struct ata_eh_context *ehc = &link->eh_context;
+       struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL;
+       unsigned int hints = ATA_LPM_EMPTY | ATA_LPM_HIPM;
+       unsigned int err_mask;
+       int rc;
+
+       /* if the link or host doesn't do LPM, noop */
+       if ((link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm))
+               return 0;
+
+       /*
+        * DIPM is enabled only for MIN_POWER as some devices
+        * misbehave when the host NACKs transition to SLUMBER.  Order
+        * device and link configurations such that the host always
+        * allows DIPM requests.
+        */
+       ata_for_each_dev(dev, link, ENABLED) {
+               bool hipm = ata_id_has_hipm(dev->id);
+               bool dipm = ata_id_has_dipm(dev->id);
+
+               /* find the first enabled and LPM enabled devices */
+               if (!link_dev)
+                       link_dev = dev;
+
+               if (!lpm_dev && (hipm || dipm))
+                       lpm_dev = dev;
+
+               hints &= ~ATA_LPM_EMPTY;
+               if (!hipm)
+                       hints &= ~ATA_LPM_HIPM;
+
+               /* disable DIPM before changing link config */
+               if (policy != ATA_LPM_MIN_POWER && dipm) {
+                       err_mask = ata_dev_set_feature(dev,
+                                       SETFEATURES_SATA_DISABLE, SATA_DIPM);
+                       if (err_mask && err_mask != AC_ERR_DEV) {
+                               ata_dev_printk(dev, KERN_WARNING,
+                                       "failed to disable DIPM, Emask 0x%x\n",
+                                       err_mask);
+                               rc = -EIO;
+                               goto fail;
+                       }
+               }
+       }
+
+       if (ap) {
+               rc = ap->ops->set_lpm(link, policy, hints);
+               if (!rc && ap->slave_link)
+                       rc = ap->ops->set_lpm(ap->slave_link, policy, hints);
+       } else
+               rc = sata_pmp_set_lpm(link, policy, hints);
+
+       /*
+        * Attribute link config failure to the first (LPM) enabled
+        * device on the link.
+        */
+       if (rc) {
+               if (rc == -EOPNOTSUPP) {
+                       link->flags |= ATA_LFLAG_NO_LPM;
+                       return 0;
+               }
+               dev = lpm_dev ? lpm_dev : link_dev;
+               goto fail;
+       }
+
+       /* host config updated, enable DIPM if transitioning to MIN_POWER */
+       ata_for_each_dev(dev, link, ENABLED) {
+               if (policy == ATA_LPM_MIN_POWER && ata_id_has_dipm(dev->id)) {
+                       err_mask = ata_dev_set_feature(dev,
+                                       SETFEATURES_SATA_ENABLE, SATA_DIPM);
+                       if (err_mask && err_mask != AC_ERR_DEV) {
+                               ata_dev_printk(dev, KERN_WARNING,
+                                       "failed to enable DIPM, Emask 0x%x\n",
+                                       err_mask);
+                               rc = -EIO;
+                               goto fail;
+                       }
+               }
+       }
+
+       link->lpm_policy = policy;
+       if (ap && ap->slave_link)
+               ap->slave_link->lpm_policy = policy;
+       return 0;
+
+fail:
+       /* if no device or only one more chance is left, disable LPM */
+       if (!dev || ehc->tries[dev->devno] <= 2) {
+               ata_link_printk(link, KERN_WARNING,
+                               "disabling LPM on the link\n");
+               link->flags |= ATA_LFLAG_NO_LPM;
+       }
+       if (r_failed_dev)
+               *r_failed_dev = dev;
+       return rc;
+}
+
 static int ata_link_nr_enabled(struct ata_link *link)
 {
        struct ata_device *dev;
@@ -3288,6 +3454,16 @@ static int ata_eh_schedule_probe(struct ata_device *dev)
        ehc->saved_xfer_mode[dev->devno] = 0;
        ehc->saved_ncq_enabled &= ~(1 << dev->devno);
 
+       /* the link maybe in a deep sleep, wake it up */
+       if (link->lpm_policy > ATA_LPM_MAX_POWER) {
+               if (ata_is_host_link(link))
+                       link->ap->ops->set_lpm(link, ATA_LPM_MAX_POWER,
+                                              ATA_LPM_EMPTY);
+               else
+                       sata_pmp_set_lpm(link, ATA_LPM_MAX_POWER,
+                                        ATA_LPM_EMPTY);
+       }
+
        /* Record and count probe trials on the ering.  The specific
         * error mask used is irrelevant.  Because a successful device
         * detection clears the ering, this count accumulates only if
@@ -3389,8 +3565,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 {
        struct ata_link *link;
        struct ata_device *dev;
-       int nr_failed_devs;
-       int rc;
+       int rc, nr_fails;
        unsigned long flags, deadline;
 
        DPRINTK("ENTER\n");
@@ -3431,7 +3606,6 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
 
  retry:
        rc = 0;
-       nr_failed_devs = 0;
 
        /* if UNLOADING, finish immediately */
        if (ap->pflags & ATA_PFLAG_UNLOADING)
@@ -3501,8 +3675,10 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                if (time_before_eq(deadline, now))
                        break;
 
+               ata_eh_release(ap);
                deadline = wait_for_completion_timeout(&ap->park_req_pending,
                                                       deadline - now);
+               ata_eh_acquire(ap);
        } while (deadline);
        ata_for_each_link(link, ap, EDGE) {
                ata_for_each_dev(dev, link, ALL) {
@@ -3516,13 +3692,17 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
        }
 
        /* the rest */
-       ata_for_each_link(link, ap, EDGE) {
+       nr_fails = 0;
+       ata_for_each_link(link, ap, PMP_FIRST) {
                struct ata_eh_context *ehc = &link->eh_context;
 
+               if (sata_pmp_attached(ap) && ata_is_host_link(link))
+                       goto config_lpm;
+
                /* revalidate existing devices and attach new ones */
                rc = ata_eh_revalidate_and_attach(link, &dev);
                if (rc)
-                       goto dev_fail;
+                       goto rest_fail;
 
                /* if PMP got attached, return, pmp EH will take care of it */
                if (link->device->class == ATA_DEV_PMP) {
@@ -3534,7 +3714,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                if (ehc->i.flags & ATA_EHI_SETMODE) {
                        rc = ata_set_mode(link, &dev);
                        if (rc)
-                               goto dev_fail;
+                               goto rest_fail;
                        ehc->i.flags &= ~ATA_EHI_SETMODE;
                }
 
@@ -3547,7 +3727,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                                        continue;
                                rc = atapi_eh_clear_ua(dev);
                                if (rc)
-                                       goto dev_fail;
+                                       goto rest_fail;
                        }
                }
 
@@ -3557,21 +3737,25 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                                continue;
                        rc = ata_eh_maybe_retry_flush(dev);
                        if (rc)
-                               goto dev_fail;
+                               goto rest_fail;
                }
 
+       config_lpm:
                /* configure link power saving */
-               if (ehc->i.action & ATA_EH_LPM)
-                       ata_for_each_dev(dev, link, ALL)
-                               ata_dev_enable_pm(dev, ap->pm_policy);
+               if (link->lpm_policy != ap->target_lpm_policy) {
+                       rc = ata_eh_set_lpm(link, ap->target_lpm_policy, &dev);
+                       if (rc)
+                               goto rest_fail;
+               }
 
                /* this link is okay now */
                ehc->i.flags = 0;
                continue;
 
-dev_fail:
-               nr_failed_devs++;
-               ata_eh_handle_dev_fail(dev, rc);
+       rest_fail:
+               nr_fails++;
+               if (dev)
+                       ata_eh_handle_dev_fail(dev, rc);
 
                if (ap->pflags & ATA_PFLAG_FROZEN) {
                        /* PMP reset requires working host port.
@@ -3583,7 +3767,7 @@ dev_fail:
                }
        }
 
-       if (nr_failed_devs)
+       if (nr_fails)
                goto retry;
 
  out:
index 224faabd7b7efd1adf769ded4f0d4989604a012c..3120596d4afc9aaba293f100f7a075ace6438f9e 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/libata.h>
 #include <linux/slab.h>
 #include "libata.h"
+#include "libata-transport.h"
 
 const struct ata_port_operations sata_pmp_port_ops = {
        .inherits               = &sata_port_ops,
@@ -184,6 +185,27 @@ int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
        return 0;
 }
 
+/**
+ *     sata_pmp_set_lpm - configure LPM for a PMP link
+ *     @link: PMP link to configure LPM for
+ *     @policy: target LPM policy
+ *     @hints: LPM hints
+ *
+ *     Configure LPM for @link.  This function will contain any PMP
+ *     specific workarounds if necessary.
+ *
+ *     LOCKING:
+ *     EH context.
+ *
+ *     RETURNS:
+ *     0 on success, -errno on failure.
+ */
+int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                    unsigned hints)
+{
+       return sata_link_scr_lpm(link, policy, true);
+}
+
 /**
  *     sata_pmp_read_gscr - read GSCR block of SATA PMP
  *     @dev: PMP device
@@ -312,10 +334,10 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info)
        return rc;
 }
 
-static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
+static int sata_pmp_init_links (struct ata_port *ap, int nr_ports)
 {
        struct ata_link *pmp_link = ap->pmp_link;
-       int i;
+       int i, err;
 
        if (!pmp_link) {
                pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS,
@@ -327,6 +349,13 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
                        ata_link_init(ap, &pmp_link[i], i);
 
                ap->pmp_link = pmp_link;
+
+               for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
+                       err = ata_tlink_add(&pmp_link[i]);
+                       if (err) {
+                               goto err_tlink;
+                       }
+               }
        }
 
        for (i = 0; i < nr_ports; i++) {
@@ -339,6 +368,12 @@ static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
        }
 
        return 0;
+  err_tlink:
+       while (--i >= 0)
+               ata_tlink_delete(&pmp_link[i]);
+       kfree(pmp_link);
+       ap->pmp_link = NULL;
+       return err;
 }
 
 static void sata_pmp_quirks(struct ata_port *ap)
@@ -351,6 +386,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
        if (vendor == 0x1095 && devid == 0x3726) {
                /* sil3726 quirks */
                ata_for_each_link(link, ap, EDGE) {
+                       /* link reports offline after LPM */
+                       link->flags |= ATA_LFLAG_NO_LPM;
+
                        /* Class code report is unreliable and SRST
                         * times out under certain configurations.
                         */
@@ -366,6 +404,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
        } else if (vendor == 0x1095 && devid == 0x4723) {
                /* sil4723 quirks */
                ata_for_each_link(link, ap, EDGE) {
+                       /* link reports offline after LPM */
+                       link->flags |= ATA_LFLAG_NO_LPM;
+
                        /* class code report is unreliable */
                        if (link->pmp < 2)
                                link->flags |= ATA_LFLAG_ASSUME_ATA;
@@ -378,6 +419,9 @@ static void sata_pmp_quirks(struct ata_port *ap)
        } else if (vendor == 0x1095 && devid == 0x4726) {
                /* sil4726 quirks */
                ata_for_each_link(link, ap, EDGE) {
+                       /* link reports offline after LPM */
+                       link->flags |= ATA_LFLAG_NO_LPM;
+
                        /* Class code report is unreliable and SRST
                         * times out under certain configurations.
                         * Config device can be at port 0 or 5 and
@@ -938,15 +982,25 @@ static int sata_pmp_eh_recover(struct ata_port *ap)
        if (rc)
                goto link_fail;
 
-       /* Connection status might have changed while resetting other
-        * links, check SATA_PMP_GSCR_ERROR before returning.
-        */
-
        /* clear SNotification */
        rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
        if (rc == 0)
                sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
 
+       /*
+        * If LPM is active on any fan-out port, hotplug wouldn't
+        * work.  Return w/ PHY event notification disabled.
+        */
+       ata_for_each_link(link, ap, EDGE)
+               if (link->lpm_policy > ATA_LPM_MAX_POWER)
+                       return 0;
+
+       /*
+        * Connection status might have changed while resetting other
+        * links, enable notification and check SATA_PMP_GSCR_ERROR
+        * before returning.
+        */
+
        /* enable notification */
        if (pmp_dev->flags & ATA_DFLAG_AN) {
                gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
index a89172c100f5645c3317dbe6b87c4cd797a4649c..d050e073e57035a99b969c50205a4227ed6a8812 100644 (file)
@@ -51,8 +51,8 @@
 #include <asm/unaligned.h>
 
 #include "libata.h"
+#include "libata-transport.h"
 
-#define SECTOR_SIZE            512
 #define ATA_SCSI_RBUF_SIZE     4096
 
 static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
@@ -64,9 +64,6 @@ static struct ata_device *__ata_scsi_find_dev(struct ata_port *ap,
                                        const struct scsi_device *scsidev);
 static struct ata_device *ata_scsi_find_dev(struct ata_port *ap,
                                            const struct scsi_device *scsidev);
-static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
-                             unsigned int id, unsigned int lun);
-
 
 #define RW_RECOVERY_MPAGE 0x1
 #define RW_RECOVERY_MPAGE_LEN 12
@@ -106,83 +103,55 @@ static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = {
        0, 30   /* extended self test time, see 05-359r1 */
 };
 
-/*
- * libata transport template.  libata doesn't do real transport stuff.
- * It just needs the eh_timed_out hook.
- */
-static struct scsi_transport_template ata_scsi_transport_template = {
-       .eh_strategy_handler    = ata_scsi_error,
-       .eh_timed_out           = ata_scsi_timed_out,
-       .user_scan              = ata_scsi_user_scan,
-};
-
-
-static const struct {
-       enum link_pm    value;
-       const char      *name;
-} link_pm_policy[] = {
-       { NOT_AVAILABLE, "max_performance" },
-       { MIN_POWER, "min_power" },
-       { MAX_PERFORMANCE, "max_performance" },
-       { MEDIUM_POWER, "medium_power" },
+static const char *ata_lpm_policy_names[] = {
+       [ATA_LPM_UNKNOWN]       = "max_performance",
+       [ATA_LPM_MAX_POWER]     = "max_performance",
+       [ATA_LPM_MED_POWER]     = "medium_power",
+       [ATA_LPM_MIN_POWER]     = "min_power",
 };
 
-static const char *ata_scsi_lpm_get(enum link_pm policy)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(link_pm_policy); i++)
-               if (link_pm_policy[i].value == policy)
-                       return link_pm_policy[i].name;
-
-       return NULL;
-}
-
-static ssize_t ata_scsi_lpm_put(struct device *dev,
-                               struct device_attribute *attr,
-                               const char *buf, size_t count)
+static ssize_t ata_scsi_lpm_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
 {
        struct Scsi_Host *shost = class_to_shost(dev);
        struct ata_port *ap = ata_shost_to_port(shost);
-       enum link_pm policy = 0;
-       int i;
+       enum ata_lpm_policy policy;
+       unsigned long flags;
 
-       /*
-        * we are skipping array location 0 on purpose - this
-        * is because a value of NOT_AVAILABLE is displayed
-        * to the user as max_performance, but when the user
-        * writes "max_performance", they actually want the
-        * value to match MAX_PERFORMANCE.
-        */
-       for (i = 1; i < ARRAY_SIZE(link_pm_policy); i++) {
-               const int len = strlen(link_pm_policy[i].name);
-               if (strncmp(link_pm_policy[i].name, buf, len) == 0) {
-                       policy = link_pm_policy[i].value;
+       /* UNKNOWN is internal state, iterate from MAX_POWER */
+       for (policy = ATA_LPM_MAX_POWER;
+            policy < ARRAY_SIZE(ata_lpm_policy_names); policy++) {
+               const char *name = ata_lpm_policy_names[policy];
+
+               if (strncmp(name, buf, strlen(name)) == 0)
                        break;
-               }
        }
-       if (!policy)
+       if (policy == ARRAY_SIZE(ata_lpm_policy_names))
                return -EINVAL;
 
-       ata_lpm_schedule(ap, policy);
+       spin_lock_irqsave(ap->lock, flags);
+       ap->target_lpm_policy = policy;
+       ata_port_schedule_eh(ap);
+       spin_unlock_irqrestore(ap->lock, flags);
+
        return count;
 }
 
-static ssize_t
-ata_scsi_lpm_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t ata_scsi_lpm_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
        struct Scsi_Host *shost = class_to_shost(dev);
        struct ata_port *ap = ata_shost_to_port(shost);
-       const char *policy =
-               ata_scsi_lpm_get(ap->pm_policy);
 
-       if (!policy)
+       if (ap->target_lpm_policy >= ARRAY_SIZE(ata_lpm_policy_names))
                return -EINVAL;
 
-       return snprintf(buf, 23, "%s\n", policy);
+       return snprintf(buf, PAGE_SIZE, "%s\n",
+                       ata_lpm_policy_names[ap->target_lpm_policy]);
 }
 DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
-               ata_scsi_lpm_show, ata_scsi_lpm_put);
+           ata_scsi_lpm_show, ata_scsi_lpm_store);
 EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
 
 static ssize_t ata_scsi_park_show(struct device *device,
@@ -516,7 +485,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
        memset(scsi_cmd, 0, sizeof(scsi_cmd));
 
        if (args[3]) {
-               argsize = SECTOR_SIZE * args[3];
+               argsize = ATA_SECT_SIZE * args[3];
                argbuf = kmalloc(argsize, GFP_KERNEL);
                if (argbuf == NULL) {
                        rc = -ENOMEM;
@@ -1150,8 +1119,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
                blk_queue_dma_drain(q, atapi_drain_needed, buf, ATAPI_MAX_DRAIN);
        } else {
                /* ATA devices must be sector aligned */
+               sdev->sector_size = ata_id_logical_sector_size(dev->id);
                blk_queue_update_dma_alignment(sdev->request_queue,
-                                              ATA_SECT_SIZE - 1);
+                                              sdev->sector_size - 1);
                sdev->manage_start_stop = 1;
        }
 
@@ -1166,6 +1136,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
                scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
        }
 
+       dev->sdev = sdev;
        return 0;
 }
 
@@ -1696,7 +1667,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
                goto nothing_to_do;
 
        qc->flags |= ATA_QCFLAG_IO;
-       qc->nbytes = n_block * ATA_SECT_SIZE;
+       qc->nbytes = n_block * scmd->device->sector_size;
 
        rc = ata_build_rw_tf(&qc->tf, qc->dev, block, n_block, tf_flags,
                             qc->tag);
@@ -2001,6 +1972,7 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
                0x89,   /* page 0x89, ata info page */
                0xb0,   /* page 0xb0, block limits page */
                0xb1,   /* page 0xb1, block device characteristics page */
+               0xb2,   /* page 0xb2, thin provisioning page */
        };
 
        rbuf[3] = sizeof(pages);        /* number of supported VPD pages */
@@ -2123,7 +2095,7 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
 
 static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
 {
-       u32 min_io_sectors;
+       u16 min_io_sectors;
 
        rbuf[1] = 0xb0;
        rbuf[3] = 0x3c;         /* required VPD size with unmap support */
@@ -2135,10 +2107,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
         * logical than physical sector size we need to figure out what the
         * latter is.
         */
-       if (ata_id_has_large_logical_sectors(args->id))
-               min_io_sectors = ata_id_logical_per_physical_sectors(args->id);
-       else
-               min_io_sectors = 1;
+       min_io_sectors = 1 << ata_id_log2_per_physical_sector(args->id);
        put_unaligned_be16(min_io_sectors, &rbuf[6]);
 
        /*
@@ -2172,6 +2141,16 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf)
        return 0;
 }
 
+static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf)
+{
+       /* SCSI Thin Provisioning VPD page: SBC-3 rev 22 or later */
+       rbuf[1] = 0xb2;
+       rbuf[3] = 0x4;
+       rbuf[5] = 1 << 6;       /* TPWS */
+
+       return 0;
+}
+
 /**
  *     ata_scsiop_noop - Command handler that simply returns success.
  *     @args: device IDENTIFY data / SCSI command of interest.
@@ -2397,21 +2376,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
 {
        struct ata_device *dev = args->dev;
        u64 last_lba = dev->n_sectors - 1; /* LBA of the last block */
-       u8 log_per_phys = 0;
-       u16 lowest_aligned = 0;
-       u16 word_106 = dev->id[106];
-       u16 word_209 = dev->id[209];
-
-       if ((word_106 & 0xc000) == 0x4000) {
-               /* Number and offset of logical sectors per physical sector */
-               if (word_106 & (1 << 13))
-                       log_per_phys = word_106 & 0xf;
-               if ((word_209 & 0xc000) == 0x4000) {
-                       u16 first = dev->id[209] & 0x3fff;
-                       if (first > 0)
-                               lowest_aligned = (1 << log_per_phys) - first;
-               }
-       }
+       u32 sector_size; /* physical sector size in bytes */
+       u8 log2_per_phys;
+       u16 lowest_aligned;
+
+       sector_size = ata_id_logical_sector_size(dev->id);
+       log2_per_phys = ata_id_log2_per_physical_sector(dev->id);
+       lowest_aligned = ata_id_logical_sector_offset(dev->id, log2_per_phys);
 
        VPRINTK("ENTER\n");
 
@@ -2426,8 +2397,10 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
                rbuf[3] = last_lba;
 
                /* sector size */
-               rbuf[6] = ATA_SECT_SIZE >> 8;
-               rbuf[7] = ATA_SECT_SIZE & 0xff;
+               rbuf[4] = sector_size >> (8 * 3);
+               rbuf[5] = sector_size >> (8 * 2);
+               rbuf[6] = sector_size >> (8 * 1);
+               rbuf[7] = sector_size;
        } else {
                /* sector count, 64-bit */
                rbuf[0] = last_lba >> (8 * 7);
@@ -2440,11 +2413,13 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
                rbuf[7] = last_lba;
 
                /* sector size */
-               rbuf[10] = ATA_SECT_SIZE >> 8;
-               rbuf[11] = ATA_SECT_SIZE & 0xff;
+               rbuf[ 8] = sector_size >> (8 * 3);
+               rbuf[ 9] = sector_size >> (8 * 2);
+               rbuf[10] = sector_size >> (8 * 1);
+               rbuf[11] = sector_size;
 
                rbuf[12] = 0;
-               rbuf[13] = log_per_phys;
+               rbuf[13] = log2_per_phys;
                rbuf[14] = (lowest_aligned >> 8) & 0x3f;
                rbuf[15] = lowest_aligned;
 
@@ -2888,9 +2863,8 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
        tf->device = dev->devno ?
                tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1;
 
-       /* READ/WRITE LONG use a non-standard sect_size */
-       qc->sect_size = ATA_SECT_SIZE;
        switch (tf->command) {
+       /* READ/WRITE LONG use a non-standard sect_size */
        case ATA_CMD_READ_LONG:
        case ATA_CMD_READ_LONG_ONCE:
        case ATA_CMD_WRITE_LONG:
@@ -2898,6 +2872,45 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
                if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
                        goto invalid_fld;
                qc->sect_size = scsi_bufflen(scmd);
+               break;
+
+       /* commands using reported Logical Block size (e.g. 512 or 4K) */
+       case ATA_CMD_CFA_WRITE_NE:
+       case ATA_CMD_CFA_TRANS_SECT:
+       case ATA_CMD_CFA_WRITE_MULT_NE:
+       /* XXX: case ATA_CMD_CFA_WRITE_SECTORS_WITHOUT_ERASE: */
+       case ATA_CMD_READ:
+       case ATA_CMD_READ_EXT:
+       case ATA_CMD_READ_QUEUED:
+       /* XXX: case ATA_CMD_READ_QUEUED_EXT: */
+       case ATA_CMD_FPDMA_READ:
+       case ATA_CMD_READ_MULTI:
+       case ATA_CMD_READ_MULTI_EXT:
+       case ATA_CMD_PIO_READ:
+       case ATA_CMD_PIO_READ_EXT:
+       case ATA_CMD_READ_STREAM_DMA_EXT:
+       case ATA_CMD_READ_STREAM_EXT:
+       case ATA_CMD_VERIFY:
+       case ATA_CMD_VERIFY_EXT:
+       case ATA_CMD_WRITE:
+       case ATA_CMD_WRITE_EXT:
+       case ATA_CMD_WRITE_FUA_EXT:
+       case ATA_CMD_WRITE_QUEUED:
+       case ATA_CMD_WRITE_QUEUED_FUA_EXT:
+       case ATA_CMD_FPDMA_WRITE:
+       case ATA_CMD_WRITE_MULTI:
+       case ATA_CMD_WRITE_MULTI_EXT:
+       case ATA_CMD_WRITE_MULTI_FUA_EXT:
+       case ATA_CMD_PIO_WRITE:
+       case ATA_CMD_PIO_WRITE_EXT:
+       case ATA_CMD_WRITE_STREAM_DMA_EXT:
+       case ATA_CMD_WRITE_STREAM_EXT:
+               qc->sect_size = scmd->device->sector_size;
+               break;
+
+       /* Everything else uses 512 byte "sectors" */
+       default:
+               qc->sect_size = ATA_SECT_SIZE;
        }
 
        /*
@@ -3250,6 +3263,9 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
                case 0xb1:
                        ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b1);
                        break;
+               case 0xb2:
+                       ata_scsi_rbuf_fill(&args, ata_scsiop_inq_b2);
+                       break;
                default:
                        ata_scsi_invalid_field(cmd, done);
                        break;
@@ -3334,7 +3350,7 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
                *(struct ata_port **)&shost->hostdata[0] = ap;
                ap->scsi_host = shost;
 
-               shost->transportt = &ata_scsi_transport_template;
+               shost->transportt = ata_scsi_transport_template;
                shost->unique_id = ap->print_id;
                shost->max_id = 16;
                shost->max_lun = 1;
@@ -3393,6 +3409,8 @@ void ata_scsi_scan_host(struct ata_port *ap, int sync)
                        if (!IS_ERR(sdev)) {
                                dev->sdev = sdev;
                                scsi_device_put(sdev);
+                       } else {
+                               dev->sdev = NULL;
                        }
                }
        }
@@ -3616,8 +3634,8 @@ void ata_scsi_hotplug(struct work_struct *work)
  *     RETURNS:
  *     Zero.
  */
-static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
-                             unsigned int id, unsigned int lun)
+int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+                      unsigned int id, unsigned int lun)
 {
        struct ata_port *ap = ata_shost_to_port(shost);
        unsigned long flags;
index e30c537cce32f99ab7fcb07f7f124cd920c4cd4b..14d18bf812556d99c463c70c70d4897e7b33055d 100644 (file)
@@ -222,7 +222,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
        timeout = ata_deadline(timer_start, tmout_pat);
        while (status != 0xff && (status & ATA_BUSY) &&
               time_before(jiffies, timeout)) {
-               msleep(50);
+               ata_msleep(ap, 50);
                status = ata_sff_busy_wait(ap, ATA_BUSY, 3);
        }
 
@@ -234,7 +234,7 @@ int ata_sff_busy_sleep(struct ata_port *ap,
        timeout = ata_deadline(timer_start, tmout);
        while (status != 0xff && (status & ATA_BUSY) &&
               time_before(jiffies, timeout)) {
-               msleep(50);
+               ata_msleep(ap, 50);
                status = ap->ops->sff_check_status(ap);
        }
 
@@ -360,7 +360,7 @@ static void ata_dev_select(struct ata_port *ap, unsigned int device,
 
        if (wait) {
                if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
-                       msleep(150);
+                       ata_msleep(ap, 150);
                ata_wait_idle(ap);
        }
 }
@@ -1356,7 +1356,7 @@ fsm_start:
         */
        status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
        if (status & ATA_BUSY) {
-               msleep(2);
+               ata_msleep(ap, 2);
                status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
                if (status & ATA_BUSY) {
                        ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE);
@@ -1937,7 +1937,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
        unsigned int dev1 = devmask & (1 << 1);
        int rc, ret = 0;
 
-       msleep(ATA_WAIT_AFTER_RESET);
+       ata_msleep(ap, ATA_WAIT_AFTER_RESET);
 
        /* always check readiness of the master device */
        rc = ata_sff_wait_ready(link, deadline);
@@ -1966,7 +1966,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask,
                        lbal = ioread8(ioaddr->lbal_addr);
                        if ((nsect == 1) && (lbal == 1))
                                break;
-                       msleep(50);     /* give drive a breather */
+                       ata_msleep(ap, 50);     /* give drive a breather */
                }
 
                rc = ata_sff_wait_ready(link, deadline);
@@ -3342,7 +3342,7 @@ int __init ata_sff_init(void)
        return 0;
 }
 
-void __exit ata_sff_exit(void)
+void ata_sff_exit(void)
 {
        destroy_workqueue(ata_sff_wq);
 }
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
new file mode 100644 (file)
index 0000000..ce9dc62
--- /dev/null
@@ -0,0 +1,774 @@
+/*
+ *  Copyright 2008 ioogle, Inc.  All rights reserved.
+ *     Released under GPL v2.
+ *
+ * Libata transport class.
+ *
+ * The ATA transport class contains common code to deal with ATA HBAs,
+ * an approximated representation of ATA topologies in the driver model,
+ * and various sysfs attributes to expose these topologies and management
+ * interfaces to user-space.
+ *
+ * There are 3 objects defined in in this class:
+ * - ata_port
+ * - ata_link
+ * - ata_device
+ * Each port has a link object. Each link can have up to two devices for PATA
+ * and generally one for SATA.
+ * If there is SATA port multiplier [PMP], 15 additional ata_link object are
+ * created.
+ *
+ * These objects are created when the ata host is initialized and when a PMP is
+ * found. They are removed only when the HBA is removed, cleaned before the
+ * error handler runs.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <scsi/scsi_transport.h>
+#include <linux/libata.h>
+#include <linux/hdreg.h>
+#include <linux/uaccess.h>
+
+#include "libata.h"
+#include "libata-transport.h"
+
+#define ATA_PORT_ATTRS         2
+#define ATA_LINK_ATTRS         3
+#define ATA_DEV_ATTRS          9
+
+struct scsi_transport_template;
+struct scsi_transport_template *ata_scsi_transport_template;
+
+struct ata_internal {
+       struct scsi_transport_template t;
+
+       struct device_attribute private_port_attrs[ATA_PORT_ATTRS];
+       struct device_attribute private_link_attrs[ATA_LINK_ATTRS];
+       struct device_attribute private_dev_attrs[ATA_DEV_ATTRS];
+
+       struct transport_container link_attr_cont;
+       struct transport_container dev_attr_cont;
+
+       /*
+        * The array of null terminated pointers to attributes
+        * needed by scsi_sysfs.c
+        */
+       struct device_attribute *link_attrs[ATA_LINK_ATTRS + 1];
+       struct device_attribute *port_attrs[ATA_PORT_ATTRS + 1];
+       struct device_attribute *dev_attrs[ATA_DEV_ATTRS + 1];
+};
+#define to_ata_internal(tmpl)  container_of(tmpl, struct ata_internal, t)
+
+
+#define tdev_to_device(d)                                      \
+       container_of((d), struct ata_device, tdev)
+#define transport_class_to_dev(dev)                            \
+       tdev_to_device((dev)->parent)
+
+#define tdev_to_link(d)                                                \
+       container_of((d), struct ata_link, tdev)
+#define transport_class_to_link(dev)                           \
+       tdev_to_link((dev)->parent)
+
+#define tdev_to_port(d)                                                \
+       container_of((d), struct ata_port, tdev)
+#define transport_class_to_port(dev)                           \
+       tdev_to_port((dev)->parent)
+
+
+/* Device objects are always created whit link objects */
+static int ata_tdev_add(struct ata_device *dev);
+static void ata_tdev_delete(struct ata_device *dev);
+
+
+/*
+ * Hack to allow attributes of the same name in different objects.
+ */
+#define ATA_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
+       struct device_attribute device_attr_##_prefix##_##_name = \
+       __ATTR(_name,_mode,_show,_store)
+
+#define ata_bitfield_name_match(title, table)                  \
+static ssize_t                                                 \
+get_ata_##title##_names(u32 table_key, char *buf)              \
+{                                                              \
+       char *prefix = "";                                      \
+       ssize_t len = 0;                                        \
+       int i;                                                  \
+                                                               \
+       for (i = 0; i < ARRAY_SIZE(table); i++) {               \
+               if (table[i].value & table_key) {               \
+                       len += sprintf(buf + len, "%s%s",       \
+                               prefix, table[i].name);         \
+                       prefix = ", ";                          \
+               }                                               \
+       }                                                       \
+       len += sprintf(buf + len, "\n");                        \
+       return len;                                             \
+}
+
+#define ata_bitfield_name_search(title, table)                 \
+static ssize_t                                                 \
+get_ata_##title##_names(u32 table_key, char *buf)              \
+{                                                              \
+       ssize_t len = 0;                                        \
+       int i;                                                  \
+                                                               \
+       for (i = 0; i < ARRAY_SIZE(table); i++) {               \
+               if (table[i].value == table_key) {              \
+                       len += sprintf(buf + len, "%s",         \
+                               table[i].name);                 \
+                       break;                                  \
+               }                                               \
+       }                                                       \
+       len += sprintf(buf + len, "\n");                        \
+       return len;                                             \
+}
+
+static struct {
+       u32             value;
+       char            *name;
+} ata_class_names[] = {
+       { ATA_DEV_UNKNOWN,              "unknown" },
+       { ATA_DEV_ATA,                  "ata" },
+       { ATA_DEV_ATA_UNSUP,            "ata" },
+       { ATA_DEV_ATAPI,                "atapi" },
+       { ATA_DEV_ATAPI_UNSUP,          "atapi" },
+       { ATA_DEV_PMP,                  "pmp" },
+       { ATA_DEV_PMP_UNSUP,            "pmp" },
+       { ATA_DEV_SEMB,                 "semb" },
+       { ATA_DEV_SEMB_UNSUP,           "semb" },
+       { ATA_DEV_NONE,                 "none" }
+};
+ata_bitfield_name_search(class, ata_class_names)
+
+
+static struct {
+       u32             value;
+       char            *name;
+} ata_err_names[] = {
+       { AC_ERR_DEV,                   "DeviceError" },
+       { AC_ERR_HSM,                   "HostStateMachineError" },
+       { AC_ERR_TIMEOUT,               "Timeout" },
+       { AC_ERR_MEDIA,                 "MediaError" },
+       { AC_ERR_ATA_BUS,               "BusError" },
+       { AC_ERR_HOST_BUS,              "HostBusError" },
+       { AC_ERR_SYSTEM,                "SystemError" },
+       { AC_ERR_INVALID,               "InvalidArg" },
+       { AC_ERR_OTHER,                 "Unknown" },
+       { AC_ERR_NODEV_HINT,            "NoDeviceHint" },
+       { AC_ERR_NCQ,                   "NCQError" }
+};
+ata_bitfield_name_match(err, ata_err_names)
+
+static struct {
+       u32             value;
+       char            *name;
+} ata_xfer_names[] = {
+       { XFER_UDMA_7,                  "XFER_UDMA_7" },
+       { XFER_UDMA_6,                  "XFER_UDMA_6" },
+       { XFER_UDMA_5,                  "XFER_UDMA_5" },
+       { XFER_UDMA_4,                  "XFER_UDMA_4" },
+       { XFER_UDMA_3,                  "XFER_UDMA_3" },
+       { XFER_UDMA_2,                  "XFER_UDMA_2" },
+       { XFER_UDMA_1,                  "XFER_UDMA_1" },
+       { XFER_UDMA_0,                  "XFER_UDMA_0" },
+       { XFER_MW_DMA_4,                "XFER_MW_DMA_4" },
+       { XFER_MW_DMA_3,                "XFER_MW_DMA_3" },
+       { XFER_MW_DMA_2,                "XFER_MW_DMA_2" },
+       { XFER_MW_DMA_1,                "XFER_MW_DMA_1" },
+       { XFER_MW_DMA_0,                "XFER_MW_DMA_0" },
+       { XFER_SW_DMA_2,                "XFER_SW_DMA_2" },
+       { XFER_SW_DMA_1,                "XFER_SW_DMA_1" },
+       { XFER_SW_DMA_0,                "XFER_SW_DMA_0" },
+       { XFER_PIO_6,                   "XFER_PIO_6" },
+       { XFER_PIO_5,                   "XFER_PIO_5" },
+       { XFER_PIO_4,                   "XFER_PIO_4" },
+       { XFER_PIO_3,                   "XFER_PIO_3" },
+       { XFER_PIO_2,                   "XFER_PIO_2" },
+       { XFER_PIO_1,                   "XFER_PIO_1" },
+       { XFER_PIO_0,                   "XFER_PIO_0" },
+       { XFER_PIO_SLOW,                "XFER_PIO_SLOW" }
+};
+ata_bitfield_name_match(xfer,ata_xfer_names)
+
+/*
+ * ATA Port attributes
+ */
+#define ata_port_show_simple(field, name, format_string, cast)         \
+static ssize_t                                                         \
+show_ata_port_##name(struct device *dev,                               \
+                    struct device_attribute *attr, char *buf)          \
+{                                                                      \
+       struct ata_port *ap = transport_class_to_port(dev);             \
+                                                                       \
+       return snprintf(buf, 20, format_string, cast ap->field);        \
+}
+
+#define ata_port_simple_attr(field, name, format_string, type)         \
+       ata_port_show_simple(field, name, format_string, (type))        \
+static DEVICE_ATTR(name, S_IRUGO, show_ata_port_##name, NULL)
+
+ata_port_simple_attr(nr_pmp_links, nr_pmp_links, "%d\n", int);
+ata_port_simple_attr(stats.idle_irq, idle_irq, "%ld\n", unsigned long);
+
+static DECLARE_TRANSPORT_CLASS(ata_port_class,
+                              "ata_port", NULL, NULL, NULL);
+
+static void ata_tport_release(struct device *dev)
+{
+       put_device(dev->parent);
+}
+
+/**
+ * ata_is_port --  check if a struct device represents a ATA port
+ * @dev:       device to check
+ *
+ * Returns:
+ *     %1 if the device represents a ATA Port, %0 else
+ */
+int ata_is_port(const struct device *dev)
+{
+       return dev->release == ata_tport_release;
+}
+
+static int ata_tport_match(struct attribute_container *cont,
+                          struct device *dev)
+{
+       if (!ata_is_port(dev))
+               return 0;
+       return &ata_scsi_transport_template->host_attrs.ac == cont;
+}
+
+/**
+ * ata_tport_delete  --  remove ATA PORT
+ * @port:      ATA PORT to remove
+ *
+ * Removes the specified ATA PORT.  Remove the associated link as well.
+ */
+void ata_tport_delete(struct ata_port *ap)
+{
+       struct device *dev = &ap->tdev;
+
+       ata_tlink_delete(&ap->link);
+
+       transport_remove_device(dev);
+       device_del(dev);
+       transport_destroy_device(dev);
+       put_device(dev);
+}
+
+/** ata_tport_add - initialize a transport ATA port structure
+ *
+ * @parent:    parent device
+ * @ap:                existing ata_port structure
+ *
+ * Initialize a ATA port structure for sysfs.  It will be added to the device
+ * tree below the device specified by @parent which could be a PCI device.
+ *
+ * Returns %0 on success
+ */
+int ata_tport_add(struct device *parent,
+                 struct ata_port *ap)
+{
+       int error;
+       struct device *dev = &ap->tdev;
+
+       device_initialize(dev);
+
+       dev->parent = get_device(parent);
+       dev->release = ata_tport_release;
+       dev_set_name(dev, "ata%d", ap->print_id);
+       transport_setup_device(dev);
+       error = device_add(dev);
+       if (error) {
+               goto tport_err;
+       }
+
+       transport_add_device(dev);
+       transport_configure_device(dev);
+
+       error = ata_tlink_add(&ap->link);
+       if (error) {
+               goto tport_link_err;
+       }
+       return 0;
+
+ tport_link_err:
+       transport_remove_device(dev);
+       device_del(dev);
+
+ tport_err:
+       transport_destroy_device(dev);
+       put_device(dev);
+       return error;
+}
+
+
+/*
+ * ATA link attributes
+ */
+
+
+#define ata_link_show_linkspeed(field)                                 \
+static ssize_t                                                         \
+show_ata_link_##field(struct device *dev,                              \
+                     struct device_attribute *attr, char *buf)         \
+{                                                                      \
+       struct ata_link *link = transport_class_to_link(dev);           \
+                                                                       \
+       return sprintf(buf,"%s\n", sata_spd_string(fls(link->field)));  \
+}
+
+#define ata_link_linkspeed_attr(field)                                 \
+       ata_link_show_linkspeed(field)                                  \
+static DEVICE_ATTR(field, S_IRUGO, show_ata_link_##field, NULL)
+
+ata_link_linkspeed_attr(hw_sata_spd_limit);
+ata_link_linkspeed_attr(sata_spd_limit);
+ata_link_linkspeed_attr(sata_spd);
+
+
+static DECLARE_TRANSPORT_CLASS(ata_link_class,
+               "ata_link", NULL, NULL, NULL);
+
+static void ata_tlink_release(struct device *dev)
+{
+       put_device(dev->parent);
+}
+
+/**
+ * ata_is_link --  check if a struct device represents a ATA link
+ * @dev:       device to check
+ *
+ * Returns:
+ *     %1 if the device represents a ATA link, %0 else
+ */
+int ata_is_link(const struct device *dev)
+{
+       return dev->release == ata_tlink_release;
+}
+
+static int ata_tlink_match(struct attribute_container *cont,
+                          struct device *dev)
+{
+       struct ata_internal* i = to_ata_internal(ata_scsi_transport_template);
+       if (!ata_is_link(dev))
+               return 0;
+       return &i->link_attr_cont.ac == cont;
+}
+
+/**
+ * ata_tlink_delete  --  remove ATA LINK
+ * @port:      ATA LINK to remove
+ *
+ * Removes the specified ATA LINK.  remove associated ATA device(s) as well.
+ */
+void ata_tlink_delete(struct ata_link *link)
+{
+       struct device *dev = &link->tdev;
+       struct ata_device *ata_dev;
+
+       ata_for_each_dev(ata_dev, link, ALL) {
+               ata_tdev_delete(ata_dev);
+       }
+
+       transport_remove_device(dev);
+       device_del(dev);
+       transport_destroy_device(dev);
+       put_device(dev);
+}
+
+/**
+ * ata_tlink_add  --  initialize a transport ATA link structure
+ * @link:      allocated ata_link structure.
+ *
+ * Initialize an ATA LINK structure for sysfs.  It will be added in the
+ * device tree below the ATA PORT it belongs to.
+ *
+ * Returns %0 on success
+ */
+int ata_tlink_add(struct ata_link *link)
+{
+       struct device *dev = &link->tdev;
+       struct ata_port *ap = link->ap;
+       struct ata_device *ata_dev;
+       int error;
+
+       device_initialize(dev);
+       dev->parent = get_device(&ap->tdev);
+       dev->release = ata_tlink_release;
+       if (ata_is_host_link(link))
+               dev_set_name(dev, "link%d", ap->print_id);
+        else
+               dev_set_name(dev, "link%d.%d", ap->print_id, link->pmp);
+
+       transport_setup_device(dev);
+
+       error = device_add(dev);
+       if (error) {
+               goto tlink_err;
+       }
+
+       transport_add_device(dev);
+       transport_configure_device(dev);
+
+       ata_for_each_dev(ata_dev, link, ALL) {
+               error = ata_tdev_add(ata_dev);
+               if (error) {
+                       goto tlink_dev_err;
+               }
+       }
+       return 0;
+  tlink_dev_err:
+       while (--ata_dev >= link->device) {
+               ata_tdev_delete(ata_dev);
+       }
+       transport_remove_device(dev);
+       device_del(dev);
+  tlink_err:
+       transport_destroy_device(dev);
+       put_device(dev);
+       return error;
+}
+
+/*
+ * ATA device attributes
+ */
+
+#define ata_dev_show_class(title, field)                               \
+static ssize_t                                                         \
+show_ata_dev_##field(struct device *dev,                               \
+                    struct device_attribute *attr, char *buf)          \
+{                                                                      \
+       struct ata_device *ata_dev = transport_class_to_dev(dev);       \
+                                                                       \
+       return get_ata_##title##_names(ata_dev->field, buf);            \
+}
+
+#define ata_dev_attr(title, field)                                     \
+       ata_dev_show_class(title, field)                                \
+static DEVICE_ATTR(field, S_IRUGO, show_ata_dev_##field, NULL)
+
+ata_dev_attr(class, class);
+ata_dev_attr(xfer, pio_mode);
+ata_dev_attr(xfer, dma_mode);
+ata_dev_attr(xfer, xfer_mode);
+
+
+#define ata_dev_show_simple(field, format_string, cast)                \
+static ssize_t                                                         \
+show_ata_dev_##field(struct device *dev,                               \
+                    struct device_attribute *attr, char *buf)          \
+{                                                                      \
+       struct ata_device *ata_dev = transport_class_to_dev(dev);       \
+                                                                       \
+       return snprintf(buf, 20, format_string, cast ata_dev->field);   \
+}
+
+#define ata_dev_simple_attr(field, format_string, type)        \
+       ata_dev_show_simple(field, format_string, (type))       \
+static DEVICE_ATTR(field, S_IRUGO,                     \
+                  show_ata_dev_##field, NULL)
+
+ata_dev_simple_attr(spdn_cnt, "%d\n", int);
+
+struct ata_show_ering_arg {
+       char* buf;
+       int written;
+};
+
+static int ata_show_ering(struct ata_ering_entry *ent, void *void_arg)
+{
+       struct ata_show_ering_arg* arg = void_arg;
+       struct timespec time;
+
+       jiffies_to_timespec(ent->timestamp,&time);
+       arg->written += sprintf(arg->buf + arg->written,
+                              "[%5lu.%06lu]",
+                              time.tv_sec, time.tv_nsec);
+       arg->written += get_ata_err_names(ent->err_mask,
+                                         arg->buf + arg->written);
+       return 0;
+}
+
+static ssize_t
+show_ata_dev_ering(struct device *dev,
+                  struct device_attribute *attr, char *buf)
+{
+       struct ata_device *ata_dev = transport_class_to_dev(dev);
+       struct ata_show_ering_arg arg = { buf, 0 };
+
+       ata_ering_map(&ata_dev->ering, ata_show_ering, &arg);
+       return arg.written;
+}
+
+
+static DEVICE_ATTR(ering, S_IRUGO, show_ata_dev_ering, NULL);
+
+static ssize_t
+show_ata_dev_id(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct ata_device *ata_dev = transport_class_to_dev(dev);
+       int written = 0, i = 0;
+
+       if (ata_dev->class == ATA_DEV_PMP)
+               return 0;
+       for(i=0;i<ATA_ID_WORDS;i++)  {
+               written += snprintf(buf+written, 20, "%04x%c",
+                                   ata_dev->id[i],
+                                   ((i+1) & 7) ? ' ' : '\n');
+       }
+       return written;
+}
+
+static DEVICE_ATTR(id, S_IRUGO, show_ata_dev_id, NULL);
+
+static ssize_t
+show_ata_dev_gscr(struct device *dev,
+                 struct device_attribute *attr, char *buf)
+{
+       struct ata_device *ata_dev = transport_class_to_dev(dev);
+       int written = 0, i = 0;
+
+       if (ata_dev->class != ATA_DEV_PMP)
+               return 0;
+       for(i=0;i<SATA_PMP_GSCR_DWORDS;i++)  {
+               written += snprintf(buf+written, 20, "%08x%c",
+                                   ata_dev->gscr[i],
+                                   ((i+1) & 3) ? ' ' : '\n');
+       }
+       if (SATA_PMP_GSCR_DWORDS & 3)
+               buf[written-1] = '\n';
+       return written;
+}
+
+static DEVICE_ATTR(gscr, S_IRUGO, show_ata_dev_gscr, NULL);
+
+static DECLARE_TRANSPORT_CLASS(ata_dev_class,
+                              "ata_device", NULL, NULL, NULL);
+
+static void ata_tdev_release(struct device *dev)
+{
+       put_device(dev->parent);
+}
+
+/**
+ * ata_is_ata_dev  --  check if a struct device represents a ATA device
+ * @dev:       device to check
+ *
+ * Returns:
+ *     %1 if the device represents a ATA device, %0 else
+ */
+int ata_is_ata_dev(const struct device *dev)
+{
+       return dev->release == ata_tdev_release;
+}
+
+static int ata_tdev_match(struct attribute_container *cont,
+                         struct device *dev)
+{
+       struct ata_internal* i = to_ata_internal(ata_scsi_transport_template);
+       if (!ata_is_ata_dev(dev))
+               return 0;
+       return &i->dev_attr_cont.ac == cont;
+}
+
+/**
+ * ata_tdev_free  --  free a ATA LINK
+ * @dev:       ATA PHY to free
+ *
+ * Frees the specified ATA PHY.
+ *
+ * Note:
+ *   This function must only be called on a PHY that has not
+ *   successfully been added using ata_tdev_add().
+ */
+static void ata_tdev_free(struct ata_device *dev)
+{
+       transport_destroy_device(&dev->tdev);
+       put_device(&dev->tdev);
+}
+
+/**
+ * ata_tdev_delete  --  remove ATA device
+ * @port:      ATA PORT to remove
+ *
+ * Removes the specified ATA device.
+ */
+static void ata_tdev_delete(struct ata_device *ata_dev)
+{
+       struct device *dev = &ata_dev->tdev;
+
+       transport_remove_device(dev);
+       device_del(dev);
+       ata_tdev_free(ata_dev);
+}
+
+
+/**
+ * ata_tdev_add  --  initialize a transport ATA device structure.
+ * @ata_dev:   ata_dev structure.
+ *
+ * Initialize an ATA device structure for sysfs.  It will be added in the
+ * device tree below the ATA LINK device it belongs to.
+ *
+ * Returns %0 on success
+ */
+static int ata_tdev_add(struct ata_device *ata_dev)
+{
+       struct device *dev = &ata_dev->tdev;
+       struct ata_link *link = ata_dev->link;
+       struct ata_port *ap = link->ap;
+       int error;
+
+       device_initialize(dev);
+       dev->parent = get_device(&link->tdev);
+       dev->release = ata_tdev_release;
+       if (ata_is_host_link(link))
+               dev_set_name(dev, "dev%d.%d", ap->print_id,ata_dev->devno);
+        else
+               dev_set_name(dev, "dev%d.%d.0", ap->print_id, link->pmp);
+
+       transport_setup_device(dev);
+       error = device_add(dev);
+       if (error) {
+               ata_tdev_free(ata_dev);
+               return error;
+       }
+
+       transport_add_device(dev);
+       transport_configure_device(dev);
+       return 0;
+}
+
+
+/*
+ * Setup / Teardown code
+ */
+
+#define SETUP_TEMPLATE(attrb, field, perm, test)                       \
+       i->private_##attrb[count] = dev_attr_##field;                   \
+       i->private_##attrb[count].attr.mode = perm;                     \
+       i->attrb[count] = &i->private_##attrb[count];                   \
+       if (test)                                                       \
+               count++
+
+#define SETUP_LINK_ATTRIBUTE(field)                                    \
+       SETUP_TEMPLATE(link_attrs, field, S_IRUGO, 1)
+
+#define SETUP_PORT_ATTRIBUTE(field)                                    \
+       SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
+
+#define SETUP_DEV_ATTRIBUTE(field)                                     \
+       SETUP_TEMPLATE(dev_attrs, field, S_IRUGO, 1)
+
+/**
+ * ata_attach_transport  --  instantiate ATA transport template
+ */
+struct scsi_transport_template *ata_attach_transport(void)
+{
+       struct ata_internal *i;
+       int count;
+
+       i = kzalloc(sizeof(struct ata_internal), GFP_KERNEL);
+       if (!i)
+               return NULL;
+
+       i->t.eh_strategy_handler        = ata_scsi_error;
+       i->t.eh_timed_out               = ata_scsi_timed_out;
+       i->t.user_scan                  = ata_scsi_user_scan;
+
+       i->t.host_attrs.ac.attrs = &i->port_attrs[0];
+       i->t.host_attrs.ac.class = &ata_port_class.class;
+       i->t.host_attrs.ac.match = ata_tport_match;
+       transport_container_register(&i->t.host_attrs);
+
+       i->link_attr_cont.ac.class = &ata_link_class.class;
+       i->link_attr_cont.ac.attrs = &i->link_attrs[0];
+       i->link_attr_cont.ac.match = ata_tlink_match;
+       transport_container_register(&i->link_attr_cont);
+
+       i->dev_attr_cont.ac.class = &ata_dev_class.class;
+       i->dev_attr_cont.ac.attrs = &i->dev_attrs[0];
+       i->dev_attr_cont.ac.match = ata_tdev_match;
+       transport_container_register(&i->dev_attr_cont);
+
+       count = 0;
+       SETUP_PORT_ATTRIBUTE(nr_pmp_links);
+       SETUP_PORT_ATTRIBUTE(idle_irq);
+       BUG_ON(count > ATA_PORT_ATTRS);
+       i->port_attrs[count] = NULL;
+
+       count = 0;
+       SETUP_LINK_ATTRIBUTE(hw_sata_spd_limit);
+       SETUP_LINK_ATTRIBUTE(sata_spd_limit);
+       SETUP_LINK_ATTRIBUTE(sata_spd);
+       BUG_ON(count > ATA_LINK_ATTRS);
+       i->link_attrs[count] = NULL;
+
+       count = 0;
+       SETUP_DEV_ATTRIBUTE(class);
+       SETUP_DEV_ATTRIBUTE(pio_mode);
+       SETUP_DEV_ATTRIBUTE(dma_mode);
+       SETUP_DEV_ATTRIBUTE(xfer_mode);
+       SETUP_DEV_ATTRIBUTE(spdn_cnt);
+       SETUP_DEV_ATTRIBUTE(ering);
+       SETUP_DEV_ATTRIBUTE(id);
+       SETUP_DEV_ATTRIBUTE(gscr);
+       BUG_ON(count > ATA_DEV_ATTRS);
+       i->dev_attrs[count] = NULL;
+
+       return &i->t;
+}
+
+/**
+ * ata_release_transport  --  release ATA transport template instance
+ * @t:         transport template instance
+ */
+void ata_release_transport(struct scsi_transport_template *t)
+{
+       struct ata_internal *i = to_ata_internal(t);
+
+       transport_container_unregister(&i->t.host_attrs);
+       transport_container_unregister(&i->link_attr_cont);
+       transport_container_unregister(&i->dev_attr_cont);
+
+       kfree(i);
+}
+
+__init int libata_transport_init(void)
+{
+       int error;
+
+       error = transport_class_register(&ata_link_class);
+       if (error)
+               goto out_unregister_transport;
+       error = transport_class_register(&ata_port_class);
+       if (error)
+               goto out_unregister_link;
+       error = transport_class_register(&ata_dev_class);
+       if (error)
+               goto out_unregister_port;
+       return 0;
+
+ out_unregister_port:
+       transport_class_unregister(&ata_port_class);
+ out_unregister_link:
+       transport_class_unregister(&ata_link_class);
+ out_unregister_transport:
+       return error;
+
+}
+
+void __exit libata_transport_exit(void)
+{
+       transport_class_unregister(&ata_link_class);
+       transport_class_unregister(&ata_port_class);
+       transport_class_unregister(&ata_dev_class);
+}
diff --git a/drivers/ata/libata-transport.h b/drivers/ata/libata-transport.h
new file mode 100644 (file)
index 0000000..2820cf8
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _LIBATA_TRANSPORT_H
+#define _LIBATA_TRANSPORT_H
+
+
+extern struct scsi_transport_template *ata_scsi_transport_template;
+
+int ata_tlink_add(struct ata_link *link);
+void ata_tlink_delete(struct ata_link *link);
+
+int ata_tport_add(struct device *parent, struct ata_port *ap);
+void ata_tport_delete(struct ata_port *ap);
+
+struct scsi_transport_template *ata_attach_transport(void);
+void ata_release_transport(struct scsi_transport_template *t);
+
+__init int libata_transport_init(void);
+void __exit libata_transport_exit(void);
+#endif
index 9ce1ecc63e394227348aae2a513a6cd204748748..a9be110dbf5175de1f66942c5d21da98ab86b053 100644 (file)
@@ -86,6 +86,8 @@ extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
 extern int ata_dev_configure(struct ata_device *dev);
 extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
 extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
+extern unsigned int ata_dev_set_feature(struct ata_device *dev,
+                                       u8 enable, u8 feature);
 extern void ata_sg_clean(struct ata_queued_cmd *qc);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
 extern void ata_qc_issue(struct ata_queued_cmd *qc);
@@ -100,8 +102,7 @@ extern int sata_link_init_spd(struct ata_link *link);
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern struct ata_port *ata_port_alloc(struct ata_host *host);
-extern void ata_dev_enable_pm(struct ata_device *dev, enum link_pm policy);
-extern void ata_lpm_schedule(struct ata_port *ap, enum link_pm);
+extern const char *sata_spd_string(unsigned int spd);
 
 /* libata-acpi.c */
 #ifdef CONFIG_ATA_ACPI
@@ -137,10 +138,15 @@ extern void ata_scsi_hotplug(struct work_struct *work);
 extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
 extern void ata_scsi_dev_rescan(struct work_struct *work);
 extern int ata_bus_probe(struct ata_port *ap);
+extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
+                             unsigned int id, unsigned int lun);
+
 
 /* libata-eh.c */
 extern unsigned long ata_internal_cmd_timeout(struct ata_device *dev, u8 cmd);
 extern void ata_internal_cmd_timed_out(struct ata_device *dev, u8 cmd);
+extern void ata_eh_acquire(struct ata_port *ap);
+extern void ata_eh_release(struct ata_port *ap);
 extern enum blk_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
@@ -164,11 +170,16 @@ extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
                          ata_postreset_fn_t postreset,
                          struct ata_link **r_failed_disk);
 extern void ata_eh_finish(struct ata_port *ap);
+extern int ata_ering_map(struct ata_ering *ering,
+                        int (*map_fn)(struct ata_ering_entry *, void *),
+                        void *arg);
 
 /* libata-pmp.c */
 #ifdef CONFIG_SATA_PMP
 extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
 extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                           unsigned hints);
 extern int sata_pmp_attach(struct ata_device *dev);
 #else /* CONFIG_SATA_PMP */
 static inline int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val)
@@ -181,6 +192,12 @@ static inline int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
        return -EINVAL;
 }
 
+static inline int sata_pmp_set_lpm(struct ata_link *link,
+                                  enum ata_lpm_policy policy, unsigned hints)
+{
+       return -EINVAL;
+}
+
 static inline int sata_pmp_attach(struct ata_device *dev)
 {
        return -EINVAL;
index 9cae65de750e10777260d2e3e9d9bbab2026b768..ec2c777fcdb008efec7399e29054ef967cc3bed4 100644 (file)
@@ -826,7 +826,7 @@ static void bfin_dev_select(struct ata_port *ap, unsigned int device)
  *     @ctl: value to write
  */
 
-static u8 bfin_set_devctl(struct ata_port *ap, u8 ctl)
+static void bfin_set_devctl(struct ata_port *ap, u8 ctl)
 {
        void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
        write_atapi_register(base, ATA_REG_CTRL, ctl);
@@ -1046,7 +1046,7 @@ static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
                        dev1 = 0;
                        break;
                }
-               msleep(50);     /* give drive a breather */
+               ata_msleep(ap, 50);     /* give drive a breather */
        }
        if (dev1)
                ata_sff_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
@@ -1087,7 +1087,7 @@ static unsigned int bfin_bus_softreset(struct ata_port *ap,
         *
         * Old drivers/ide uses the 2mS rule and then waits for ready
         */
-       msleep(150);
+       ata_msleep(ap, 150);
 
        /* Before we perform post reset processing we want to see if
         * the bus shows 0xFF because the odd clown forgets the D7
index e5f289f59ca3203cc1d2ef7938925e60ef727159..549d28dbf90dd89db7b26e8f0e4f335616a64541 100644 (file)
@@ -161,6 +161,17 @@ static int cmd640_port_start(struct ata_port *ap)
        return 0;
 }
 
+static bool cmd640_sff_irq_check(struct ata_port *ap)
+{
+       struct pci_dev *pdev    = to_pci_dev(ap->host->dev);
+       int irq_reg             = ap->port_no ? ARTIM23 : CFR;
+       u8  irq_stat, irq_mask  = ap->port_no ? 0x10 : 0x04;
+
+       pci_read_config_byte(pdev, irq_reg, &irq_stat);
+
+       return irq_stat & irq_mask;
+}
+
 static struct scsi_host_template cmd640_sht = {
        ATA_PIO_SHT(DRV_NAME),
 };
@@ -169,6 +180,7 @@ static struct ata_port_operations cmd640_port_ops = {
        .inherits       = &ata_sff_port_ops,
        /* In theory xfer_noirq is not needed once we kill the prefetcher */
        .sff_data_xfer  = ata_sff_data_xfer_noirq,
+       .sff_irq_check  = cmd640_sff_irq_check,
        .qc_issue       = cmd640_qc_issue,
        .cable_detect   = ata_cable_40wire,
        .set_piomode    = cmd640_set_piomode,
index e944aa0c5517caaed7fc3cb8f10639245e8a3e3f..806292160b3f3c89ae698b9d279ea5d35c943680 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/ata.h>
 #include <linux/libata.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/cisreg.h>
@@ -168,63 +167,26 @@ static struct ata_port_operations pcmcia_8bit_port_ops = {
 };
 
 
-struct pcmcia_config_check {
-       unsigned long ctl_base;
-       int skip_vcc;
-       int is_kme;
-};
-
-static int pcmcia_check_one_config(struct pcmcia_device *pdev,
-                                  cistpl_cftable_entry_t *cfg,
-                                  cistpl_cftable_entry_t *dflt,
-                                  unsigned int vcc,
-                                  void *priv_data)
+static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
 {
-       struct pcmcia_config_check *stk = priv_data;
-
-       /* Check for matching Vcc, unless we're desperate */
-       if (!stk->skip_vcc) {
-               if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                       if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
-                               return -ENODEV;
-               } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                       if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
-                               return -ENODEV;
-               }
+       int *is_kme = priv_data;
+
+       if (!(pdev->resource[0]->flags & IO_DATA_PATH_WIDTH_8)) {
+               pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+               pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
        }
+       pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+       pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
 
-       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               pdev->resource[0]->start = io->win[0].base;
-               if (!(io->flags & CISTPL_IO_16BIT)) {
-                       pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-                       pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-               }
-               if (io->nwin == 2) {
-                       pdev->resource[0]->end = 8;
-                       pdev->resource[1]->start = io->win[1].base;
-                       pdev->resource[1]->end = (stk->is_kme) ? 2 : 1;
-                       if (pcmcia_request_io(pdev) != 0)
-                               return -ENODEV;
-                       stk->ctl_base = pdev->resource[1]->start;
-               } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-                       pdev->resource[0]->end = io->win[0].len;
-                       pdev->resource[1]->end = 0;
-                       if (pcmcia_request_io(pdev) != 0)
-                               return -ENODEV;
-                       stk->ctl_base = pdev->resource[0]->start + 0x0e;
-               } else
+       if (pdev->resource[1]->end) {
+               pdev->resource[0]->end = 8;
+               pdev->resource[1]->end = (*is_kme) ? 2 : 1;
+       } else {
+               if (pdev->resource[0]->end < 16)
                        return -ENODEV;
-               /* If we've got this far, we're done */
-               return 0;
        }
-       return -ENODEV;
+
+       return pcmcia_request_io(pdev);
 }
 
 /**
@@ -239,7 +201,6 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
 {
        struct ata_host *host;
        struct ata_port *ap;
-       struct pcmcia_config_check *stk = NULL;
        int is_kme = 0, ret = -ENOMEM, p;
        unsigned long io_base, ctl_base;
        void __iomem *io_addr, *ctl_addr;
@@ -247,10 +208,8 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
        struct ata_port_operations *ops = &pcmcia_port_ops;
 
        /* Set up attributes in order to probe card and get resources */
-       pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-       pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-       pdev->conf.Attributes = CONF_ENABLE_IRQ;
-       pdev->conf.IntType = INT_MEMORY_AND_IO;
+       pdev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO |
+               CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
 
        /* See if we have a manufacturer identifier. Use it to set is_kme for
           vendor quirks */
@@ -258,25 +217,21 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
                  ((pdev->card_id == PRODID_KME_KXLC005_A) ||
                   (pdev->card_id == PRODID_KME_KXLC005_B)));
 
-       /* Allocate resoure probing structures */
-
-       stk = kzalloc(sizeof(*stk), GFP_KERNEL);
-       if (!stk)
-               goto out1;
-       stk->is_kme = is_kme;
-       stk->skip_vcc = io_base = ctl_base = 0;
-
-       if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk)) {
-               stk->skip_vcc = 1;
-               if (pcmcia_loop_config(pdev, pcmcia_check_one_config, stk))
+       if (pcmcia_loop_config(pdev, pcmcia_check_one_config, &is_kme)) {
+               pdev->config_flags &= ~CONF_AUTO_CHECK_VCC;
+               if (pcmcia_loop_config(pdev, pcmcia_check_one_config, &is_kme))
                        goto failed; /* No suitable config found */
        }
        io_base = pdev->resource[0]->start;
-       ctl_base = stk->ctl_base;
+       if (pdev->resource[1]->end)
+               ctl_base = pdev->resource[1]->start;
+       else
+               ctl_base = pdev->resource[0]->start + 0x0e;
+
        if (!pdev->irq)
                goto failed;
 
-       ret = pcmcia_request_configuration(pdev, &pdev->conf);
+       ret = pcmcia_enable_device(pdev);
        if (ret)
                goto failed;
 
@@ -329,13 +284,10 @@ static int pcmcia_init_one(struct pcmcia_device *pdev)
                goto failed;
 
        pdev->priv = host;
-       kfree(stk);
        return 0;
 
 failed:
-       kfree(stk);
        pcmcia_disable_device(pdev);
-out1:
        return ret;
 }
 
@@ -430,9 +382,7 @@ MODULE_DEVICE_TABLE(pcmcia, pcmcia_devices);
 
 static struct pcmcia_driver pcmcia_driver = {
        .owner          = THIS_MODULE,
-       .drv = {
-               .name           = DRV_NAME,
-       },
+       .name           = DRV_NAME,
        .id_table       = pcmcia_devices,
        .probe          = pcmcia_init_one,
        .remove         = pcmcia_remove_one,
index c39f213e1bbcba37605d39928125182edbb903c5..c2ed5868dda6086ded4335539eb7fddfd37135a9 100644 (file)
@@ -44,6 +44,27 @@ static void pdc202xx_exec_command(struct ata_port *ap,
        ndelay(400);
 }
 
+static bool pdc202xx_irq_check(struct ata_port *ap)
+{
+       struct pci_dev *pdev    = to_pci_dev(ap->host->dev);
+       unsigned long master    = pci_resource_start(pdev, 4);
+       u8 sc1d                 = inb(master + 0x1d);
+
+       if (ap->port_no) {
+               /*
+                * bit 7: error, bit 6: interrupting,
+                * bit 5: FIFO full, bit 4: FIFO empty
+                */
+               return sc1d & 0x40;
+       } else  {
+               /*
+                * bit 3: error, bit 2: interrupting,
+                * bit 1: FIFO full, bit 0: FIFO empty
+                */
+               return sc1d & 0x04;
+       }
+}
+
 /**
  *     pdc202xx_configure_piomode      -       set chip PIO timing
  *     @ap: ATA interface
@@ -282,6 +303,7 @@ static struct ata_port_operations pdc2024x_port_ops = {
        .set_dmamode            = pdc202xx_set_dmamode,
 
        .sff_exec_command       = pdc202xx_exec_command,
+       .sff_irq_check          = pdc202xx_irq_check,
 };
 
 static struct ata_port_operations pdc2026x_port_ops = {
@@ -297,6 +319,7 @@ static struct ata_port_operations pdc2026x_port_ops = {
        .port_start             = pdc2026x_port_start,
 
        .sff_exec_command       = pdc202xx_exec_command,
+       .sff_irq_check          = pdc202xx_irq_check,
 };
 
 static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
index 6f9cfb24b751fbefb816bed7bb5b32399135c149..8a51d673e5b29e5073978ba9cdc11baa314fc88f 100644 (file)
@@ -322,7 +322,7 @@ static int pata_s3c_wait_after_reset(struct ata_link *link,
 {
        int rc;
 
-       msleep(ATA_WAIT_AFTER_RESET);
+       ata_msleep(link->ap, ATA_WAIT_AFTER_RESET);
 
        /* always check readiness of the master device */
        rc = ata_sff_wait_ready(link, deadline);
index fe36966f7e347dedd4781cef96fcec5ff79e62f3..093715c3273a9fd0fa00cec911f83972710615fa 100644 (file)
@@ -530,7 +530,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
         *
         * Old drivers/ide uses the 2mS rule and then waits for ready.
         */
-       msleep(150);
+       ata_msleep(ap, 150);
 
        /* always check readiness of the master device */
        rc = ata_sff_wait_ready(link, deadline);
@@ -559,7 +559,7 @@ static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
                        lbal = in_be32(ioaddr->lbal_addr);
                        if ((nsect == 1) && (lbal == 1))
                                break;
-                       msleep(50);     /* give drive a breather */
+                       ata_msleep(ap, 50);     /* give drive a breather */
                }
 
                rc = ata_sff_wait_ready(link, deadline);
index d3190d7ec304034458c6979f08f40059ac80643e..00eefbd84b33ebc927224f6dc343fd0f71707a42 100644 (file)
@@ -202,14 +202,25 @@ static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev)
  *     LOCKING:
  *     spin_lock_irqsave(host lock)
  */
-void sil680_sff_exec_command(struct ata_port *ap,
-                                       const struct ata_taskfile *tf)
+static void sil680_sff_exec_command(struct ata_port *ap,
+                                   const struct ata_taskfile *tf)
 {
        DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
        iowrite8(tf->command, ap->ioaddr.command_addr);
        ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 }
 
+static bool sil680_sff_irq_check(struct ata_port *ap)
+{
+       struct pci_dev *pdev    = to_pci_dev(ap->host->dev);
+       unsigned long addr      = sil680_selreg(ap, 1);
+       u8 val;
+
+       pci_read_config_byte(pdev, addr, &val);
+
+       return val & 0x08;
+}
+
 static struct scsi_host_template sil680_sht = {
        ATA_BMDMA_SHT(DRV_NAME),
 };
@@ -218,6 +229,7 @@ static struct scsi_host_template sil680_sht = {
 static struct ata_port_operations sil680_port_ops = {
        .inherits               = &ata_bmdma32_port_ops,
        .sff_exec_command       = sil680_sff_exec_command,
+       .sff_irq_check          = sil680_sff_irq_check,
        .cable_detect           = sil680_cable_detect,
        .set_piomode            = sil680_set_piomode,
        .set_dmamode            = sil680_set_dmamode,
index 98548f640c8eae74bc408b67273f529dd9b8a310..7f5d020ed56c445b712198d4d4bb133ec77e2761 100644 (file)
@@ -227,6 +227,16 @@ static int sl82c105_qc_defer(struct ata_queued_cmd *qc)
        return 0;
 }
 
+static bool sl82c105_sff_irq_check(struct ata_port *ap)
+{
+       struct pci_dev *pdev    = to_pci_dev(ap->host->dev);
+       u32 val, mask           = ap->port_no ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
+
+       pci_read_config_dword(pdev, 0x40, &val);
+
+       return val & mask;
+}
+
 static struct scsi_host_template sl82c105_sht = {
        ATA_BMDMA_SHT(DRV_NAME),
 };
@@ -239,6 +249,7 @@ static struct ata_port_operations sl82c105_port_ops = {
        .cable_detect   = ata_cable_40wire,
        .set_piomode    = sl82c105_set_piomode,
        .prereset       = sl82c105_pre_reset,
+       .sff_irq_check  = sl82c105_sff_irq_check,
 };
 
 /**
index 7325f77480dcb77296d148f8566bd64148a4cf3e..b0214d00d50bb469de76b40fb8a4f81f70cbb161 100644 (file)
@@ -678,7 +678,7 @@ static void sata_fsl_port_stop(struct ata_port *ap)
        iowrite32(temp, hcr_base + HCONTROL);
 
        /* Poll for controller to go offline - should happen immediately */
-       ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1);
+       ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, ONLINE, 1, 1);
 
        ap->private_data = NULL;
        dma_free_coherent(dev, SATA_FSL_PORT_PRIV_DMA_SZ,
@@ -729,7 +729,8 @@ try_offline_again:
        iowrite32(temp, hcr_base + HCONTROL);
 
        /* Poll for controller to go offline */
-       temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, ONLINE, 1, 500);
+       temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, ONLINE,
+                                1, 500);
 
        if (temp & ONLINE) {
                ata_port_printk(ap, KERN_ERR,
@@ -752,7 +753,7 @@ try_offline_again:
        /*
         * PHY reset should remain asserted for atleast 1ms
         */
-       msleep(1);
+       ata_msleep(ap, 1);
 
        /*
         * Now, bring the host controller online again, this can take time
@@ -766,7 +767,7 @@ try_offline_again:
        temp |= HCONTROL_PMP_ATTACHED;
        iowrite32(temp, hcr_base + HCONTROL);
 
-       temp = ata_wait_register(hcr_base + HSTATUS, ONLINE, 0, 1, 500);
+       temp = ata_wait_register(ap, hcr_base + HSTATUS, ONLINE, 0, 1, 500);
 
        if (!(temp & ONLINE)) {
                ata_port_printk(ap, KERN_ERR,
@@ -784,7 +785,7 @@ try_offline_again:
         * presence
         */
 
-       temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0, 1, 500);
+       temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0, 1, 500);
        if ((!(temp & 0x10)) || ata_link_offline(link)) {
                ata_port_printk(ap, KERN_WARNING,
                                "No Device OR PHYRDY change,Hstatus = 0x%x\n",
@@ -797,7 +798,7 @@ try_offline_again:
         * Wait for the first D2H from device,i.e,signature update notification
         */
        start_jiffies = jiffies;
-       temp = ata_wait_register(hcr_base + HSTATUS, 0xFF, 0x10,
+       temp = ata_wait_register(ap, hcr_base + HSTATUS, 0xFF, 0x10,
                        500, jiffies_to_msecs(deadline - start_jiffies));
 
        if ((temp & 0xFF) != 0x18) {
@@ -880,7 +881,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
                iowrite32(pmp, CQPMP + hcr_base);
        iowrite32(1, CQ + hcr_base);
 
-       temp = ata_wait_register(CQ + hcr_base, 0x1, 0x1, 1, 5000);
+       temp = ata_wait_register(ap, CQ + hcr_base, 0x1, 0x1, 1, 5000);
        if (temp & 0x1) {
                ata_port_printk(ap, KERN_WARNING, "ATA_SRST issue failed\n");
 
@@ -896,7 +897,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
                goto err;
        }
 
-       msleep(1);
+       ata_msleep(ap, 1);
 
        /*
         * SATA device enters reset state after receving a Control register
@@ -915,7 +916,7 @@ static int sata_fsl_softreset(struct ata_link *link, unsigned int *class,
        if (pmp != SATA_PMP_CTRL_PORT)
                iowrite32(pmp, CQPMP + hcr_base);
        iowrite32(1, CQ + hcr_base);
-       msleep(150);            /* ?? */
+       ata_msleep(ap, 150);            /* ?? */
 
        /*
         * The above command would have signalled an interrupt on command
@@ -1137,17 +1138,13 @@ static void sata_fsl_host_intr(struct ata_port *ap)
                        ioread32(hcr_base + CE));
 
                for (i = 0; i < SATA_FSL_QUEUE_DEPTH; i++) {
-                       if (done_mask & (1 << i)) {
-                               qc = ata_qc_from_tag(ap, i);
-                               if (qc) {
-                                       ata_qc_complete(qc);
-                               }
+                       if (done_mask & (1 << i))
                                DPRINTK
                                    ("completing ncq cmd,tag=%d,CC=0x%x,CA=0x%x\n",
                                     i, ioread32(hcr_base + CC),
                                     ioread32(hcr_base + CA));
-                       }
                }
+               ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
                return;
 
        } else if ((ap->qc_active & (1 << ATA_TAG_INTERNAL))) {
index a36149ebf4a2c835717ab820915a4f76af0201ee..83a44471b1897b7d93acb7220ce0ac71a492c28b 100644 (file)
@@ -614,7 +614,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
 
        writew(IDMA_CTL_RST_ATA, idma_ctl);
        readw(idma_ctl);        /* flush */
-       msleep(1);
+       ata_msleep(ap, 1);
        writew(0, idma_ctl);
 
        rc = sata_link_resume(link, timing, deadline);
index a9fd9709c2627c7514fe74a8ec9ebc26f09b44f9..bf74a36d3cc3b4904363e97d4656c9e48fbe1a6f 100644 (file)
@@ -2743,18 +2743,11 @@ static void mv_err_intr(struct ata_port *ap)
        }
 }
 
-static void mv_process_crpb_response(struct ata_port *ap,
+static bool mv_process_crpb_response(struct ata_port *ap,
                struct mv_crpb *response, unsigned int tag, int ncq_enabled)
 {
        u8 ata_status;
        u16 edma_status = le16_to_cpu(response->flags);
-       struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
-
-       if (unlikely(!qc)) {
-               ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n",
-                               __func__, tag);
-               return;
-       }
 
        /*
         * edma_status from a response queue entry:
@@ -2768,13 +2761,14 @@ static void mv_process_crpb_response(struct ata_port *ap,
                         * Error will be seen/handled by
                         * mv_err_intr().  So do nothing at all here.
                         */
-                       return;
+                       return false;
                }
        }
        ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
        if (!ac_err_mask(ata_status))
-               ata_qc_complete(qc);
+               return true;
        /* else: leave it for mv_err_intr() */
+       return false;
 }
 
 static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp)
@@ -2783,6 +2777,7 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
        struct mv_host_priv *hpriv = ap->host->private_data;
        u32 in_index;
        bool work_done = false;
+       u32 done_mask = 0;
        int ncq_enabled = (pp->pp_flags & MV_PP_FLAG_NCQ_EN);
 
        /* Get the hardware queue position index */
@@ -2803,15 +2798,19 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
                        /* Gen II/IIE: get command tag from CRPB entry */
                        tag = le16_to_cpu(response->id) & 0x1f;
                }
-               mv_process_crpb_response(ap, response, tag, ncq_enabled);
+               if (mv_process_crpb_response(ap, response, tag, ncq_enabled))
+                       done_mask |= 1 << tag;
                work_done = true;
        }
 
-       /* Update the software queue position index in hardware */
-       if (work_done)
+       if (work_done) {
+               ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
+
+               /* Update the software queue position index in hardware */
                writelfl((pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK) |
                         (pp->resp_idx << EDMA_RSP_Q_PTR_SHIFT),
                         port_mmio + EDMA_RSP_Q_OUT_PTR);
+       }
 }
 
 static void mv_port_intr(struct ata_port *ap, u32 port_cause)
index cb89ef8d99d94468ed2cfba330f19b65d413d524..7254e255fd7868b6bfdb82d4d1e17dec560bebb0 100644 (file)
@@ -873,29 +873,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
                        ata_port_freeze(ap);
                else
                        ata_port_abort(ap);
-               return 1;
+               return -1;
        }
 
-       if (likely(flags & NV_CPB_RESP_DONE)) {
-               struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
-               VPRINTK("CPB flags done, flags=0x%x\n", flags);
-               if (likely(qc)) {
-                       DPRINTK("Completing qc from tag %d\n", cpb_num);
-                       ata_qc_complete(qc);
-               } else {
-                       struct ata_eh_info *ehi = &ap->link.eh_info;
-                       /* Notifier bits set without a command may indicate the drive
-                          is misbehaving. Raise host state machine violation on this
-                          condition. */
-                       ata_port_printk(ap, KERN_ERR,
-                                       "notifier for tag %d with no cmd?\n",
-                                       cpb_num);
-                       ehi->err_mask |= AC_ERR_HSM;
-                       ehi->action |= ATA_EH_RESET;
-                       ata_port_freeze(ap);
-                       return 1;
-               }
-       }
+       if (likely(flags & NV_CPB_RESP_DONE))
+               return 1;
        return 0;
 }
 
@@ -1018,6 +1000,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
                              NV_ADMA_STAT_CPBERR |
                              NV_ADMA_STAT_CMD_COMPLETE)) {
                        u32 check_commands = notifier_clears[i];
+                       u32 done_mask = 0;
                        int pos, rc;
 
                        if (status & NV_ADMA_STAT_CPBERR) {
@@ -1034,10 +1017,13 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
                                pos--;
                                rc = nv_adma_check_cpb(ap, pos,
                                                notifier_error & (1 << pos));
-                               if (unlikely(rc))
+                               if (rc > 0)
+                                       done_mask |= 1 << pos;
+                               else if (unlikely(rc < 0))
                                        check_commands = 0;
                                check_commands &= ~(1 << pos);
                        }
+                       ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
                }
        }
 
@@ -2132,7 +2118,6 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
        struct ata_eh_info *ehi = &ap->link.eh_info;
        u32 sactive;
        u32 done_mask;
-       int i;
        u8 host_stat;
        u8 lack_dhfis = 0;
 
@@ -2152,27 +2137,11 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
        sactive = readl(pp->sactive_block);
        done_mask = pp->qc_active ^ sactive;
 
-       if (unlikely(done_mask & sactive)) {
-               ata_ehi_clear_desc(ehi);
-               ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition"
-                                 "(%08x->%08x)", pp->qc_active, sactive);
-               ehi->err_mask |= AC_ERR_HSM;
-               ehi->action |= ATA_EH_RESET;
-               return -EINVAL;
-       }
-       for (i = 0; i < ATA_MAX_QUEUE; i++) {
-               if (!(done_mask & (1 << i)))
-                       continue;
-
-               qc = ata_qc_from_tag(ap, i);
-               if (qc) {
-                       ata_qc_complete(qc);
-                       pp->qc_active &= ~(1 << i);
-                       pp->dhfis_bits &= ~(1 << i);
-                       pp->dmafis_bits &= ~(1 << i);
-                       pp->sdbfis_bits |= (1 << i);
-               }
-       }
+       pp->qc_active &= ~done_mask;
+       pp->dhfis_bits &= ~done_mask;
+       pp->dmafis_bits &= ~done_mask;
+       pp->sdbfis_bits |= done_mask;
+       ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
 
        if (!ap->qc_active) {
                DPRINTK("over\n");
index be7726d7686dd1b11368948ff2cd8645a5368dbd..af41c6fd1254876028866b53a323fe2edb1aac8b 100644 (file)
@@ -589,9 +589,9 @@ static int sil24_init_port(struct ata_port *ap)
                sil24_clear_pmp(ap);
 
        writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
-       ata_wait_register(port + PORT_CTRL_STAT,
+       ata_wait_register(ap, port + PORT_CTRL_STAT,
                          PORT_CS_INIT, PORT_CS_INIT, 10, 100);
-       tmp = ata_wait_register(port + PORT_CTRL_STAT,
+       tmp = ata_wait_register(ap, port + PORT_CTRL_STAT,
                                PORT_CS_RDY, 0, 10, 100);
 
        if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
@@ -631,7 +631,7 @@ static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
        writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
 
        irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
-       irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+       irq_stat = ata_wait_register(ap, port + PORT_IRQ_STAT, irq_mask, 0x0,
                                     10, timeout_msec);
 
        writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
@@ -719,9 +719,9 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
                                "state, performing PORT_RST\n");
 
                writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
-               msleep(10);
+               ata_msleep(ap, 10);
                writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
-               ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
+               ata_wait_register(ap, port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
                                  10, 5000);
 
                /* restore port configuration */
@@ -740,7 +740,7 @@ static int sil24_hardreset(struct ata_link *link, unsigned int *class,
                tout_msec = 5000;
 
        writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
-       tmp = ata_wait_register(port + PORT_CTRL_STAT,
+       tmp = ata_wait_register(ap, port + PORT_CTRL_STAT,
                                PORT_CS_DEV_RST, PORT_CS_DEV_RST, 10,
                                tout_msec);
 
@@ -1253,7 +1253,7 @@ static void sil24_init_controller(struct ata_host *host)
                tmp = readl(port + PORT_CTRL_STAT);
                if (tmp & PORT_CS_PORT_RST) {
                        writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
-                       tmp = ata_wait_register(port + PORT_CTRL_STAT,
+                       tmp = ata_wait_register(NULL, port + PORT_CTRL_STAT,
                                                PORT_CS_PORT_RST,
                                                PORT_CS_PORT_RST, 10, 100);
                        if (tmp & PORT_CS_PORT_RST)
index 4730c42a5ee58c54a295dc6a72e493f7b91cd411..c21589986c695f38756d1ced8a13422acfa3cac9 100644 (file)
@@ -349,7 +349,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
 
        /* wait for phy to become ready, if necessary */
        do {
-               msleep(200);
+               ata_msleep(link->ap, 200);
                svia_scr_read(link, SCR_STATUS, &sstatus);
                if ((sstatus & 0xf) != 1)
                        break;
index cbccf9a3cee49a67b0952e633065f54ff7357747..abe46edfe5b41b9c2c5b39640c94c2208ffe283b 100644 (file)
@@ -3,6 +3,7 @@ obj-$(CONFIG_PM_SLEEP)  += main.o wakeup.o
 obj-$(CONFIG_PM_RUNTIME)       += runtime.o
 obj-$(CONFIG_PM_OPS)   += generic_ops.o
 obj-$(CONFIG_PM_TRACE_RTC)     += trace.o
+obj-$(CONFIG_PM_OPP)   += opp.o
 
 ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
 ccflags-$(CONFIG_PM_VERBOSE)   += -DDEBUG
index 4b29d4981253a22d8386b50dd74ca1a046ca6682..81f2c84697f450544f3dfef66b1726cdfac83728 100644 (file)
@@ -46,7 +46,7 @@ int pm_generic_runtime_suspend(struct device *dev)
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        int ret;
 
-       ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : -EINVAL;
+       ret = pm && pm->runtime_suspend ? pm->runtime_suspend(dev) : 0;
 
        return ret;
 }
@@ -65,7 +65,7 @@ int pm_generic_runtime_resume(struct device *dev)
        const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
        int ret;
 
-       ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : -EINVAL;
+       ret = pm && pm->runtime_resume ? pm->runtime_resume(dev) : 0;
 
        return ret;
 }
index 276d5a701dc37cfbebc828a88efc824abc163774..31b526661ec4d78346c3b6edd04b733705285797 100644 (file)
@@ -51,6 +51,8 @@ static pm_message_t pm_transition;
  */
 static bool transition_started;
 
+static int async_error;
+
 /**
  * device_pm_init - Initialize the PM-related part of a device object.
  * @dev: Device object being initialized.
@@ -60,7 +62,8 @@ void device_pm_init(struct device *dev)
        dev->power.status = DPM_ON;
        init_completion(&dev->power.completion);
        complete_all(&dev->power.completion);
-       dev->power.wakeup_count = 0;
+       dev->power.wakeup = NULL;
+       spin_lock_init(&dev->power.lock);
        pm_runtime_init(dev);
 }
 
@@ -120,6 +123,7 @@ void device_pm_remove(struct device *dev)
        mutex_lock(&dpm_list_mtx);
        list_del_init(&dev->power.entry);
        mutex_unlock(&dpm_list_mtx);
+       device_wakeup_disable(dev);
        pm_runtime_remove(dev);
 }
 
@@ -407,7 +411,7 @@ static void pm_dev_err(struct device *dev, pm_message_t state, char *info,
 static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
 {
        ktime_t calltime;
-       s64 usecs64;
+       u64 usecs64;
        int usecs;
 
        calltime = ktime_get();
@@ -600,6 +604,7 @@ static void dpm_resume(pm_message_t state)
        INIT_LIST_HEAD(&list);
        mutex_lock(&dpm_list_mtx);
        pm_transition = state;
+       async_error = 0;
 
        list_for_each_entry(dev, &dpm_list, power.entry) {
                if (dev->power.status < DPM_OFF)
@@ -829,8 +834,6 @@ static int legacy_suspend(struct device *dev, pm_message_t state,
        return error;
 }
 
-static int async_error;
-
 /**
  * device_suspend - Execute "suspend" callbacks for given device.
  * @dev: Device to handle.
@@ -885,6 +888,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
        device_unlock(dev);
        complete_all(&dev->power.completion);
 
+       if (error)
+               async_error = error;
+
        return error;
 }
 
@@ -894,10 +900,8 @@ static void async_suspend(void *data, async_cookie_t cookie)
        int error;
 
        error = __device_suspend(dev, pm_transition, true);
-       if (error) {
+       if (error)
                pm_dev_err(dev, pm_transition, " async", error);
-               async_error = error;
-       }
 
        put_device(dev);
 }
@@ -1085,8 +1089,9 @@ EXPORT_SYMBOL_GPL(__suspend_report_result);
  * @dev: Device to wait for.
  * @subordinate: Device that needs to wait for @dev.
  */
-void device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
+int device_pm_wait_for_dev(struct device *subordinate, struct device *dev)
 {
        dpm_wait(dev, subordinate->power.async_suspend);
+       return async_error;
 }
 EXPORT_SYMBOL_GPL(device_pm_wait_for_dev);
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
new file mode 100644 (file)
index 0000000..2bb9b4c
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ * Generic OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *     Nishanth Menon
+ *     Romit Dasgupta
+ *     Kevin Hilman
+ *
+ * This program is free software; you can 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/errno.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/cpufreq.h>
+#include <linux/list.h>
+#include <linux/rculist.h>
+#include <linux/rcupdate.h>
+#include <linux/opp.h>
+
+/*
+ * Internal data structure organization with the OPP layer library is as
+ * follows:
+ * dev_opp_list (root)
+ *     |- device 1 (represents voltage domain 1)
+ *     |       |- opp 1 (availability, freq, voltage)
+ *     |       |- opp 2 ..
+ *     ...     ...
+ *     |       `- opp n ..
+ *     |- device 2 (represents the next voltage domain)
+ *     ...
+ *     `- device m (represents mth voltage domain)
+ * device 1, 2.. are represented by dev_opp structure while each opp
+ * is represented by the opp structure.
+ */
+
+/**
+ * struct opp - Generic OPP description structure
+ * @node:      opp list node. The nodes are maintained throughout the lifetime
+ *             of boot. It is expected only an optimal set of OPPs are
+ *             added to the library by the SoC framework.
+ *             RCU usage: opp list is traversed with RCU locks. node
+ *             modification is possible realtime, hence the modifications
+ *             are protected by the dev_opp_list_lock for integrity.
+ *             IMPORTANT: the opp nodes should be maintained in increasing
+ *             order.
+ * @available: true/false - marks if this OPP as available or not
+ * @rate:      Frequency in hertz
+ * @u_volt:    Nominal voltage in microvolts corresponding to this OPP
+ * @dev_opp:   points back to the device_opp struct this opp belongs to
+ *
+ * This structure stores the OPP information for a given device.
+ */
+struct opp {
+       struct list_head node;
+
+       bool available;
+       unsigned long rate;
+       unsigned long u_volt;
+
+       struct device_opp *dev_opp;
+};
+
+/**
+ * struct device_opp - Device opp structure
+ * @node:      list node - contains the devices with OPPs that
+ *             have been registered. Nodes once added are not modified in this
+ *             list.
+ *             RCU usage: nodes are not modified in the list of device_opp,
+ *             however addition is possible and is secured by dev_opp_list_lock
+ * @dev:       device pointer
+ * @opp_list:  list of opps
+ *
+ * This is an internal data structure maintaining the link to opps attached to
+ * a device. This structure is not meant to be shared to users as it is
+ * meant for book keeping and private to OPP library
+ */
+struct device_opp {
+       struct list_head node;
+
+       struct device *dev;
+       struct list_head opp_list;
+};
+
+/*
+ * The root of the list of all devices. All device_opp structures branch off
+ * from here, with each device_opp containing the list of opp it supports in
+ * various states of availability.
+ */
+static LIST_HEAD(dev_opp_list);
+/* Lock to allow exclusive modification to the device and opp lists */
+static DEFINE_MUTEX(dev_opp_list_lock);
+
+/**
+ * find_device_opp() - find device_opp struct using device pointer
+ * @dev:       device pointer used to lookup device OPPs
+ *
+ * Search list of device OPPs for one containing matching device. Does a RCU
+ * reader operation to grab the pointer needed.
+ *
+ * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or
+ * -EINVAL based on type of error.
+ *
+ * Locking: This function must be called under rcu_read_lock(). device_opp
+ * is a RCU protected pointer. This means that device_opp is valid as long
+ * as we are under RCU lock.
+ */
+static struct device_opp *find_device_opp(struct device *dev)
+{
+       struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV);
+
+       if (unlikely(IS_ERR_OR_NULL(dev))) {
+               pr_err("%s: Invalid parameters\n", __func__);
+               return ERR_PTR(-EINVAL);
+       }
+
+       list_for_each_entry_rcu(tmp_dev_opp, &dev_opp_list, node) {
+               if (tmp_dev_opp->dev == dev) {
+                       dev_opp = tmp_dev_opp;
+                       break;
+               }
+       }
+
+       return dev_opp;
+}
+
+/**
+ * opp_get_voltage() - Gets the voltage corresponding to an available opp
+ * @opp:       opp for which voltage has to be returned for
+ *
+ * Return voltage in micro volt corresponding to the opp, else
+ * return 0
+ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. This means that opp which could have been fetched by
+ * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
+ * under RCU lock. The pointer returned by the opp_find_freq family must be
+ * used in the same section as the usage of this function with the pointer
+ * prior to unlocking with rcu_read_unlock() to maintain the integrity of the
+ * pointer.
+ */
+unsigned long opp_get_voltage(struct opp *opp)
+{
+       struct opp *tmp_opp;
+       unsigned long v = 0;
+
+       tmp_opp = rcu_dereference(opp);
+       if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
+               pr_err("%s: Invalid parameters\n", __func__);
+       else
+               v = tmp_opp->u_volt;
+
+       return v;
+}
+
+/**
+ * opp_get_freq() - Gets the frequency corresponding to an available opp
+ * @opp:       opp for which frequency has to be returned for
+ *
+ * Return frequency in hertz corresponding to the opp, else
+ * return 0
+ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. This means that opp which could have been fetched by
+ * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
+ * under RCU lock. The pointer returned by the opp_find_freq family must be
+ * used in the same section as the usage of this function with the pointer
+ * prior to unlocking with rcu_read_unlock() to maintain the integrity of the
+ * pointer.
+ */
+unsigned long opp_get_freq(struct opp *opp)
+{
+       struct opp *tmp_opp;
+       unsigned long f = 0;
+
+       tmp_opp = rcu_dereference(opp);
+       if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
+               pr_err("%s: Invalid parameters\n", __func__);
+       else
+               f = tmp_opp->rate;
+
+       return f;
+}
+
+/**
+ * opp_get_opp_count() - Get number of opps available in the opp list
+ * @dev:       device for which we do this operation
+ *
+ * This function returns the number of available opps if there are any,
+ * else returns 0 if none or the corresponding error value.
+ *
+ * Locking: This function must be called under rcu_read_lock(). This function
+ * internally references two RCU protected structures: device_opp and opp which
+ * are safe as long as we are under a common RCU locked section.
+ */
+int opp_get_opp_count(struct device *dev)
+{
+       struct device_opp *dev_opp;
+       struct opp *temp_opp;
+       int count = 0;
+
+       dev_opp = find_device_opp(dev);
+       if (IS_ERR(dev_opp)) {
+               int r = PTR_ERR(dev_opp);
+               dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
+               return r;
+       }
+
+       list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+               if (temp_opp->available)
+                       count++;
+       }
+
+       return count;
+}
+
+/**
+ * opp_find_freq_exact() - search for an exact frequency
+ * @dev:               device for which we do this operation
+ * @freq:              frequency to search for
+ * @is_available:      true/false - match for available opp
+ *
+ * Searches for exact match in the opp list and returns pointer to the matching
+ * opp if found, else returns ERR_PTR in case of error and should be handled
+ * using IS_ERR.
+ *
+ * Note: available is a modifier for the search. if available=true, then the
+ * match is for exact matching frequency and is available in the stored OPP
+ * table. if false, the match is for exact frequency which is not available.
+ *
+ * This provides a mechanism to enable an opp which is not available currently
+ * or the opposite as well.
+ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. The reason for the same is that the opp pointer which is
+ * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * under the locked area. The pointer returned must be used prior to unlocking
+ * with rcu_read_unlock() to maintain the integrity of the pointer.
+ */
+struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
+                               bool available)
+{
+       struct device_opp *dev_opp;
+       struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+       dev_opp = find_device_opp(dev);
+       if (IS_ERR(dev_opp)) {
+               int r = PTR_ERR(dev_opp);
+               dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
+               return ERR_PTR(r);
+       }
+
+       list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+               if (temp_opp->available == available &&
+                               temp_opp->rate == freq) {
+                       opp = temp_opp;
+                       break;
+               }
+       }
+
+       return opp;
+}
+
+/**
+ * opp_find_freq_ceil() - Search for an rounded ceil freq
+ * @dev:       device for which we do this operation
+ * @freq:      Start frequency
+ *
+ * Search for the matching ceil *available* OPP from a starting freq
+ * for a device.
+ *
+ * Returns matching *opp and refreshes *freq accordingly, else returns
+ * ERR_PTR in case of error and should be handled using IS_ERR.
+ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. The reason for the same is that the opp pointer which is
+ * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * under the locked area. The pointer returned must be used prior to unlocking
+ * with rcu_read_unlock() to maintain the integrity of the pointer.
+ */
+struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq)
+{
+       struct device_opp *dev_opp;
+       struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+       if (!dev || !freq) {
+               dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
+               return ERR_PTR(-EINVAL);
+       }
+
+       dev_opp = find_device_opp(dev);
+       if (IS_ERR(dev_opp))
+               return opp;
+
+       list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+               if (temp_opp->available && temp_opp->rate >= *freq) {
+                       opp = temp_opp;
+                       *freq = opp->rate;
+                       break;
+               }
+       }
+
+       return opp;
+}
+
+/**
+ * opp_find_freq_floor() - Search for a rounded floor freq
+ * @dev:       device for which we do this operation
+ * @freq:      Start frequency
+ *
+ * Search for the matching floor *available* OPP from a starting freq
+ * for a device.
+ *
+ * Returns matching *opp and refreshes *freq accordingly, else returns
+ * ERR_PTR in case of error and should be handled using IS_ERR.
+ *
+ * Locking: This function must be called under rcu_read_lock(). opp is a rcu
+ * protected pointer. The reason for the same is that the opp pointer which is
+ * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * under the locked area. The pointer returned must be used prior to unlocking
+ * with rcu_read_unlock() to maintain the integrity of the pointer.
+ */
+struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq)
+{
+       struct device_opp *dev_opp;
+       struct opp *temp_opp, *opp = ERR_PTR(-ENODEV);
+
+       if (!dev || !freq) {
+               dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
+               return ERR_PTR(-EINVAL);
+       }
+
+       dev_opp = find_device_opp(dev);
+       if (IS_ERR(dev_opp))
+               return opp;
+
+       list_for_each_entry_rcu(temp_opp, &dev_opp->opp_list, node) {
+               if (temp_opp->available) {
+                       /* go to the next node, before choosing prev */
+                       if (temp_opp->rate > *freq)
+                               break;
+                       else
+                               opp = temp_opp;
+               }
+       }
+       if (!IS_ERR(opp))
+               *freq = opp->rate;
+
+       return opp;
+}
+
+/**
+ * opp_add()  - Add an OPP table from a table definitions
+ * @dev:       device for which we do this operation
+ * @freq:      Frequency in Hz for this OPP
+ * @u_volt:    Voltage in uVolts for this OPP
+ *
+ * This function adds an opp definition to the opp list and returns status.
+ * The opp is made available by default and it can be controlled using
+ * opp_enable/disable functions.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ */
+int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
+{
+       struct device_opp *dev_opp = NULL;
+       struct opp *opp, *new_opp;
+       struct list_head *head;
+
+       /* allocate new OPP node */
+       new_opp = kzalloc(sizeof(struct opp), GFP_KERNEL);
+       if (!new_opp) {
+               dev_warn(dev, "%s: Unable to create new OPP node\n", __func__);
+               return -ENOMEM;
+       }
+
+       /* Hold our list modification lock here */
+       mutex_lock(&dev_opp_list_lock);
+
+       /* Check for existing list for 'dev' */
+       dev_opp = find_device_opp(dev);
+       if (IS_ERR(dev_opp)) {
+               /*
+                * Allocate a new device OPP table. In the infrequent case
+                * where a new device is needed to be added, we pay this
+                * penalty.
+                */
+               dev_opp = kzalloc(sizeof(struct device_opp), GFP_KERNEL);
+               if (!dev_opp) {
+                       mutex_unlock(&dev_opp_list_lock);
+                       kfree(new_opp);
+                       dev_warn(dev,
+                               "%s: Unable to create device OPP structure\n",
+                               __func__);
+                       return -ENOMEM;
+               }
+
+               dev_opp->dev = dev;
+               INIT_LIST_HEAD(&dev_opp->opp_list);
+
+               /* Secure the device list modification */
+               list_add_rcu(&dev_opp->node, &dev_opp_list);
+       }
+
+       /* populate the opp table */
+       new_opp->dev_opp = dev_opp;
+       new_opp->rate = freq;
+       new_opp->u_volt = u_volt;
+       new_opp->available = true;
+
+       /* Insert new OPP in order of increasing frequency */
+       head = &dev_opp->opp_list;
+       list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) {
+               if (new_opp->rate < opp->rate)
+                       break;
+               else
+                       head = &opp->node;
+       }
+
+       list_add_rcu(&new_opp->node, head);
+       mutex_unlock(&dev_opp_list_lock);
+
+       return 0;
+}
+
+/**
+ * opp_set_availability() - helper to set the availability of an opp
+ * @dev:               device for which we do this operation
+ * @freq:              OPP frequency to modify availability
+ * @availability_req:  availability status requested for this opp
+ *
+ * Set the availability of an OPP with an RCU operation, opp_{enable,disable}
+ * share a common logic which is isolated here.
+ *
+ * Returns -EINVAL for bad pointers, -ENOMEM if no memory available for the
+ * copy operation, returns 0 if no modifcation was done OR modification was
+ * successful.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks to
+ * keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex locking or synchronize_rcu() blocking calls cannot be used.
+ */
+static int opp_set_availability(struct device *dev, unsigned long freq,
+               bool availability_req)
+{
+       struct device_opp *tmp_dev_opp, *dev_opp = NULL;
+       struct opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV);
+       int r = 0;
+
+       /* keep the node allocated */
+       new_opp = kmalloc(sizeof(struct opp), GFP_KERNEL);
+       if (!new_opp) {
+               dev_warn(dev, "%s: Unable to create OPP\n", __func__);
+               return -ENOMEM;
+       }
+
+       mutex_lock(&dev_opp_list_lock);
+
+       /* Find the device_opp */
+       list_for_each_entry(tmp_dev_opp, &dev_opp_list, node) {
+               if (dev == tmp_dev_opp->dev) {
+                       dev_opp = tmp_dev_opp;
+                       break;
+               }
+       }
+       if (IS_ERR(dev_opp)) {
+               r = PTR_ERR(dev_opp);
+               dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
+               goto unlock;
+       }
+
+       /* Do we have the frequency? */
+       list_for_each_entry(tmp_opp, &dev_opp->opp_list, node) {
+               if (tmp_opp->rate == freq) {
+                       opp = tmp_opp;
+                       break;
+               }
+       }
+       if (IS_ERR(opp)) {
+               r = PTR_ERR(opp);
+               goto unlock;
+       }
+
+       /* Is update really needed? */
+       if (opp->available == availability_req)
+               goto unlock;
+       /* copy the old data over */
+       *new_opp = *opp;
+
+       /* plug in new node */
+       new_opp->available = availability_req;
+
+       list_replace_rcu(&opp->node, &new_opp->node);
+       mutex_unlock(&dev_opp_list_lock);
+       synchronize_rcu();
+
+       /* clean up old opp */
+       new_opp = opp;
+       goto out;
+
+unlock:
+       mutex_unlock(&dev_opp_list_lock);
+out:
+       kfree(new_opp);
+       return r;
+}
+
+/**
+ * opp_enable() - Enable a specific OPP
+ * @dev:       device for which we do this operation
+ * @freq:      OPP frequency to enable
+ *
+ * Enables a provided opp. If the operation is valid, this returns 0, else the
+ * corresponding error value. It is meant to be used for users an OPP available
+ * after being temporarily made unavailable with opp_disable.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function indirectly uses RCU and mutex locks to keep the
+ * integrity of the internal data structures. Callers should ensure that
+ * this function is *NOT* called under RCU protection or in contexts where
+ * mutex locking or synchronize_rcu() blocking calls cannot be used.
+ */
+int opp_enable(struct device *dev, unsigned long freq)
+{
+       return opp_set_availability(dev, freq, true);
+}
+
+/**
+ * opp_disable() - Disable a specific OPP
+ * @dev:       device for which we do this operation
+ * @freq:      OPP frequency to disable
+ *
+ * Disables a provided opp. If the operation is valid, this returns
+ * 0, else the corresponding error value. It is meant to be a temporary
+ * control by users to make this OPP not available until the circumstances are
+ * right to make it available again (with a call to opp_enable).
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function indirectly uses RCU and mutex locks to keep the
+ * integrity of the internal data structures. Callers should ensure that
+ * this function is *NOT* called under RCU protection or in contexts where
+ * mutex locking or synchronize_rcu() blocking calls cannot be used.
+ */
+int opp_disable(struct device *dev, unsigned long freq)
+{
+       return opp_set_availability(dev, freq, false);
+}
+
+#ifdef CONFIG_CPU_FREQ
+/**
+ * opp_init_cpufreq_table() - create a cpufreq table for a device
+ * @dev:       device for which we do this operation
+ * @table:     Cpufreq table returned back to caller
+ *
+ * Generate a cpufreq table for a provided device- this assumes that the
+ * opp list is already initialized and ready for usage.
+ *
+ * This function allocates required memory for the cpufreq table. It is
+ * expected that the caller does the required maintenance such as freeing
+ * the table as required.
+ *
+ * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
+ * if no memory available for the operation (table is not populated), returns 0
+ * if successful and table is populated.
+ *
+ * WARNING: It is  important for the callers to ensure refreshing their copy of
+ * the table if any of the mentioned functions have been invoked in the interim.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * To simplify the logic, we pretend we are updater and hold relevant mutex here
+ * Callers should ensure that this function is *NOT* called under RCU protection
+ * or in contexts where mutex locking cannot be used.
+ */
+int opp_init_cpufreq_table(struct device *dev,
+                           struct cpufreq_frequency_table **table)
+{
+       struct device_opp *dev_opp;
+       struct opp *opp;
+       struct cpufreq_frequency_table *freq_table;
+       int i = 0;
+
+       /* Pretend as if I am an updater */
+       mutex_lock(&dev_opp_list_lock);
+
+       dev_opp = find_device_opp(dev);
+       if (IS_ERR(dev_opp)) {
+               int r = PTR_ERR(dev_opp);
+               mutex_unlock(&dev_opp_list_lock);
+               dev_err(dev, "%s: Device OPP not found (%d)\n", __func__, r);
+               return r;
+       }
+
+       freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
+                            (opp_get_opp_count(dev) + 1), GFP_KERNEL);
+       if (!freq_table) {
+               mutex_unlock(&dev_opp_list_lock);
+               dev_warn(dev, "%s: Unable to allocate frequency table\n",
+                       __func__);
+               return -ENOMEM;
+       }
+
+       list_for_each_entry(opp, &dev_opp->opp_list, node) {
+               if (opp->available) {
+                       freq_table[i].index = i;
+                       freq_table[i].frequency = opp->rate / 1000;
+                       i++;
+               }
+       }
+       mutex_unlock(&dev_opp_list_lock);
+
+       freq_table[i].index = i;
+       freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+       *table = &freq_table[0];
+
+       return 0;
+}
+#endif         /* CONFIG_CPU_FREQ */
index c0bd03c83b9cad1dbbb9341aa70f13e85b520760..698dde74258792544098eb8866e77ee72303c865 100644 (file)
@@ -34,6 +34,7 @@ extern void device_pm_move_last(struct device *);
 
 static inline void device_pm_init(struct device *dev)
 {
+       spin_lock_init(&dev->power.lock);
        pm_runtime_init(dev);
 }
 
@@ -59,6 +60,7 @@ static inline void device_pm_move_last(struct device *dev) {}
 
 extern int dpm_sysfs_add(struct device *);
 extern void dpm_sysfs_remove(struct device *);
+extern void rpm_sysfs_remove(struct device *);
 
 #else /* CONFIG_PM */
 
index b78c401ffa7380f67f29dbddf1fecf1396746e85..1dd8676d7f55705a84ad26ff77544b0518c02723 100644 (file)
@@ -2,17 +2,55 @@
  * drivers/base/power/runtime.c - Helper functions for device run-time PM
  *
  * Copyright (c) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc.
+ * Copyright (C) 2010 Alan Stern <stern@rowland.harvard.edu>
  *
  * This file is released under the GPLv2.
  */
 
 #include <linux/sched.h>
 #include <linux/pm_runtime.h>
-#include <linux/jiffies.h>
+#include "power.h"
 
-static int __pm_runtime_resume(struct device *dev, bool from_wq);
-static int __pm_request_idle(struct device *dev);
-static int __pm_request_resume(struct device *dev);
+static int rpm_resume(struct device *dev, int rpmflags);
+static int rpm_suspend(struct device *dev, int rpmflags);
+
+/**
+ * update_pm_runtime_accounting - Update the time accounting of power states
+ * @dev: Device to update the accounting for
+ *
+ * In order to be able to have time accounting of the various power states
+ * (as used by programs such as PowerTOP to show the effectiveness of runtime
+ * PM), we need to track the time spent in each state.
+ * update_pm_runtime_accounting must be called each time before the
+ * runtime_status field is updated, to account the time in the old state
+ * correctly.
+ */
+void update_pm_runtime_accounting(struct device *dev)
+{
+       unsigned long now = jiffies;
+       int delta;
+
+       delta = now - dev->power.accounting_timestamp;
+
+       if (delta < 0)
+               delta = 0;
+
+       dev->power.accounting_timestamp = now;
+
+       if (dev->power.disable_depth > 0)
+               return;
+
+       if (dev->power.runtime_status == RPM_SUSPENDED)
+               dev->power.suspended_jiffies += delta;
+       else
+               dev->power.active_jiffies += delta;
+}
+
+static void __update_runtime_status(struct device *dev, enum rpm_status status)
+{
+       update_pm_runtime_accounting(dev);
+       dev->power.runtime_status = status;
+}
 
 /**
  * pm_runtime_deactivate_timer - Deactivate given device's suspend timer.
@@ -40,62 +78,154 @@ static void pm_runtime_cancel_pending(struct device *dev)
        dev->power.request = RPM_REQ_NONE;
 }
 
-/**
- * __pm_runtime_idle - Notify device bus type if the device can be suspended.
- * @dev: Device to notify the bus type about.
+/*
+ * pm_runtime_autosuspend_expiration - Get a device's autosuspend-delay expiration time.
+ * @dev: Device to handle.
  *
- * This function must be called under dev->power.lock with interrupts disabled.
+ * Compute the autosuspend-delay expiration time based on the device's
+ * power.last_busy time.  If the delay has already expired or is disabled
+ * (negative) or the power.use_autosuspend flag isn't set, return 0.
+ * Otherwise return the expiration time in jiffies (adjusted to be nonzero).
+ *
+ * This function may be called either with or without dev->power.lock held.
+ * Either way it can be racy, since power.last_busy may be updated at any time.
  */
-static int __pm_runtime_idle(struct device *dev)
-       __releases(&dev->power.lock) __acquires(&dev->power.lock)
+unsigned long pm_runtime_autosuspend_expiration(struct device *dev)
+{
+       int autosuspend_delay;
+       long elapsed;
+       unsigned long last_busy;
+       unsigned long expires = 0;
+
+       if (!dev->power.use_autosuspend)
+               goto out;
+
+       autosuspend_delay = ACCESS_ONCE(dev->power.autosuspend_delay);
+       if (autosuspend_delay < 0)
+               goto out;
+
+       last_busy = ACCESS_ONCE(dev->power.last_busy);
+       elapsed = jiffies - last_busy;
+       if (elapsed < 0)
+               goto out;       /* jiffies has wrapped around. */
+
+       /*
+        * If the autosuspend_delay is >= 1 second, align the timer by rounding
+        * up to the nearest second.
+        */
+       expires = last_busy + msecs_to_jiffies(autosuspend_delay);
+       if (autosuspend_delay >= 1000)
+               expires = round_jiffies(expires);
+       expires += !expires;
+       if (elapsed >= expires - last_busy)
+               expires = 0;    /* Already expired. */
+
+ out:
+       return expires;
+}
+EXPORT_SYMBOL_GPL(pm_runtime_autosuspend_expiration);
+
+/**
+ * rpm_check_suspend_allowed - Test whether a device may be suspended.
+ * @dev: Device to test.
+ */
+static int rpm_check_suspend_allowed(struct device *dev)
 {
        int retval = 0;
 
        if (dev->power.runtime_error)
                retval = -EINVAL;
-       else if (dev->power.idle_notification)
-               retval = -EINPROGRESS;
        else if (atomic_read(&dev->power.usage_count) > 0
-           || dev->power.disable_depth > 0
-           || dev->power.runtime_status != RPM_ACTIVE)
+           || dev->power.disable_depth > 0)
                retval = -EAGAIN;
        else if (!pm_children_suspended(dev))
                retval = -EBUSY;
+
+       /* Pending resume requests take precedence over suspends. */
+       else if ((dev->power.deferred_resume
+                       && dev->power.status == RPM_SUSPENDING)
+           || (dev->power.request_pending
+                       && dev->power.request == RPM_REQ_RESUME))
+               retval = -EAGAIN;
+       else if (dev->power.runtime_status == RPM_SUSPENDED)
+               retval = 1;
+
+       return retval;
+}
+
+/**
+ * rpm_idle - Notify device bus type if the device can be suspended.
+ * @dev: Device to notify the bus type about.
+ * @rpmflags: Flag bits.
+ *
+ * Check if the device's run-time PM status allows it to be suspended.  If
+ * another idle notification has been started earlier, return immediately.  If
+ * the RPM_ASYNC flag is set then queue an idle-notification request; otherwise
+ * run the ->runtime_idle() callback directly.
+ *
+ * This function must be called under dev->power.lock with interrupts disabled.
+ */
+static int rpm_idle(struct device *dev, int rpmflags)
+{
+       int (*callback)(struct device *);
+       int retval;
+
+       retval = rpm_check_suspend_allowed(dev);
+       if (retval < 0)
+               ;       /* Conditions are wrong. */
+
+       /* Idle notifications are allowed only in the RPM_ACTIVE state. */
+       else if (dev->power.runtime_status != RPM_ACTIVE)
+               retval = -EAGAIN;
+
+       /*
+        * Any pending request other than an idle notification takes
+        * precedence over us, except that the timer may be running.
+        */
+       else if (dev->power.request_pending &&
+           dev->power.request > RPM_REQ_IDLE)
+               retval = -EAGAIN;
+
+       /* Act as though RPM_NOWAIT is always set. */
+       else if (dev->power.idle_notification)
+               retval = -EINPROGRESS;
        if (retval)
                goto out;
 
-       if (dev->power.request_pending) {
-               /*
-                * If an idle notification request is pending, cancel it.  Any
-                * other pending request takes precedence over us.
-                */
-               if (dev->power.request == RPM_REQ_IDLE) {
-                       dev->power.request = RPM_REQ_NONE;
-               } else if (dev->power.request != RPM_REQ_NONE) {
-                       retval = -EAGAIN;
-                       goto out;
+       /* Pending requests need to be canceled. */
+       dev->power.request = RPM_REQ_NONE;
+
+       if (dev->power.no_callbacks) {
+               /* Assume ->runtime_idle() callback would have suspended. */
+               retval = rpm_suspend(dev, rpmflags);
+               goto out;
+       }
+
+       /* Carry out an asynchronous or a synchronous idle notification. */
+       if (rpmflags & RPM_ASYNC) {
+               dev->power.request = RPM_REQ_IDLE;
+               if (!dev->power.request_pending) {
+                       dev->power.request_pending = true;
+                       queue_work(pm_wq, &dev->power.work);
                }
+               goto out;
        }
 
        dev->power.idle_notification = true;
 
-       if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle) {
-               spin_unlock_irq(&dev->power.lock);
-
-               dev->bus->pm->runtime_idle(dev);
-
-               spin_lock_irq(&dev->power.lock);
-       } else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle) {
-               spin_unlock_irq(&dev->power.lock);
-
-               dev->type->pm->runtime_idle(dev);
+       if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_idle)
+               callback = dev->bus->pm->runtime_idle;
+       else if (dev->type && dev->type->pm && dev->type->pm->runtime_idle)
+               callback = dev->type->pm->runtime_idle;
+       else if (dev->class && dev->class->pm)
+               callback = dev->class->pm->runtime_idle;
+       else
+               callback = NULL;
 
-               spin_lock_irq(&dev->power.lock);
-       } else if (dev->class && dev->class->pm
-           && dev->class->pm->runtime_idle) {
+       if (callback) {
                spin_unlock_irq(&dev->power.lock);
 
-               dev->class->pm->runtime_idle(dev);
+               callback(dev);
 
                spin_lock_irq(&dev->power.lock);
        }
@@ -108,113 +238,99 @@ static int __pm_runtime_idle(struct device *dev)
 }
 
 /**
- * pm_runtime_idle - Notify device bus type if the device can be suspended.
- * @dev: Device to notify the bus type about.
+ * rpm_callback - Run a given runtime PM callback for a given device.
+ * @cb: Runtime PM callback to run.
+ * @dev: Device to run the callback for.
  */
-int pm_runtime_idle(struct device *dev)
+static int rpm_callback(int (*cb)(struct device *), struct device *dev)
+       __releases(&dev->power.lock) __acquires(&dev->power.lock)
 {
        int retval;
 
-       spin_lock_irq(&dev->power.lock);
-       retval = __pm_runtime_idle(dev);
-       spin_unlock_irq(&dev->power.lock);
+       if (!cb)
+               return -ENOSYS;
 
-       return retval;
-}
-EXPORT_SYMBOL_GPL(pm_runtime_idle);
-
-
-/**
- * update_pm_runtime_accounting - Update the time accounting of power states
- * @dev: Device to update the accounting for
- *
- * In order to be able to have time accounting of the various power states
- * (as used by programs such as PowerTOP to show the effectiveness of runtime
- * PM), we need to track the time spent in each state.
- * update_pm_runtime_accounting must be called each time before the
- * runtime_status field is updated, to account the time in the old state
- * correctly.
- */
-void update_pm_runtime_accounting(struct device *dev)
-{
-       unsigned long now = jiffies;
-       int delta;
-
-       delta = now - dev->power.accounting_timestamp;
-
-       if (delta < 0)
-               delta = 0;
+       spin_unlock_irq(&dev->power.lock);
 
-       dev->power.accounting_timestamp = now;
+       retval = cb(dev);
 
-       if (dev->power.disable_depth > 0)
-               return;
-
-       if (dev->power.runtime_status == RPM_SUSPENDED)
-               dev->power.suspended_jiffies += delta;
-       else
-               dev->power.active_jiffies += delta;
-}
+       spin_lock_irq(&dev->power.lock);
+       dev->power.runtime_error = retval;
 
-static void __update_runtime_status(struct device *dev, enum rpm_status status)
-{
-       update_pm_runtime_accounting(dev);
-       dev->power.runtime_status = status;
+       return retval;
 }
 
 /**
- * __pm_runtime_suspend - Carry out run-time suspend of given device.
+ * rpm_suspend - Carry out run-time suspend of given device.
  * @dev: Device to suspend.
- * @from_wq: If set, the function has been called via pm_wq.
+ * @rpmflags: Flag bits.
  *
- * Check if the device can be suspended and run the ->runtime_suspend() callback
- * provided by its bus type.  If another suspend has been started earlier, wait
- * for it to finish.  If an idle notification or suspend request is pending or
- * scheduled, cancel it.
+ * Check if the device's run-time PM status allows it to be suspended.  If
+ * another suspend has been started earlier, either return immediately or wait
+ * for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC flags.  Cancel a
+ * pending idle notification.  If the RPM_ASYNC flag is set then queue a
+ * suspend request; otherwise run the ->runtime_suspend() callback directly.
+ * If a deferred resume was requested while the callback was running then carry
+ * it out; otherwise send an idle notification for the device (if the suspend
+ * failed) or for its parent (if the suspend succeeded).
  *
  * This function must be called under dev->power.lock with interrupts disabled.
  */
-int __pm_runtime_suspend(struct device *dev, bool from_wq)
+static int rpm_suspend(struct device *dev, int rpmflags)
        __releases(&dev->power.lock) __acquires(&dev->power.lock)
 {
+       int (*callback)(struct device *);
        struct device *parent = NULL;
-       bool notify = false;
-       int retval = 0;
+       int retval;
 
-       dev_dbg(dev, "__pm_runtime_suspend()%s!\n",
-               from_wq ? " from workqueue" : "");
+       dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
 
  repeat:
-       if (dev->power.runtime_error) {
-               retval = -EINVAL;
-               goto out;
-       }
+       retval = rpm_check_suspend_allowed(dev);
 
-       /* Pending resume requests take precedence over us. */
-       if (dev->power.request_pending
-           && dev->power.request == RPM_REQ_RESUME) {
+       if (retval < 0)
+               ;       /* Conditions are wrong. */
+
+       /* Synchronous suspends are not allowed in the RPM_RESUMING state. */
+       else if (dev->power.runtime_status == RPM_RESUMING &&
+           !(rpmflags & RPM_ASYNC))
                retval = -EAGAIN;
+       if (retval)
                goto out;
+
+       /* If the autosuspend_delay time hasn't expired yet, reschedule. */
+       if ((rpmflags & RPM_AUTO)
+           && dev->power.runtime_status != RPM_SUSPENDING) {
+               unsigned long expires = pm_runtime_autosuspend_expiration(dev);
+
+               if (expires != 0) {
+                       /* Pending requests need to be canceled. */
+                       dev->power.request = RPM_REQ_NONE;
+
+                       /*
+                        * Optimization: If the timer is already running and is
+                        * set to expire at or before the autosuspend delay,
+                        * avoid the overhead of resetting it.  Just let it
+                        * expire; pm_suspend_timer_fn() will take care of the
+                        * rest.
+                        */
+                       if (!(dev->power.timer_expires && time_before_eq(
+                           dev->power.timer_expires, expires))) {
+                               dev->power.timer_expires = expires;
+                               mod_timer(&dev->power.suspend_timer, expires);
+                       }
+                       dev->power.timer_autosuspends = 1;
+                       goto out;
+               }
        }
 
        /* Other scheduled or pending requests need to be canceled. */
        pm_runtime_cancel_pending(dev);
 
-       if (dev->power.runtime_status == RPM_SUSPENDED)
-               retval = 1;
-       else if (dev->power.runtime_status == RPM_RESUMING
-           || dev->power.disable_depth > 0
-           || atomic_read(&dev->power.usage_count) > 0)
-               retval = -EAGAIN;
-       else if (!pm_children_suspended(dev))
-               retval = -EBUSY;
-       if (retval)
-               goto out;
-
        if (dev->power.runtime_status == RPM_SUSPENDING) {
                DEFINE_WAIT(wait);
 
-               if (from_wq) {
+               if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) {
                        retval = -EINPROGRESS;
                        goto out;
                }
@@ -236,46 +352,42 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
                goto repeat;
        }
 
-       __update_runtime_status(dev, RPM_SUSPENDING);
        dev->power.deferred_resume = false;
+       if (dev->power.no_callbacks)
+               goto no_callback;       /* Assume success. */
+
+       /* Carry out an asynchronous or a synchronous suspend. */
+       if (rpmflags & RPM_ASYNC) {
+               dev->power.request = (rpmflags & RPM_AUTO) ?
+                   RPM_REQ_AUTOSUSPEND : RPM_REQ_SUSPEND;
+               if (!dev->power.request_pending) {
+                       dev->power.request_pending = true;
+                       queue_work(pm_wq, &dev->power.work);
+               }
+               goto out;
+       }
 
-       if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
-               spin_unlock_irq(&dev->power.lock);
-
-               retval = dev->bus->pm->runtime_suspend(dev);
-
-               spin_lock_irq(&dev->power.lock);
-               dev->power.runtime_error = retval;
-       } else if (dev->type && dev->type->pm
-           && dev->type->pm->runtime_suspend) {
-               spin_unlock_irq(&dev->power.lock);
-
-               retval = dev->type->pm->runtime_suspend(dev);
-
-               spin_lock_irq(&dev->power.lock);
-               dev->power.runtime_error = retval;
-       } else if (dev->class && dev->class->pm
-           && dev->class->pm->runtime_suspend) {
-               spin_unlock_irq(&dev->power.lock);
-
-               retval = dev->class->pm->runtime_suspend(dev);
+       __update_runtime_status(dev, RPM_SUSPENDING);
 
-               spin_lock_irq(&dev->power.lock);
-               dev->power.runtime_error = retval;
-       } else {
-               retval = -ENOSYS;
-       }
+       if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
+               callback = dev->bus->pm->runtime_suspend;
+       else if (dev->type && dev->type->pm && dev->type->pm->runtime_suspend)
+               callback = dev->type->pm->runtime_suspend;
+       else if (dev->class && dev->class->pm)
+               callback = dev->class->pm->runtime_suspend;
+       else
+               callback = NULL;
 
+       retval = rpm_callback(callback, dev);
        if (retval) {
                __update_runtime_status(dev, RPM_ACTIVE);
-               if (retval == -EAGAIN || retval == -EBUSY) {
-                       if (dev->power.timer_expires == 0)
-                               notify = true;
+               dev->power.deferred_resume = 0;
+               if (retval == -EAGAIN || retval == -EBUSY)
                        dev->power.runtime_error = 0;
-               } else {
+               else
                        pm_runtime_cancel_pending(dev);
-               }
        } else {
+ no_callback:
                __update_runtime_status(dev, RPM_SUSPENDED);
                pm_runtime_deactivate_timer(dev);
 
@@ -287,14 +399,11 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
        wake_up_all(&dev->power.wait_queue);
 
        if (dev->power.deferred_resume) {
-               __pm_runtime_resume(dev, false);
+               rpm_resume(dev, 0);
                retval = -EAGAIN;
                goto out;
        }
 
-       if (notify)
-               __pm_runtime_idle(dev);
-
        if (parent && !parent->power.ignore_children) {
                spin_unlock_irq(&dev->power.lock);
 
@@ -304,72 +413,69 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
        }
 
  out:
-       dev_dbg(dev, "__pm_runtime_suspend() returns %d!\n", retval);
-
-       return retval;
-}
-
-/**
- * pm_runtime_suspend - Carry out run-time suspend of given device.
- * @dev: Device to suspend.
- */
-int pm_runtime_suspend(struct device *dev)
-{
-       int retval;
-
-       spin_lock_irq(&dev->power.lock);
-       retval = __pm_runtime_suspend(dev, false);
-       spin_unlock_irq(&dev->power.lock);
+       dev_dbg(dev, "%s returns %d\n", __func__, retval);
 
        return retval;
 }
-EXPORT_SYMBOL_GPL(pm_runtime_suspend);
 
 /**
- * __pm_runtime_resume - Carry out run-time resume of given device.
+ * rpm_resume - Carry out run-time resume of given device.
  * @dev: Device to resume.
- * @from_wq: If set, the function has been called via pm_wq.
+ * @rpmflags: Flag bits.
  *
- * Check if the device can be woken up and run the ->runtime_resume() callback
- * provided by its bus type.  If another resume has been started earlier, wait
- * for it to finish.  If there's a suspend running in parallel with this
- * function, wait for it to finish and resume the device.  Cancel any scheduled
- * or pending requests.
+ * Check if the device's run-time PM status allows it to be resumed.  Cancel
+ * any scheduled or pending requests.  If another resume has been started
+ * earlier, either return imediately or wait for it to finish, depending on the
+ * RPM_NOWAIT and RPM_ASYNC flags.  Similarly, if there's a suspend running in
+ * parallel with this function, either tell the other process to resume after
+ * suspending (deferred_resume) or wait for it to finish.  If the RPM_ASYNC
+ * flag is set then queue a resume request; otherwise run the
+ * ->runtime_resume() callback directly.  Queue an idle notification for the
+ * device if the resume succeeded.
  *
  * This function must be called under dev->power.lock with interrupts disabled.
  */
-int __pm_runtime_resume(struct device *dev, bool from_wq)
+static int rpm_resume(struct device *dev, int rpmflags)
        __releases(&dev->power.lock) __acquires(&dev->power.lock)
 {
+       int (*callback)(struct device *);
        struct device *parent = NULL;
        int retval = 0;
 
-       dev_dbg(dev, "__pm_runtime_resume()%s!\n",
-               from_wq ? " from workqueue" : "");
+       dev_dbg(dev, "%s flags 0x%x\n", __func__, rpmflags);
 
  repeat:
-       if (dev->power.runtime_error) {
+       if (dev->power.runtime_error)
                retval = -EINVAL;
+       else if (dev->power.disable_depth > 0)
+               retval = -EAGAIN;
+       if (retval)
                goto out;
-       }
 
-       pm_runtime_cancel_pending(dev);
+       /*
+        * Other scheduled or pending requests need to be canceled.  Small
+        * optimization: If an autosuspend timer is running, leave it running
+        * rather than cancelling it now only to restart it again in the near
+        * future.
+        */
+       dev->power.request = RPM_REQ_NONE;
+       if (!dev->power.timer_autosuspends)
+               pm_runtime_deactivate_timer(dev);
 
-       if (dev->power.runtime_status == RPM_ACTIVE)
+       if (dev->power.runtime_status == RPM_ACTIVE) {
                retval = 1;
-       else if (dev->power.disable_depth > 0)
-               retval = -EAGAIN;
-       if (retval)
                goto out;
+       }
 
        if (dev->power.runtime_status == RPM_RESUMING
            || dev->power.runtime_status == RPM_SUSPENDING) {
                DEFINE_WAIT(wait);
 
-               if (from_wq) {
+               if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) {
                        if (dev->power.runtime_status == RPM_SUSPENDING)
                                dev->power.deferred_resume = true;
-                       retval = -EINPROGRESS;
+                       else
+                               retval = -EINPROGRESS;
                        goto out;
                }
 
@@ -391,6 +497,34 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
                goto repeat;
        }
 
+       /*
+        * See if we can skip waking up the parent.  This is safe only if
+        * power.no_callbacks is set, because otherwise we don't know whether
+        * the resume will actually succeed.
+        */
+       if (dev->power.no_callbacks && !parent && dev->parent) {
+               spin_lock(&dev->parent->power.lock);
+               if (dev->parent->power.disable_depth > 0
+                   || dev->parent->power.ignore_children
+                   || dev->parent->power.runtime_status == RPM_ACTIVE) {
+                       atomic_inc(&dev->parent->power.child_count);
+                       spin_unlock(&dev->parent->power.lock);
+                       goto no_callback;       /* Assume success. */
+               }
+               spin_unlock(&dev->parent->power.lock);
+       }
+
+       /* Carry out an asynchronous or a synchronous resume. */
+       if (rpmflags & RPM_ASYNC) {
+               dev->power.request = RPM_REQ_RESUME;
+               if (!dev->power.request_pending) {
+                       dev->power.request_pending = true;
+                       queue_work(pm_wq, &dev->power.work);
+               }
+               retval = 0;
+               goto out;
+       }
+
        if (!parent && dev->parent) {
                /*
                 * Increment the parent's resume counter and resume it if
@@ -408,7 +542,7 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
                 */
                if (!parent->power.disable_depth
                    && !parent->power.ignore_children) {
-                       __pm_runtime_resume(parent, false);
+                       rpm_resume(parent, 0);
                        if (parent->power.runtime_status != RPM_ACTIVE)
                                retval = -EBUSY;
                }
@@ -420,39 +554,26 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
                goto repeat;
        }
 
-       __update_runtime_status(dev, RPM_RESUMING);
-
-       if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
-               spin_unlock_irq(&dev->power.lock);
-
-               retval = dev->bus->pm->runtime_resume(dev);
-
-               spin_lock_irq(&dev->power.lock);
-               dev->power.runtime_error = retval;
-       } else if (dev->type && dev->type->pm
-           && dev->type->pm->runtime_resume) {
-               spin_unlock_irq(&dev->power.lock);
-
-               retval = dev->type->pm->runtime_resume(dev);
+       if (dev->power.no_callbacks)
+               goto no_callback;       /* Assume success. */
 
-               spin_lock_irq(&dev->power.lock);
-               dev->power.runtime_error = retval;
-       } else if (dev->class && dev->class->pm
-           && dev->class->pm->runtime_resume) {
-               spin_unlock_irq(&dev->power.lock);
-
-               retval = dev->class->pm->runtime_resume(dev);
+       __update_runtime_status(dev, RPM_RESUMING);
 
-               spin_lock_irq(&dev->power.lock);
-               dev->power.runtime_error = retval;
-       } else {
-               retval = -ENOSYS;
-       }
+       if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
+               callback = dev->bus->pm->runtime_resume;
+       else if (dev->type && dev->type->pm && dev->type->pm->runtime_resume)
+               callback = dev->type->pm->runtime_resume;
+       else if (dev->class && dev->class->pm)
+               callback = dev->class->pm->runtime_resume;
+       else
+               callback = NULL;
 
+       retval = rpm_callback(callback, dev);
        if (retval) {
                __update_runtime_status(dev, RPM_SUSPENDED);
                pm_runtime_cancel_pending(dev);
        } else {
+ no_callback:
                __update_runtime_status(dev, RPM_ACTIVE);
                if (parent)
                        atomic_inc(&parent->power.child_count);
@@ -460,7 +581,7 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
        wake_up_all(&dev->power.wait_queue);
 
        if (!retval)
-               __pm_request_idle(dev);
+               rpm_idle(dev, RPM_ASYNC);
 
  out:
        if (parent) {
@@ -471,27 +592,11 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
                spin_lock_irq(&dev->power.lock);
        }
 
-       dev_dbg(dev, "__pm_runtime_resume() returns %d!\n", retval);
+       dev_dbg(dev, "%s returns %d\n", __func__, retval);
 
        return retval;
 }
 
-/**
- * pm_runtime_resume - Carry out run-time resume of given device.
- * @dev: Device to suspend.
- */
-int pm_runtime_resume(struct device *dev)
-{
-       int retval;
-
-       spin_lock_irq(&dev->power.lock);
-       retval = __pm_runtime_resume(dev, false);
-       spin_unlock_irq(&dev->power.lock);
-
-       return retval;
-}
-EXPORT_SYMBOL_GPL(pm_runtime_resume);
-
 /**
  * pm_runtime_work - Universal run-time PM work function.
  * @work: Work structure used for scheduling the execution of this function.
@@ -517,13 +622,16 @@ static void pm_runtime_work(struct work_struct *work)
        case RPM_REQ_NONE:
                break;
        case RPM_REQ_IDLE:
-               __pm_runtime_idle(dev);
+               rpm_idle(dev, RPM_NOWAIT);
                break;
        case RPM_REQ_SUSPEND:
-               __pm_runtime_suspend(dev, true);
+               rpm_suspend(dev, RPM_NOWAIT);
+               break;
+       case RPM_REQ_AUTOSUSPEND:
+               rpm_suspend(dev, RPM_NOWAIT | RPM_AUTO);
                break;
        case RPM_REQ_RESUME:
-               __pm_runtime_resume(dev, true);
+               rpm_resume(dev, RPM_NOWAIT);
                break;
        }
 
@@ -531,118 +639,11 @@ static void pm_runtime_work(struct work_struct *work)
        spin_unlock_irq(&dev->power.lock);
 }
 
-/**
- * __pm_request_idle - Submit an idle notification request for given device.
- * @dev: Device to handle.
- *
- * Check if the device's run-time PM status is correct for suspending the device
- * and queue up a request to run __pm_runtime_idle() for it.
- *
- * This function must be called under dev->power.lock with interrupts disabled.
- */
-static int __pm_request_idle(struct device *dev)
-{
-       int retval = 0;
-
-       if (dev->power.runtime_error)
-               retval = -EINVAL;
-       else if (atomic_read(&dev->power.usage_count) > 0
-           || dev->power.disable_depth > 0
-           || dev->power.runtime_status == RPM_SUSPENDED
-           || dev->power.runtime_status == RPM_SUSPENDING)
-               retval = -EAGAIN;
-       else if (!pm_children_suspended(dev))
-               retval = -EBUSY;
-       if (retval)
-               return retval;
-
-       if (dev->power.request_pending) {
-               /* Any requests other then RPM_REQ_IDLE take precedence. */
-               if (dev->power.request == RPM_REQ_NONE)
-                       dev->power.request = RPM_REQ_IDLE;
-               else if (dev->power.request != RPM_REQ_IDLE)
-                       retval = -EAGAIN;
-               return retval;
-       }
-
-       dev->power.request = RPM_REQ_IDLE;
-       dev->power.request_pending = true;
-       queue_work(pm_wq, &dev->power.work);
-
-       return retval;
-}
-
-/**
- * pm_request_idle - Submit an idle notification request for given device.
- * @dev: Device to handle.
- */
-int pm_request_idle(struct device *dev)
-{
-       unsigned long flags;
-       int retval;
-
-       spin_lock_irqsave(&dev->power.lock, flags);
-       retval = __pm_request_idle(dev);
-       spin_unlock_irqrestore(&dev->power.lock, flags);
-
-       return retval;
-}
-EXPORT_SYMBOL_GPL(pm_request_idle);
-
-/**
- * __pm_request_suspend - Submit a suspend request for given device.
- * @dev: Device to suspend.
- *
- * This function must be called under dev->power.lock with interrupts disabled.
- */
-static int __pm_request_suspend(struct device *dev)
-{
-       int retval = 0;
-
-       if (dev->power.runtime_error)
-               return -EINVAL;
-
-       if (dev->power.runtime_status == RPM_SUSPENDED)
-               retval = 1;
-       else if (atomic_read(&dev->power.usage_count) > 0
-           || dev->power.disable_depth > 0)
-               retval = -EAGAIN;
-       else if (dev->power.runtime_status == RPM_SUSPENDING)
-               retval = -EINPROGRESS;
-       else if (!pm_children_suspended(dev))
-               retval = -EBUSY;
-       if (retval < 0)
-               return retval;
-
-       pm_runtime_deactivate_timer(dev);
-
-       if (dev->power.request_pending) {
-               /*
-                * Pending resume requests take precedence over us, but we can
-                * overtake any other pending request.
-                */
-               if (dev->power.request == RPM_REQ_RESUME)
-                       retval = -EAGAIN;
-               else if (dev->power.request != RPM_REQ_SUSPEND)
-                       dev->power.request = retval ?
-                                               RPM_REQ_NONE : RPM_REQ_SUSPEND;
-               return retval;
-       } else if (retval) {
-               return retval;
-       }
-
-       dev->power.request = RPM_REQ_SUSPEND;
-       dev->power.request_pending = true;
-       queue_work(pm_wq, &dev->power.work);
-
-       return 0;
-}
-
 /**
  * pm_suspend_timer_fn - Timer function for pm_schedule_suspend().
  * @data: Device pointer passed by pm_schedule_suspend().
  *
- * Check if the time is right and execute __pm_request_suspend() in that case.
+ * Check if the time is right and queue a suspend request.
  */
 static void pm_suspend_timer_fn(unsigned long data)
 {
@@ -656,7 +657,8 @@ static void pm_suspend_timer_fn(unsigned long data)
        /* If 'expire' is after 'jiffies' we've been called too early. */
        if (expires > 0 && !time_after(expires, jiffies)) {
                dev->power.timer_expires = 0;
-               __pm_request_suspend(dev);
+               rpm_suspend(dev, dev->power.timer_autosuspends ?
+                   (RPM_ASYNC | RPM_AUTO) : RPM_ASYNC);
        }
 
        spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -670,47 +672,25 @@ static void pm_suspend_timer_fn(unsigned long data)
 int pm_schedule_suspend(struct device *dev, unsigned int delay)
 {
        unsigned long flags;
-       int retval = 0;
+       int retval;
 
        spin_lock_irqsave(&dev->power.lock, flags);
 
-       if (dev->power.runtime_error) {
-               retval = -EINVAL;
-               goto out;
-       }
-
        if (!delay) {
-               retval = __pm_request_suspend(dev);
+               retval = rpm_suspend(dev, RPM_ASYNC);
                goto out;
        }
 
-       pm_runtime_deactivate_timer(dev);
-
-       if (dev->power.request_pending) {
-               /*
-                * Pending resume requests take precedence over us, but any
-                * other pending requests have to be canceled.
-                */
-               if (dev->power.request == RPM_REQ_RESUME) {
-                       retval = -EAGAIN;
-                       goto out;
-               }
-               dev->power.request = RPM_REQ_NONE;
-       }
-
-       if (dev->power.runtime_status == RPM_SUSPENDED)
-               retval = 1;
-       else if (atomic_read(&dev->power.usage_count) > 0
-           || dev->power.disable_depth > 0)
-               retval = -EAGAIN;
-       else if (!pm_children_suspended(dev))
-               retval = -EBUSY;
+       retval = rpm_check_suspend_allowed(dev);
        if (retval)
                goto out;
 
+       /* Other scheduled or pending requests need to be canceled. */
+       pm_runtime_cancel_pending(dev);
+
        dev->power.timer_expires = jiffies + msecs_to_jiffies(delay);
-       if (!dev->power.timer_expires)
-               dev->power.timer_expires = 1;
+       dev->power.timer_expires += !dev->power.timer_expires;
+       dev->power.timer_autosuspends = 0;
        mod_timer(&dev->power.suspend_timer, dev->power.timer_expires);
 
  out:
@@ -721,103 +701,88 @@ int pm_schedule_suspend(struct device *dev, unsigned int delay)
 EXPORT_SYMBOL_GPL(pm_schedule_suspend);
 
 /**
- * pm_request_resume - Submit a resume request for given device.
- * @dev: Device to resume.
+ * __pm_runtime_idle - Entry point for run-time idle operations.
+ * @dev: Device to send idle notification for.
+ * @rpmflags: Flag bits.
  *
- * This function must be called under dev->power.lock with interrupts disabled.
+ * If the RPM_GET_PUT flag is set, decrement the device's usage count and
+ * return immediately if it is larger than zero.  Then carry out an idle
+ * notification, either synchronous or asynchronous.
+ *
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set.
  */
-static int __pm_request_resume(struct device *dev)
+int __pm_runtime_idle(struct device *dev, int rpmflags)
 {
-       int retval = 0;
-
-       if (dev->power.runtime_error)
-               return -EINVAL;
-
-       if (dev->power.runtime_status == RPM_ACTIVE)
-               retval = 1;
-       else if (dev->power.runtime_status == RPM_RESUMING)
-               retval = -EINPROGRESS;
-       else if (dev->power.disable_depth > 0)
-               retval = -EAGAIN;
-       if (retval < 0)
-               return retval;
-
-       pm_runtime_deactivate_timer(dev);
+       unsigned long flags;
+       int retval;
 
-       if (dev->power.runtime_status == RPM_SUSPENDING) {
-               dev->power.deferred_resume = true;
-               return retval;
+       if (rpmflags & RPM_GET_PUT) {
+               if (!atomic_dec_and_test(&dev->power.usage_count))
+                       return 0;
        }
-       if (dev->power.request_pending) {
-               /* If non-resume request is pending, we can overtake it. */
-               dev->power.request = retval ? RPM_REQ_NONE : RPM_REQ_RESUME;
-               return retval;
-       }
-       if (retval)
-               return retval;
 
-       dev->power.request = RPM_REQ_RESUME;
-       dev->power.request_pending = true;
-       queue_work(pm_wq, &dev->power.work);
+       spin_lock_irqsave(&dev->power.lock, flags);
+       retval = rpm_idle(dev, rpmflags);
+       spin_unlock_irqrestore(&dev->power.lock, flags);
 
        return retval;
 }
+EXPORT_SYMBOL_GPL(__pm_runtime_idle);
 
 /**
- * pm_request_resume - Submit a resume request for given device.
- * @dev: Device to resume.
+ * __pm_runtime_suspend - Entry point for run-time put/suspend operations.
+ * @dev: Device to suspend.
+ * @rpmflags: Flag bits.
+ *
+ * If the RPM_GET_PUT flag is set, decrement the device's usage count and
+ * return immediately if it is larger than zero.  Then carry out a suspend,
+ * either synchronous or asynchronous.
+ *
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set.
  */
-int pm_request_resume(struct device *dev)
+int __pm_runtime_suspend(struct device *dev, int rpmflags)
 {
        unsigned long flags;
        int retval;
 
+       if (rpmflags & RPM_GET_PUT) {
+               if (!atomic_dec_and_test(&dev->power.usage_count))
+                       return 0;
+       }
+
        spin_lock_irqsave(&dev->power.lock, flags);
-       retval = __pm_request_resume(dev);
+       retval = rpm_suspend(dev, rpmflags);
        spin_unlock_irqrestore(&dev->power.lock, flags);
 
        return retval;
 }
-EXPORT_SYMBOL_GPL(pm_request_resume);
+EXPORT_SYMBOL_GPL(__pm_runtime_suspend);
 
 /**
- * __pm_runtime_get - Reference count a device and wake it up, if necessary.
- * @dev: Device to handle.
- * @sync: If set and the device is suspended, resume it synchronously.
+ * __pm_runtime_resume - Entry point for run-time resume operations.
+ * @dev: Device to resume.
+ * @rpmflags: Flag bits.
+ *
+ * If the RPM_GET_PUT flag is set, increment the device's usage count.  Then
+ * carry out a resume, either synchronous or asynchronous.
  *
- * Increment the usage count of the device and resume it or submit a resume
- * request for it, depending on the value of @sync.
+ * This routine may be called in atomic context if the RPM_ASYNC flag is set.
  */
-int __pm_runtime_get(struct device *dev, bool sync)
+int __pm_runtime_resume(struct device *dev, int rpmflags)
 {
+       unsigned long flags;
        int retval;
 
-       atomic_inc(&dev->power.usage_count);
-       retval = sync ? pm_runtime_resume(dev) : pm_request_resume(dev);
+       if (rpmflags & RPM_GET_PUT)
+               atomic_inc(&dev->power.usage_count);
 
-       return retval;
-}
-EXPORT_SYMBOL_GPL(__pm_runtime_get);
-
-/**
- * __pm_runtime_put - Decrement the device's usage counter and notify its bus.
- * @dev: Device to handle.
- * @sync: If the device's bus type is to be notified, do that synchronously.
- *
- * Decrement the usage count of the device and if it reaches zero, carry out a
- * synchronous idle notification or submit an idle notification request for it,
- * depending on the value of @sync.
- */
-int __pm_runtime_put(struct device *dev, bool sync)
-{
-       int retval = 0;
-
-       if (atomic_dec_and_test(&dev->power.usage_count))
-               retval = sync ? pm_runtime_idle(dev) : pm_request_idle(dev);
+       spin_lock_irqsave(&dev->power.lock, flags);
+       retval = rpm_resume(dev, rpmflags);
+       spin_unlock_irqrestore(&dev->power.lock, flags);
 
        return retval;
 }
-EXPORT_SYMBOL_GPL(__pm_runtime_put);
+EXPORT_SYMBOL_GPL(__pm_runtime_resume);
 
 /**
  * __pm_runtime_set_status - Set run-time PM status of a device.
@@ -968,7 +933,7 @@ int pm_runtime_barrier(struct device *dev)
 
        if (dev->power.request_pending
            && dev->power.request == RPM_REQ_RESUME) {
-               __pm_runtime_resume(dev, false);
+               rpm_resume(dev, 0);
                retval = 1;
        }
 
@@ -1017,7 +982,7 @@ void __pm_runtime_disable(struct device *dev, bool check_resume)
                 */
                pm_runtime_get_noresume(dev);
 
-               __pm_runtime_resume(dev, false);
+               rpm_resume(dev, 0);
 
                pm_runtime_put_noidle(dev);
        }
@@ -1065,7 +1030,7 @@ void pm_runtime_forbid(struct device *dev)
 
        dev->power.runtime_auto = false;
        atomic_inc(&dev->power.usage_count);
-       __pm_runtime_resume(dev, false);
+       rpm_resume(dev, 0);
 
  out:
        spin_unlock_irq(&dev->power.lock);
@@ -1086,21 +1051,118 @@ void pm_runtime_allow(struct device *dev)
 
        dev->power.runtime_auto = true;
        if (atomic_dec_and_test(&dev->power.usage_count))
-               __pm_runtime_idle(dev);
+               rpm_idle(dev, RPM_AUTO);
 
  out:
        spin_unlock_irq(&dev->power.lock);
 }
 EXPORT_SYMBOL_GPL(pm_runtime_allow);
 
+/**
+ * pm_runtime_no_callbacks - Ignore run-time PM callbacks for a device.
+ * @dev: Device to handle.
+ *
+ * Set the power.no_callbacks flag, which tells the PM core that this
+ * device is power-managed through its parent and has no run-time PM
+ * callbacks of its own.  The run-time sysfs attributes will be removed.
+ *
+ */
+void pm_runtime_no_callbacks(struct device *dev)
+{
+       spin_lock_irq(&dev->power.lock);
+       dev->power.no_callbacks = 1;
+       spin_unlock_irq(&dev->power.lock);
+       if (device_is_registered(dev))
+               rpm_sysfs_remove(dev);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_no_callbacks);
+
+/**
+ * update_autosuspend - Handle a change to a device's autosuspend settings.
+ * @dev: Device to handle.
+ * @old_delay: The former autosuspend_delay value.
+ * @old_use: The former use_autosuspend value.
+ *
+ * Prevent runtime suspend if the new delay is negative and use_autosuspend is
+ * set; otherwise allow it.  Send an idle notification if suspends are allowed.
+ *
+ * This function must be called under dev->power.lock with interrupts disabled.
+ */
+static void update_autosuspend(struct device *dev, int old_delay, int old_use)
+{
+       int delay = dev->power.autosuspend_delay;
+
+       /* Should runtime suspend be prevented now? */
+       if (dev->power.use_autosuspend && delay < 0) {
+
+               /* If it used to be allowed then prevent it. */
+               if (!old_use || old_delay >= 0) {
+                       atomic_inc(&dev->power.usage_count);
+                       rpm_resume(dev, 0);
+               }
+       }
+
+       /* Runtime suspend should be allowed now. */
+       else {
+
+               /* If it used to be prevented then allow it. */
+               if (old_use && old_delay < 0)
+                       atomic_dec(&dev->power.usage_count);
+
+               /* Maybe we can autosuspend now. */
+               rpm_idle(dev, RPM_AUTO);
+       }
+}
+
+/**
+ * pm_runtime_set_autosuspend_delay - Set a device's autosuspend_delay value.
+ * @dev: Device to handle.
+ * @delay: Value of the new delay in milliseconds.
+ *
+ * Set the device's power.autosuspend_delay value.  If it changes to negative
+ * and the power.use_autosuspend flag is set, prevent run-time suspends.  If it
+ * changes the other way, allow run-time suspends.
+ */
+void pm_runtime_set_autosuspend_delay(struct device *dev, int delay)
+{
+       int old_delay, old_use;
+
+       spin_lock_irq(&dev->power.lock);
+       old_delay = dev->power.autosuspend_delay;
+       old_use = dev->power.use_autosuspend;
+       dev->power.autosuspend_delay = delay;
+       update_autosuspend(dev, old_delay, old_use);
+       spin_unlock_irq(&dev->power.lock);
+}
+EXPORT_SYMBOL_GPL(pm_runtime_set_autosuspend_delay);
+
+/**
+ * __pm_runtime_use_autosuspend - Set a device's use_autosuspend flag.
+ * @dev: Device to handle.
+ * @use: New value for use_autosuspend.
+ *
+ * Set the device's power.use_autosuspend flag, and allow or prevent run-time
+ * suspends as needed.
+ */
+void __pm_runtime_use_autosuspend(struct device *dev, bool use)
+{
+       int old_delay, old_use;
+
+       spin_lock_irq(&dev->power.lock);
+       old_delay = dev->power.autosuspend_delay;
+       old_use = dev->power.use_autosuspend;
+       dev->power.use_autosuspend = use;
+       update_autosuspend(dev, old_delay, old_use);
+       spin_unlock_irq(&dev->power.lock);
+}
+EXPORT_SYMBOL_GPL(__pm_runtime_use_autosuspend);
+
 /**
  * pm_runtime_init - Initialize run-time PM fields in given device object.
  * @dev: Device object to initialize.
  */
 void pm_runtime_init(struct device *dev)
 {
-       spin_lock_init(&dev->power.lock);
-
        dev->power.runtime_status = RPM_SUSPENDED;
        dev->power.idle_notification = false;
 
index e56b4388fe61004a1f85e0209cbc59bd60f4d1fb..0b1e46bf3e56950e45366ab46a664992ac2c1f0f 100644 (file)
  *     attribute is set to "enabled" by bus type code or device drivers and in
  *     that cases it should be safe to leave the default value.
  *
+ *     autosuspend_delay_ms - Report/change a device's autosuspend_delay value
+ *
+ *     Some drivers don't want to carry out a runtime suspend as soon as a
+ *     device becomes idle; they want it always to remain idle for some period
+ *     of time before suspending it.  This period is the autosuspend_delay
+ *     value (expressed in milliseconds) and it can be controlled by the user.
+ *     If the value is negative then the device will never be runtime
+ *     suspended.
+ *
+ *     NOTE: The autosuspend_delay_ms attribute and the autosuspend_delay
+ *     value are used only if the driver calls pm_runtime_use_autosuspend().
+ *
  *     wakeup_count - Report the number of wakeup events related to the device
  */
 
 static const char enabled[] = "enabled";
 static const char disabled[] = "disabled";
 
+const char power_group_name[] = "power";
+EXPORT_SYMBOL_GPL(power_group_name);
+
 #ifdef CONFIG_PM_RUNTIME
 static const char ctrl_auto[] = "auto";
 static const char ctrl_on[] = "on";
@@ -170,6 +185,33 @@ static ssize_t rtpm_status_show(struct device *dev,
 }
 
 static DEVICE_ATTR(runtime_status, 0444, rtpm_status_show, NULL);
+
+static ssize_t autosuspend_delay_ms_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       if (!dev->power.use_autosuspend)
+               return -EIO;
+       return sprintf(buf, "%d\n", dev->power.autosuspend_delay);
+}
+
+static ssize_t autosuspend_delay_ms_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t n)
+{
+       long delay;
+
+       if (!dev->power.use_autosuspend)
+               return -EIO;
+
+       if (strict_strtol(buf, 10, &delay) != 0 || delay != (int) delay)
+               return -EINVAL;
+
+       pm_runtime_set_autosuspend_delay(dev, delay);
+       return n;
+}
+
+static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
+               autosuspend_delay_ms_store);
+
 #endif
 
 static ssize_t
@@ -210,11 +252,122 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
 static ssize_t wakeup_count_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%lu\n", dev->power.wakeup_count);
+       unsigned long count = 0;
+       bool enabled = false;
+
+       spin_lock_irq(&dev->power.lock);
+       if (dev->power.wakeup) {
+               count = dev->power.wakeup->event_count;
+               enabled = true;
+       }
+       spin_unlock_irq(&dev->power.lock);
+       return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
 }
 
 static DEVICE_ATTR(wakeup_count, 0444, wakeup_count_show, NULL);
-#endif
+
+static ssize_t wakeup_active_count_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       unsigned long count = 0;
+       bool enabled = false;
+
+       spin_lock_irq(&dev->power.lock);
+       if (dev->power.wakeup) {
+               count = dev->power.wakeup->active_count;
+               enabled = true;
+       }
+       spin_unlock_irq(&dev->power.lock);
+       return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL);
+
+static ssize_t wakeup_hit_count_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       unsigned long count = 0;
+       bool enabled = false;
+
+       spin_lock_irq(&dev->power.lock);
+       if (dev->power.wakeup) {
+               count = dev->power.wakeup->hit_count;
+               enabled = true;
+       }
+       spin_unlock_irq(&dev->power.lock);
+       return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL);
+
+static ssize_t wakeup_active_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       unsigned int active = 0;
+       bool enabled = false;
+
+       spin_lock_irq(&dev->power.lock);
+       if (dev->power.wakeup) {
+               active = dev->power.wakeup->active;
+               enabled = true;
+       }
+       spin_unlock_irq(&dev->power.lock);
+       return enabled ? sprintf(buf, "%u\n", active) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_active, 0444, wakeup_active_show, NULL);
+
+static ssize_t wakeup_total_time_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       s64 msec = 0;
+       bool enabled = false;
+
+       spin_lock_irq(&dev->power.lock);
+       if (dev->power.wakeup) {
+               msec = ktime_to_ms(dev->power.wakeup->total_time);
+               enabled = true;
+       }
+       spin_unlock_irq(&dev->power.lock);
+       return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_total_time_ms, 0444, wakeup_total_time_show, NULL);
+
+static ssize_t wakeup_max_time_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       s64 msec = 0;
+       bool enabled = false;
+
+       spin_lock_irq(&dev->power.lock);
+       if (dev->power.wakeup) {
+               msec = ktime_to_ms(dev->power.wakeup->max_time);
+               enabled = true;
+       }
+       spin_unlock_irq(&dev->power.lock);
+       return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_max_time_ms, 0444, wakeup_max_time_show, NULL);
+
+static ssize_t wakeup_last_time_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       s64 msec = 0;
+       bool enabled = false;
+
+       spin_lock_irq(&dev->power.lock);
+       if (dev->power.wakeup) {
+               msec = ktime_to_ms(dev->power.wakeup->last_time);
+               enabled = true;
+       }
+       spin_unlock_irq(&dev->power.lock);
+       return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
+}
+
+static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PM_ADVANCED_DEBUG
 #ifdef CONFIG_PM_RUNTIME
@@ -279,19 +432,20 @@ static DEVICE_ATTR(async, 0644, async_show, async_store);
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
 
 static struct attribute * power_attrs[] = {
-#ifdef CONFIG_PM_RUNTIME
-       &dev_attr_control.attr,
-       &dev_attr_runtime_status.attr,
-       &dev_attr_runtime_suspended_time.attr,
-       &dev_attr_runtime_active_time.attr,
-#endif
        &dev_attr_wakeup.attr,
 #ifdef CONFIG_PM_SLEEP
        &dev_attr_wakeup_count.attr,
+       &dev_attr_wakeup_active_count.attr,
+       &dev_attr_wakeup_hit_count.attr,
+       &dev_attr_wakeup_active.attr,
+       &dev_attr_wakeup_total_time_ms.attr,
+       &dev_attr_wakeup_max_time_ms.attr,
+       &dev_attr_wakeup_last_time_ms.attr,
 #endif
 #ifdef CONFIG_PM_ADVANCED_DEBUG
        &dev_attr_async.attr,
 #ifdef CONFIG_PM_RUNTIME
+       &dev_attr_runtime_status.attr,
        &dev_attr_runtime_usage.attr,
        &dev_attr_runtime_active_kids.attr,
        &dev_attr_runtime_enabled.attr,
@@ -300,10 +454,53 @@ static struct attribute * power_attrs[] = {
        NULL,
 };
 static struct attribute_group pm_attr_group = {
-       .name   = "power",
+       .name   = power_group_name,
        .attrs  = power_attrs,
 };
 
+#ifdef CONFIG_PM_RUNTIME
+
+static struct attribute *runtime_attrs[] = {
+#ifndef CONFIG_PM_ADVANCED_DEBUG
+       &dev_attr_runtime_status.attr,
+#endif
+       &dev_attr_control.attr,
+       &dev_attr_runtime_suspended_time.attr,
+       &dev_attr_runtime_active_time.attr,
+       &dev_attr_autosuspend_delay_ms.attr,
+       NULL,
+};
+static struct attribute_group pm_runtime_attr_group = {
+       .name   = power_group_name,
+       .attrs  = runtime_attrs,
+};
+
+int dpm_sysfs_add(struct device *dev)
+{
+       int rc;
+
+       rc = sysfs_create_group(&dev->kobj, &pm_attr_group);
+       if (rc == 0 && !dev->power.no_callbacks) {
+               rc = sysfs_merge_group(&dev->kobj, &pm_runtime_attr_group);
+               if (rc)
+                       sysfs_remove_group(&dev->kobj, &pm_attr_group);
+       }
+       return rc;
+}
+
+void rpm_sysfs_remove(struct device *dev)
+{
+       sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);
+}
+
+void dpm_sysfs_remove(struct device *dev)
+{
+       rpm_sysfs_remove(dev);
+       sysfs_remove_group(&dev->kobj, &pm_attr_group);
+}
+
+#else /* CONFIG_PM_RUNTIME */
+
 int dpm_sysfs_add(struct device * dev)
 {
        return sysfs_create_group(&dev->kobj, &pm_attr_group);
@@ -313,3 +510,5 @@ void dpm_sysfs_remove(struct device * dev)
 {
        sysfs_remove_group(&dev->kobj, &pm_attr_group);
 }
+
+#endif
index 0a1a2c4dbc6e75e5647117b97ae1f055c2fdb080..9f4258df4cfdbace7c80d889154738f17c7d8461 100644 (file)
@@ -188,8 +188,10 @@ static int show_file_hash(unsigned int value)
 static int show_dev_hash(unsigned int value)
 {
        int match = 0;
-       struct list_head *entry = dpm_list.prev;
+       struct list_head *entry;
 
+       device_pm_lock();
+       entry = dpm_list.prev;
        while (entry != &dpm_list) {
                struct device * dev = to_device(entry);
                unsigned int hash = hash_string(DEVSEED, dev_name(dev), DEVHASH);
@@ -199,11 +201,43 @@ static int show_dev_hash(unsigned int value)
                }
                entry = entry->prev;
        }
+       device_pm_unlock();
        return match;
 }
 
 static unsigned int hash_value_early_read;
 
+int show_trace_dev_match(char *buf, size_t size)
+{
+       unsigned int value = hash_value_early_read / (USERHASH * FILEHASH);
+       int ret = 0;
+       struct list_head *entry;
+
+       /*
+        * It's possible that multiple devices will match the hash and we can't
+        * tell which is the culprit, so it's best to output them all.
+        */
+       device_pm_lock();
+       entry = dpm_list.prev;
+       while (size && entry != &dpm_list) {
+               struct device *dev = to_device(entry);
+               unsigned int hash = hash_string(DEVSEED, dev_name(dev),
+                                               DEVHASH);
+               if (hash == value) {
+                       int len = snprintf(buf, size, "%s\n",
+                                           dev_driver_string(dev));
+                       if (len > size)
+                               len = size;
+                       buf += len;
+                       ret += len;
+                       size -= len;
+               }
+               entry = entry->prev;
+       }
+       device_pm_unlock();
+       return ret;
+}
+
 static int early_resume_init(void)
 {
        hash_value_early_read = read_magic_time();
index eb594facfc3f8a027e982fb9b67984643c400219..71c5528e1c357a81112c6f79b1e91f013a58e3aa 100644 (file)
 #include <linux/sched.h>
 #include <linux/capability.h>
 #include <linux/suspend.h>
-#include <linux/pm.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include "power.h"
+
+#define TIMEOUT                100
 
 /*
  * If set, the suspend/hibernate code will abort transitions to a sleep state
 bool events_check_enabled;
 
 /* The counter of registered wakeup events. */
-static unsigned long event_count;
+static atomic_t event_count = ATOMIC_INIT(0);
 /* A preserved old value of event_count. */
-static unsigned long saved_event_count;
+static unsigned int saved_count;
 /* The counter of wakeup events being processed. */
-static unsigned long events_in_progress;
+static atomic_t events_in_progress = ATOMIC_INIT(0);
 
 static DEFINE_SPINLOCK(events_lock);
 
 static void pm_wakeup_timer_fn(unsigned long data);
 
-static DEFINE_TIMER(events_timer, pm_wakeup_timer_fn, 0, 0);
-static unsigned long events_timer_expires;
+static LIST_HEAD(wakeup_sources);
+
+/**
+ * wakeup_source_create - Create a struct wakeup_source object.
+ * @name: Name of the new wakeup source.
+ */
+struct wakeup_source *wakeup_source_create(const char *name)
+{
+       struct wakeup_source *ws;
+
+       ws = kzalloc(sizeof(*ws), GFP_KERNEL);
+       if (!ws)
+               return NULL;
+
+       spin_lock_init(&ws->lock);
+       if (name)
+               ws->name = kstrdup(name, GFP_KERNEL);
+
+       return ws;
+}
+EXPORT_SYMBOL_GPL(wakeup_source_create);
+
+/**
+ * wakeup_source_destroy - Destroy a struct wakeup_source object.
+ * @ws: Wakeup source to destroy.
+ */
+void wakeup_source_destroy(struct wakeup_source *ws)
+{
+       if (!ws)
+               return;
+
+       spin_lock_irq(&ws->lock);
+       while (ws->active) {
+               spin_unlock_irq(&ws->lock);
+
+               schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
+
+               spin_lock_irq(&ws->lock);
+       }
+       spin_unlock_irq(&ws->lock);
+
+       kfree(ws->name);
+       kfree(ws);
+}
+EXPORT_SYMBOL_GPL(wakeup_source_destroy);
+
+/**
+ * wakeup_source_add - Add given object to the list of wakeup sources.
+ * @ws: Wakeup source object to add to the list.
+ */
+void wakeup_source_add(struct wakeup_source *ws)
+{
+       if (WARN_ON(!ws))
+               return;
+
+       setup_timer(&ws->timer, pm_wakeup_timer_fn, (unsigned long)ws);
+       ws->active = false;
+
+       spin_lock_irq(&events_lock);
+       list_add_rcu(&ws->entry, &wakeup_sources);
+       spin_unlock_irq(&events_lock);
+       synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(wakeup_source_add);
+
+/**
+ * wakeup_source_remove - Remove given object from the wakeup sources list.
+ * @ws: Wakeup source object to remove from the list.
+ */
+void wakeup_source_remove(struct wakeup_source *ws)
+{
+       if (WARN_ON(!ws))
+               return;
+
+       spin_lock_irq(&events_lock);
+       list_del_rcu(&ws->entry);
+       spin_unlock_irq(&events_lock);
+       synchronize_rcu();
+}
+EXPORT_SYMBOL_GPL(wakeup_source_remove);
+
+/**
+ * wakeup_source_register - Create wakeup source and add it to the list.
+ * @name: Name of the wakeup source to register.
+ */
+struct wakeup_source *wakeup_source_register(const char *name)
+{
+       struct wakeup_source *ws;
+
+       ws = wakeup_source_create(name);
+       if (ws)
+               wakeup_source_add(ws);
+
+       return ws;
+}
+EXPORT_SYMBOL_GPL(wakeup_source_register);
+
+/**
+ * wakeup_source_unregister - Remove wakeup source from the list and remove it.
+ * @ws: Wakeup source object to unregister.
+ */
+void wakeup_source_unregister(struct wakeup_source *ws)
+{
+       wakeup_source_remove(ws);
+       wakeup_source_destroy(ws);
+}
+EXPORT_SYMBOL_GPL(wakeup_source_unregister);
+
+/**
+ * device_wakeup_attach - Attach a wakeup source object to a device object.
+ * @dev: Device to handle.
+ * @ws: Wakeup source object to attach to @dev.
+ *
+ * This causes @dev to be treated as a wakeup device.
+ */
+static int device_wakeup_attach(struct device *dev, struct wakeup_source *ws)
+{
+       spin_lock_irq(&dev->power.lock);
+       if (dev->power.wakeup) {
+               spin_unlock_irq(&dev->power.lock);
+               return -EEXIST;
+       }
+       dev->power.wakeup = ws;
+       spin_unlock_irq(&dev->power.lock);
+       return 0;
+}
+
+/**
+ * device_wakeup_enable - Enable given device to be a wakeup source.
+ * @dev: Device to handle.
+ *
+ * Create a wakeup source object, register it and attach it to @dev.
+ */
+int device_wakeup_enable(struct device *dev)
+{
+       struct wakeup_source *ws;
+       int ret;
+
+       if (!dev || !dev->power.can_wakeup)
+               return -EINVAL;
+
+       ws = wakeup_source_register(dev_name(dev));
+       if (!ws)
+               return -ENOMEM;
+
+       ret = device_wakeup_attach(dev, ws);
+       if (ret)
+               wakeup_source_unregister(ws);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(device_wakeup_enable);
+
+/**
+ * device_wakeup_detach - Detach a device's wakeup source object from it.
+ * @dev: Device to detach the wakeup source object from.
+ *
+ * After it returns, @dev will not be treated as a wakeup device any more.
+ */
+static struct wakeup_source *device_wakeup_detach(struct device *dev)
+{
+       struct wakeup_source *ws;
+
+       spin_lock_irq(&dev->power.lock);
+       ws = dev->power.wakeup;
+       dev->power.wakeup = NULL;
+       spin_unlock_irq(&dev->power.lock);
+       return ws;
+}
+
+/**
+ * device_wakeup_disable - Do not regard a device as a wakeup source any more.
+ * @dev: Device to handle.
+ *
+ * Detach the @dev's wakeup source object from it, unregister this wakeup source
+ * object and destroy it.
+ */
+int device_wakeup_disable(struct device *dev)
+{
+       struct wakeup_source *ws;
+
+       if (!dev || !dev->power.can_wakeup)
+               return -EINVAL;
+
+       ws = device_wakeup_detach(dev);
+       if (ws)
+               wakeup_source_unregister(ws);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(device_wakeup_disable);
+
+/**
+ * device_init_wakeup - Device wakeup initialization.
+ * @dev: Device to handle.
+ * @enable: Whether or not to enable @dev as a wakeup device.
+ *
+ * By default, most devices should leave wakeup disabled.  The exceptions are
+ * devices that everyone expects to be wakeup sources: keyboards, power buttons,
+ * possibly network interfaces, etc.
+ */
+int device_init_wakeup(struct device *dev, bool enable)
+{
+       int ret = 0;
+
+       if (enable) {
+               device_set_wakeup_capable(dev, true);
+               ret = device_wakeup_enable(dev);
+       } else {
+               device_set_wakeup_capable(dev, false);
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(device_init_wakeup);
+
+/**
+ * device_set_wakeup_enable - Enable or disable a device to wake up the system.
+ * @dev: Device to handle.
+ */
+int device_set_wakeup_enable(struct device *dev, bool enable)
+{
+       if (!dev || !dev->power.can_wakeup)
+               return -EINVAL;
+
+       return enable ? device_wakeup_enable(dev) : device_wakeup_disable(dev);
+}
+EXPORT_SYMBOL_GPL(device_set_wakeup_enable);
 
 /*
  * The functions below use the observation that each wakeup event starts a
@@ -55,118 +286,259 @@ static unsigned long events_timer_expires;
  * knowledge, however, may not be available to it, so it can simply specify time
  * to wait before the system can be suspended and pass it as the second
  * argument of pm_wakeup_event().
+ *
+ * It is valid to call pm_relax() after pm_wakeup_event(), in which case the
+ * "no suspend" period will be ended either by the pm_relax(), or by the timer
+ * function executed when the timer expires, whichever comes first.
  */
 
+/**
+ * wakup_source_activate - Mark given wakeup source as active.
+ * @ws: Wakeup source to handle.
+ *
+ * Update the @ws' statistics and, if @ws has just been activated, notify the PM
+ * core of the event by incrementing the counter of of wakeup events being
+ * processed.
+ */
+static void wakeup_source_activate(struct wakeup_source *ws)
+{
+       ws->active = true;
+       ws->active_count++;
+       ws->timer_expires = jiffies;
+       ws->last_time = ktime_get();
+
+       atomic_inc(&events_in_progress);
+}
+
+/**
+ * __pm_stay_awake - Notify the PM core of a wakeup event.
+ * @ws: Wakeup source object associated with the source of the event.
+ *
+ * It is safe to call this function from interrupt context.
+ */
+void __pm_stay_awake(struct wakeup_source *ws)
+{
+       unsigned long flags;
+
+       if (!ws)
+               return;
+
+       spin_lock_irqsave(&ws->lock, flags);
+       ws->event_count++;
+       if (!ws->active)
+               wakeup_source_activate(ws);
+       spin_unlock_irqrestore(&ws->lock, flags);
+}
+EXPORT_SYMBOL_GPL(__pm_stay_awake);
+
 /**
  * pm_stay_awake - Notify the PM core that a wakeup event is being processed.
  * @dev: Device the wakeup event is related to.
  *
- * Notify the PM core of a wakeup event (signaled by @dev) by incrementing the
- * counter of wakeup events being processed.  If @dev is not NULL, the counter
- * of wakeup events related to @dev is incremented too.
+ * Notify the PM core of a wakeup event (signaled by @dev) by calling
+ * __pm_stay_awake for the @dev's wakeup source object.
  *
  * Call this function after detecting of a wakeup event if pm_relax() is going
  * to be called directly after processing the event (and possibly passing it to
  * user space for further processing).
- *
- * It is safe to call this function from interrupt context.
  */
 void pm_stay_awake(struct device *dev)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&events_lock, flags);
-       if (dev)
-               dev->power.wakeup_count++;
+       if (!dev)
+               return;
 
-       events_in_progress++;
-       spin_unlock_irqrestore(&events_lock, flags);
+       spin_lock_irqsave(&dev->power.lock, flags);
+       __pm_stay_awake(dev->power.wakeup);
+       spin_unlock_irqrestore(&dev->power.lock, flags);
 }
+EXPORT_SYMBOL_GPL(pm_stay_awake);
 
 /**
- * pm_relax - Notify the PM core that processing of a wakeup event has ended.
+ * wakup_source_deactivate - Mark given wakeup source as inactive.
+ * @ws: Wakeup source to handle.
  *
- * Notify the PM core that a wakeup event has been processed by decrementing
- * the counter of wakeup events being processed and incrementing the counter
- * of registered wakeup events.
+ * Update the @ws' statistics and notify the PM core that the wakeup source has
+ * become inactive by decrementing the counter of wakeup events being processed
+ * and incrementing the counter of registered wakeup events.
+ */
+static void wakeup_source_deactivate(struct wakeup_source *ws)
+{
+       ktime_t duration;
+       ktime_t now;
+
+       ws->relax_count++;
+       /*
+        * __pm_relax() may be called directly or from a timer function.
+        * If it is called directly right after the timer function has been
+        * started, but before the timer function calls __pm_relax(), it is
+        * possible that __pm_stay_awake() will be called in the meantime and
+        * will set ws->active.  Then, ws->active may be cleared immediately
+        * by the __pm_relax() called from the timer function, but in such a
+        * case ws->relax_count will be different from ws->active_count.
+        */
+       if (ws->relax_count != ws->active_count) {
+               ws->relax_count--;
+               return;
+       }
+
+       ws->active = false;
+
+       now = ktime_get();
+       duration = ktime_sub(now, ws->last_time);
+       ws->total_time = ktime_add(ws->total_time, duration);
+       if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
+               ws->max_time = duration;
+
+       del_timer(&ws->timer);
+
+       /*
+        * event_count has to be incremented before events_in_progress is
+        * modified, so that the callers of pm_check_wakeup_events() and
+        * pm_save_wakeup_count() don't see the old value of event_count and
+        * events_in_progress equal to zero at the same time.
+        */
+       atomic_inc(&event_count);
+       smp_mb__before_atomic_dec();
+       atomic_dec(&events_in_progress);
+}
+
+/**
+ * __pm_relax - Notify the PM core that processing of a wakeup event has ended.
+ * @ws: Wakeup source object associated with the source of the event.
  *
  * Call this function for wakeup events whose processing started with calling
- * pm_stay_awake().
+ * __pm_stay_awake().
  *
  * It is safe to call it from interrupt context.
  */
-void pm_relax(void)
+void __pm_relax(struct wakeup_source *ws)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&events_lock, flags);
-       if (events_in_progress) {
-               events_in_progress--;
-               event_count++;
-       }
-       spin_unlock_irqrestore(&events_lock, flags);
+       if (!ws)
+               return;
+
+       spin_lock_irqsave(&ws->lock, flags);
+       if (ws->active)
+               wakeup_source_deactivate(ws);
+       spin_unlock_irqrestore(&ws->lock, flags);
+}
+EXPORT_SYMBOL_GPL(__pm_relax);
+
+/**
+ * pm_relax - Notify the PM core that processing of a wakeup event has ended.
+ * @dev: Device that signaled the event.
+ *
+ * Execute __pm_relax() for the @dev's wakeup source object.
+ */
+void pm_relax(struct device *dev)
+{
+       unsigned long flags;
+
+       if (!dev)
+               return;
+
+       spin_lock_irqsave(&dev->power.lock, flags);
+       __pm_relax(dev->power.wakeup);
+       spin_unlock_irqrestore(&dev->power.lock, flags);
 }
+EXPORT_SYMBOL_GPL(pm_relax);
 
 /**
  * pm_wakeup_timer_fn - Delayed finalization of a wakeup event.
+ * @data: Address of the wakeup source object associated with the event source.
  *
- * Decrease the counter of wakeup events being processed after it was increased
- * by pm_wakeup_event().
+ * Call __pm_relax() for the wakeup source whose address is stored in @data.
  */
 static void pm_wakeup_timer_fn(unsigned long data)
+{
+       __pm_relax((struct wakeup_source *)data);
+}
+
+/**
+ * __pm_wakeup_event - Notify the PM core of a wakeup event.
+ * @ws: Wakeup source object associated with the event source.
+ * @msec: Anticipated event processing time (in milliseconds).
+ *
+ * Notify the PM core of a wakeup event whose source is @ws that will take
+ * approximately @msec milliseconds to be processed by the kernel.  If @ws is
+ * not active, activate it.  If @msec is nonzero, set up the @ws' timer to
+ * execute pm_wakeup_timer_fn() in future.
+ *
+ * It is safe to call this function from interrupt context.
+ */
+void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
 {
        unsigned long flags;
+       unsigned long expires;
 
-       spin_lock_irqsave(&events_lock, flags);
-       if (events_timer_expires
-           && time_before_eq(events_timer_expires, jiffies)) {
-               events_in_progress--;
-               events_timer_expires = 0;
+       if (!ws)
+               return;
+
+       spin_lock_irqsave(&ws->lock, flags);
+
+       ws->event_count++;
+       if (!ws->active)
+               wakeup_source_activate(ws);
+
+       if (!msec) {
+               wakeup_source_deactivate(ws);
+               goto unlock;
        }
-       spin_unlock_irqrestore(&events_lock, flags);
+
+       expires = jiffies + msecs_to_jiffies(msec);
+       if (!expires)
+               expires = 1;
+
+       if (time_after(expires, ws->timer_expires)) {
+               mod_timer(&ws->timer, expires);
+               ws->timer_expires = expires;
+       }
+
+ unlock:
+       spin_unlock_irqrestore(&ws->lock, flags);
 }
+EXPORT_SYMBOL_GPL(__pm_wakeup_event);
+
 
 /**
  * pm_wakeup_event - Notify the PM core of a wakeup event.
  * @dev: Device the wakeup event is related to.
  * @msec: Anticipated event processing time (in milliseconds).
  *
- * Notify the PM core of a wakeup event (signaled by @dev) that will take
- * approximately @msec milliseconds to be processed by the kernel.  Increment
- * the counter of registered wakeup events and (if @msec is nonzero) set up
- * the wakeup events timer to execute pm_wakeup_timer_fn() in future (if the
- * timer has not been set up already, increment the counter of wakeup events
- * being processed).  If @dev is not NULL, the counter of wakeup events related
- * to @dev is incremented too.
- *
- * It is safe to call this function from interrupt context.
+ * Call __pm_wakeup_event() for the @dev's wakeup source object.
  */
 void pm_wakeup_event(struct device *dev, unsigned int msec)
 {
        unsigned long flags;
 
-       spin_lock_irqsave(&events_lock, flags);
-       event_count++;
-       if (dev)
-               dev->power.wakeup_count++;
-
-       if (msec) {
-               unsigned long expires;
+       if (!dev)
+               return;
 
-               expires = jiffies + msecs_to_jiffies(msec);
-               if (!expires)
-                       expires = 1;
+       spin_lock_irqsave(&dev->power.lock, flags);
+       __pm_wakeup_event(dev->power.wakeup, msec);
+       spin_unlock_irqrestore(&dev->power.lock, flags);
+}
+EXPORT_SYMBOL_GPL(pm_wakeup_event);
 
-               if (!events_timer_expires
-                   || time_after(expires, events_timer_expires)) {
-                       if (!events_timer_expires)
-                               events_in_progress++;
+/**
+ * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources.
+ */
+static void pm_wakeup_update_hit_counts(void)
+{
+       unsigned long flags;
+       struct wakeup_source *ws;
 
-                       mod_timer(&events_timer, expires);
-                       events_timer_expires = expires;
-               }
+       rcu_read_lock();
+       list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+               spin_lock_irqsave(&ws->lock, flags);
+               if (ws->active)
+                       ws->hit_count++;
+               spin_unlock_irqrestore(&ws->lock, flags);
        }
-       spin_unlock_irqrestore(&events_lock, flags);
+       rcu_read_unlock();
 }
 
 /**
@@ -184,10 +556,13 @@ bool pm_check_wakeup_events(void)
 
        spin_lock_irqsave(&events_lock, flags);
        if (events_check_enabled) {
-               ret = (event_count == saved_event_count) && !events_in_progress;
+               ret = ((unsigned int)atomic_read(&event_count) == saved_count)
+                       && !atomic_read(&events_in_progress);
                events_check_enabled = ret;
        }
        spin_unlock_irqrestore(&events_lock, flags);
+       if (!ret)
+               pm_wakeup_update_hit_counts();
        return ret;
 }
 
@@ -202,24 +577,20 @@ bool pm_check_wakeup_events(void)
  * drop down to zero has been interrupted by a signal (and the current number
  * of wakeup events being processed is still nonzero).  Otherwise return true.
  */
-bool pm_get_wakeup_count(unsigned long *count)
+bool pm_get_wakeup_count(unsigned int *count)
 {
        bool ret;
 
-       spin_lock_irq(&events_lock);
        if (capable(CAP_SYS_ADMIN))
                events_check_enabled = false;
 
-       while (events_in_progress && !signal_pending(current)) {
-               spin_unlock_irq(&events_lock);
-
-               schedule_timeout_interruptible(msecs_to_jiffies(100));
-
-               spin_lock_irq(&events_lock);
+       while (atomic_read(&events_in_progress) && !signal_pending(current)) {
+               pm_wakeup_update_hit_counts();
+               schedule_timeout_interruptible(msecs_to_jiffies(TIMEOUT));
        }
-       *count = event_count;
-       ret = !events_in_progress;
-       spin_unlock_irq(&events_lock);
+
+       ret = !atomic_read(&events_in_progress);
+       *count = atomic_read(&event_count);
        return ret;
 }
 
@@ -232,16 +603,102 @@ bool pm_get_wakeup_count(unsigned long *count)
  * old number of registered wakeup events to be used by pm_check_wakeup_events()
  * and return true.  Otherwise return false.
  */
-bool pm_save_wakeup_count(unsigned long count)
+bool pm_save_wakeup_count(unsigned int count)
 {
        bool ret = false;
 
        spin_lock_irq(&events_lock);
-       if (count == event_count && !events_in_progress) {
-               saved_event_count = count;
+       if (count == (unsigned int)atomic_read(&event_count)
+           && !atomic_read(&events_in_progress)) {
+               saved_count = count;
                events_check_enabled = true;
                ret = true;
        }
        spin_unlock_irq(&events_lock);
+       if (!ret)
+               pm_wakeup_update_hit_counts();
+       return ret;
+}
+
+static struct dentry *wakeup_sources_stats_dentry;
+
+/**
+ * print_wakeup_source_stats - Print wakeup source statistics information.
+ * @m: seq_file to print the statistics into.
+ * @ws: Wakeup source object to print the statistics for.
+ */
+static int print_wakeup_source_stats(struct seq_file *m,
+                                    struct wakeup_source *ws)
+{
+       unsigned long flags;
+       ktime_t total_time;
+       ktime_t max_time;
+       unsigned long active_count;
+       ktime_t active_time;
+       int ret;
+
+       spin_lock_irqsave(&ws->lock, flags);
+
+       total_time = ws->total_time;
+       max_time = ws->max_time;
+       active_count = ws->active_count;
+       if (ws->active) {
+               active_time = ktime_sub(ktime_get(), ws->last_time);
+               total_time = ktime_add(total_time, active_time);
+               if (active_time.tv64 > max_time.tv64)
+                       max_time = active_time;
+       } else {
+               active_time = ktime_set(0, 0);
+       }
+
+       ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t"
+                       "%lld\t\t%lld\t\t%lld\t\t%lld\n",
+                       ws->name, active_count, ws->event_count, ws->hit_count,
+                       ktime_to_ms(active_time), ktime_to_ms(total_time),
+                       ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
+
+       spin_unlock_irqrestore(&ws->lock, flags);
+
        return ret;
 }
+
+/**
+ * wakeup_sources_stats_show - Print wakeup sources statistics information.
+ * @m: seq_file to print the statistics into.
+ */
+static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
+{
+       struct wakeup_source *ws;
+
+       seq_puts(m, "name\t\tactive_count\tevent_count\thit_count\t"
+               "active_since\ttotal_time\tmax_time\tlast_change\n");
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(ws, &wakeup_sources, entry)
+               print_wakeup_source_stats(m, ws);
+       rcu_read_unlock();
+
+       return 0;
+}
+
+static int wakeup_sources_stats_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, wakeup_sources_stats_show, NULL);
+}
+
+static const struct file_operations wakeup_sources_stats_fops = {
+       .owner = THIS_MODULE,
+       .open = wakeup_sources_stats_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int __init wakeup_sources_debugfs_init(void)
+{
+       wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources",
+                       S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops);
+       return 0;
+}
+
+postcore_initcall(wakeup_sources_debugfs_init);
index 9fc630ce1ddb4b46f93dd2c35a459849399efa8b..f6f37a05a0c3a5664503040bcdfaae32516d6e6c 100644 (file)
@@ -45,7 +45,8 @@ static ssize_t show_##name(struct sys_device *dev,            \
        return sprintf(buf, "%d\n", topology_##name(cpu));      \
 }
 
-#if defined(topology_thread_cpumask) || defined(topology_core_cpumask)
+#if defined(topology_thread_cpumask) || defined(topology_core_cpumask) || \
+    defined(topology_book_cpumask)
 static ssize_t show_cpumap(int type, const struct cpumask *mask, char *buf)
 {
        ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
@@ -114,6 +115,14 @@ define_siblings_show_func(core_cpumask);
 define_one_ro_named(core_siblings, show_core_cpumask);
 define_one_ro_named(core_siblings_list, show_core_cpumask_list);
 
+#ifdef CONFIG_SCHED_BOOK
+define_id_show_func(book_id);
+define_one_ro(book_id);
+define_siblings_show_func(book_cpumask);
+define_one_ro_named(book_siblings, show_book_cpumask);
+define_one_ro_named(book_siblings_list, show_book_cpumask_list);
+#endif
+
 static struct attribute *default_attrs[] = {
        &attr_physical_package_id.attr,
        &attr_core_id.attr,
@@ -121,6 +130,11 @@ static struct attribute *default_attrs[] = {
        &attr_thread_siblings_list.attr,
        &attr_core_siblings.attr,
        &attr_core_siblings_list.attr,
+#ifdef CONFIG_SCHED_BOOK
+       &attr_book_id.attr,
+       &attr_book_siblings.attr,
+       &attr_book_siblings_list.attr,
+#endif
        NULL
 };
 
index de277689da6153fac725e54e50f752e7a6ee5978..4b9359a6f6ca45c4cd5f8803b5e7cdb9ba496678 100644 (file)
@@ -488,4 +488,21 @@ config BLK_DEV_HD
 
          If unsure, say N.
 
+config BLK_DEV_RBD
+       tristate "Rados block device (RBD)"
+       depends on INET && EXPERIMENTAL && BLOCK
+       select CEPH_LIB
+       select LIBCRC32C
+       select CRYPTO_AES
+       select CRYPTO
+       default n
+       help
+         Say Y here if you want include the Rados block device, which stripes
+         a block device over objects stored in the Ceph distributed object
+         store.
+
+         More information at http://ceph.newdream.net/.
+
+         If unsure, say N.
+
 endif # BLK_DEV
index aff5ac925c34332f235e523164f7f85cd76b6751..d7f463d6312d6494c3ef795c5b96ff11fa0ec801 100644 (file)
@@ -37,5 +37,6 @@ obj-$(CONFIG_BLK_DEV_HD)      += hd.o
 
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)      += xen-blkfront.o
 obj-$(CONFIG_BLK_DEV_DRBD)     += drbd/
+obj-$(CONFIG_BLK_DEV_RBD)     += rbd.o
 
 swim_mod-objs  := swim.o swim_asm.o
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
new file mode 100644 (file)
index 0000000..6ec9d53
--- /dev/null
@@ -0,0 +1,1841 @@
+/*
+   rbd.c -- Export ceph rados objects as a Linux block device
+
+
+   based on drivers/block/osdblk.c:
+
+   Copyright 2009 Red Hat, 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.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR 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.
+
+
+
+   Instructions for use
+   --------------------
+
+   1) Map a Linux block device to an existing rbd image.
+
+      Usage: <mon ip addr> <options> <pool name> <rbd image name> [snap name]
+
+      $ echo "192.168.0.1 name=admin rbd foo" > /sys/class/rbd/add
+
+      The snapshot name can be "-" or omitted to map the image read/write.
+
+   2) List all active blkdev<->object mappings.
+
+      In this example, we have performed step #1 twice, creating two blkdevs,
+      mapped to two separate rados objects in the rados rbd pool
+
+      $ cat /sys/class/rbd/list
+      #id     major   client_name     pool    name    snap    KB
+      0       254     client4143      rbd     foo     -      1024000
+
+      The columns, in order, are:
+      - blkdev unique id
+      - blkdev assigned major
+      - rados client id
+      - rados pool name
+      - rados block device name
+      - mapped snapshot ("-" if none)
+      - device size in KB
+
+
+   3) Create a snapshot.
+
+      Usage: <blkdev id> <snapname>
+
+      $ echo "0 mysnap" > /sys/class/rbd/snap_create
+
+
+   4) Listing a snapshot.
+
+      $ cat /sys/class/rbd/snaps_list
+      #id     snap    KB
+      0       -       1024000 (*)
+      0       foo     1024000
+
+      The columns, in order, are:
+      - blkdev unique id
+      - snapshot name, '-' means none (active read/write version)
+      - size of device at time of snapshot
+      - the (*) indicates this is the active version
+
+   5) Rollback to snapshot.
+
+      Usage: <blkdev id> <snapname>
+
+      $ echo "0 mysnap" > /sys/class/rbd/snap_rollback
+
+
+   6) Mapping an image using snapshot.
+
+      A snapshot mapping is read-only. This is being done by passing
+      snap=<snapname> to the options when adding a device.
+
+      $ echo "192.168.0.1 name=admin,snap=mysnap rbd foo" > /sys/class/rbd/add
+
+
+   7) Remove an active blkdev<->rbd image mapping.
+
+      In this example, we remove the mapping with blkdev unique id 1.
+
+      $ echo 1 > /sys/class/rbd/remove
+
+
+   NOTE:  The actual creation and deletion of rados objects is outside the scope
+   of this driver.
+
+ */
+
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/osd_client.h>
+#include <linux/ceph/mon_client.h>
+#include <linux/ceph/decode.h>
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+
+#include "rbd_types.h"
+
+#define DRV_NAME "rbd"
+#define DRV_NAME_LONG "rbd (rados block device)"
+
+#define RBD_MINORS_PER_MAJOR   256             /* max minors per blkdev */
+
+#define RBD_MAX_MD_NAME_LEN    (96 + sizeof(RBD_SUFFIX))
+#define RBD_MAX_POOL_NAME_LEN  64
+#define RBD_MAX_SNAP_NAME_LEN  32
+#define RBD_MAX_OPT_LEN                1024
+
+#define RBD_SNAP_HEAD_NAME     "-"
+
+#define DEV_NAME_LEN           32
+
+/*
+ * block device image metadata (in-memory version)
+ */
+struct rbd_image_header {
+       u64 image_size;
+       char block_name[32];
+       __u8 obj_order;
+       __u8 crypt_type;
+       __u8 comp_type;
+       struct rw_semaphore snap_rwsem;
+       struct ceph_snap_context *snapc;
+       size_t snap_names_len;
+       u64 snap_seq;
+       u32 total_snaps;
+
+       char *snap_names;
+       u64 *snap_sizes;
+};
+
+/*
+ * an instance of the client.  multiple devices may share a client.
+ */
+struct rbd_client {
+       struct ceph_client      *client;
+       struct kref             kref;
+       struct list_head        node;
+};
+
+/*
+ * a single io request
+ */
+struct rbd_request {
+       struct request          *rq;            /* blk layer request */
+       struct bio              *bio;           /* cloned bio */
+       struct page             **pages;        /* list of used pages */
+       u64                     len;
+};
+
+/*
+ * a single device
+ */
+struct rbd_device {
+       int                     id;             /* blkdev unique id */
+
+       int                     major;          /* blkdev assigned major */
+       struct gendisk          *disk;          /* blkdev's gendisk and rq */
+       struct request_queue    *q;
+
+       struct ceph_client      *client;
+       struct rbd_client       *rbd_client;
+
+       char                    name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */
+
+       spinlock_t              lock;           /* queue lock */
+
+       struct rbd_image_header header;
+       char                    obj[RBD_MAX_OBJ_NAME_LEN]; /* rbd image name */
+       int                     obj_len;
+       char                    obj_md_name[RBD_MAX_MD_NAME_LEN]; /* hdr nm. */
+       char                    pool_name[RBD_MAX_POOL_NAME_LEN];
+       int                     poolid;
+
+       char                    snap_name[RBD_MAX_SNAP_NAME_LEN];
+       u32 cur_snap;   /* index+1 of current snapshot within snap context
+                          0 - for the head */
+       int read_only;
+
+       struct list_head        node;
+};
+
+static spinlock_t node_lock;      /* protects client get/put */
+
+static struct class *class_rbd;          /* /sys/class/rbd */
+static DEFINE_MUTEX(ctl_mutex);          /* Serialize open/close/setup/teardown */
+static LIST_HEAD(rbd_dev_list);    /* devices */
+static LIST_HEAD(rbd_client_list);      /* clients */
+
+
+static int rbd_open(struct block_device *bdev, fmode_t mode)
+{
+       struct gendisk *disk = bdev->bd_disk;
+       struct rbd_device *rbd_dev = disk->private_data;
+
+       set_device_ro(bdev, rbd_dev->read_only);
+
+       if ((mode & FMODE_WRITE) && rbd_dev->read_only)
+               return -EROFS;
+
+       return 0;
+}
+
+static const struct block_device_operations rbd_bd_ops = {
+       .owner                  = THIS_MODULE,
+       .open                   = rbd_open,
+};
+
+/*
+ * Initialize an rbd client instance.
+ * We own *opt.
+ */
+static struct rbd_client *rbd_client_create(struct ceph_options *opt)
+{
+       struct rbd_client *rbdc;
+       int ret = -ENOMEM;
+
+       dout("rbd_client_create\n");
+       rbdc = kmalloc(sizeof(struct rbd_client), GFP_KERNEL);
+       if (!rbdc)
+               goto out_opt;
+
+       kref_init(&rbdc->kref);
+       INIT_LIST_HEAD(&rbdc->node);
+
+       rbdc->client = ceph_create_client(opt, rbdc);
+       if (IS_ERR(rbdc->client))
+               goto out_rbdc;
+       opt = NULL; /* Now rbdc->client is responsible for opt */
+
+       ret = ceph_open_session(rbdc->client);
+       if (ret < 0)
+               goto out_err;
+
+       spin_lock(&node_lock);
+       list_add_tail(&rbdc->node, &rbd_client_list);
+       spin_unlock(&node_lock);
+
+       dout("rbd_client_create created %p\n", rbdc);
+       return rbdc;
+
+out_err:
+       ceph_destroy_client(rbdc->client);
+out_rbdc:
+       kfree(rbdc);
+out_opt:
+       if (opt)
+               ceph_destroy_options(opt);
+       return ERR_PTR(ret);
+}
+
+/*
+ * Find a ceph client with specific addr and configuration.
+ */
+static struct rbd_client *__rbd_client_find(struct ceph_options *opt)
+{
+       struct rbd_client *client_node;
+
+       if (opt->flags & CEPH_OPT_NOSHARE)
+               return NULL;
+
+       list_for_each_entry(client_node, &rbd_client_list, node)
+               if (ceph_compare_options(opt, client_node->client) == 0)
+                       return client_node;
+       return NULL;
+}
+
+/*
+ * Get a ceph client with specific addr and configuration, if one does
+ * not exist create it.
+ */
+static int rbd_get_client(struct rbd_device *rbd_dev, const char *mon_addr,
+                         char *options)
+{
+       struct rbd_client *rbdc;
+       struct ceph_options *opt;
+       int ret;
+
+       ret = ceph_parse_options(&opt, options, mon_addr,
+                                mon_addr + strlen(mon_addr), NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       spin_lock(&node_lock);
+       rbdc = __rbd_client_find(opt);
+       if (rbdc) {
+               ceph_destroy_options(opt);
+
+               /* using an existing client */
+               kref_get(&rbdc->kref);
+               rbd_dev->rbd_client = rbdc;
+               rbd_dev->client = rbdc->client;
+               spin_unlock(&node_lock);
+               return 0;
+       }
+       spin_unlock(&node_lock);
+
+       rbdc = rbd_client_create(opt);
+       if (IS_ERR(rbdc))
+               return PTR_ERR(rbdc);
+
+       rbd_dev->rbd_client = rbdc;
+       rbd_dev->client = rbdc->client;
+       return 0;
+}
+
+/*
+ * Destroy ceph client
+ */
+static void rbd_client_release(struct kref *kref)
+{
+       struct rbd_client *rbdc = container_of(kref, struct rbd_client, kref);
+
+       dout("rbd_release_client %p\n", rbdc);
+       spin_lock(&node_lock);
+       list_del(&rbdc->node);
+       spin_unlock(&node_lock);
+
+       ceph_destroy_client(rbdc->client);
+       kfree(rbdc);
+}
+
+/*
+ * Drop reference to ceph client node. If it's not referenced anymore, release
+ * it.
+ */
+static void rbd_put_client(struct rbd_device *rbd_dev)
+{
+       kref_put(&rbd_dev->rbd_client->kref, rbd_client_release);
+       rbd_dev->rbd_client = NULL;
+       rbd_dev->client = NULL;
+}
+
+
+/*
+ * Create a new header structure, translate header format from the on-disk
+ * header.
+ */
+static int rbd_header_from_disk(struct rbd_image_header *header,
+                                struct rbd_image_header_ondisk *ondisk,
+                                int allocated_snaps,
+                                gfp_t gfp_flags)
+{
+       int i;
+       u32 snap_count = le32_to_cpu(ondisk->snap_count);
+       int ret = -ENOMEM;
+
+       init_rwsem(&header->snap_rwsem);
+
+       header->snap_names_len = le64_to_cpu(ondisk->snap_names_len);
+       header->snapc = kmalloc(sizeof(struct ceph_snap_context) +
+                               snap_count *
+                                sizeof(struct rbd_image_snap_ondisk),
+                               gfp_flags);
+       if (!header->snapc)
+               return -ENOMEM;
+       if (snap_count) {
+               header->snap_names = kmalloc(header->snap_names_len,
+                                            GFP_KERNEL);
+               if (!header->snap_names)
+                       goto err_snapc;
+               header->snap_sizes = kmalloc(snap_count * sizeof(u64),
+                                            GFP_KERNEL);
+               if (!header->snap_sizes)
+                       goto err_names;
+       } else {
+               header->snap_names = NULL;
+               header->snap_sizes = NULL;
+       }
+       memcpy(header->block_name, ondisk->block_name,
+              sizeof(ondisk->block_name));
+
+       header->image_size = le64_to_cpu(ondisk->image_size);
+       header->obj_order = ondisk->options.order;
+       header->crypt_type = ondisk->options.crypt_type;
+       header->comp_type = ondisk->options.comp_type;
+
+       atomic_set(&header->snapc->nref, 1);
+       header->snap_seq = le64_to_cpu(ondisk->snap_seq);
+       header->snapc->num_snaps = snap_count;
+       header->total_snaps = snap_count;
+
+       if (snap_count &&
+           allocated_snaps == snap_count) {
+               for (i = 0; i < snap_count; i++) {
+                       header->snapc->snaps[i] =
+                               le64_to_cpu(ondisk->snaps[i].id);
+                       header->snap_sizes[i] =
+                               le64_to_cpu(ondisk->snaps[i].image_size);
+               }
+
+               /* copy snapshot names */
+               memcpy(header->snap_names, &ondisk->snaps[i],
+                       header->snap_names_len);
+       }
+
+       return 0;
+
+err_names:
+       kfree(header->snap_names);
+err_snapc:
+       kfree(header->snapc);
+       return ret;
+}
+
+static int snap_index(struct rbd_image_header *header, int snap_num)
+{
+       return header->total_snaps - snap_num;
+}
+
+static u64 cur_snap_id(struct rbd_device *rbd_dev)
+{
+       struct rbd_image_header *header = &rbd_dev->header;
+
+       if (!rbd_dev->cur_snap)
+               return 0;
+
+       return header->snapc->snaps[snap_index(header, rbd_dev->cur_snap)];
+}
+
+static int snap_by_name(struct rbd_image_header *header, const char *snap_name,
+                       u64 *seq, u64 *size)
+{
+       int i;
+       char *p = header->snap_names;
+
+       for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) {
+               if (strcmp(snap_name, p) == 0)
+                       break;
+       }
+       if (i == header->total_snaps)
+               return -ENOENT;
+       if (seq)
+               *seq = header->snapc->snaps[i];
+
+       if (size)
+               *size = header->snap_sizes[i];
+
+       return i;
+}
+
+static int rbd_header_set_snap(struct rbd_device *dev,
+                              const char *snap_name,
+                              u64 *size)
+{
+       struct rbd_image_header *header = &dev->header;
+       struct ceph_snap_context *snapc = header->snapc;
+       int ret = -ENOENT;
+
+       down_write(&header->snap_rwsem);
+
+       if (!snap_name ||
+           !*snap_name ||
+           strcmp(snap_name, "-") == 0 ||
+           strcmp(snap_name, RBD_SNAP_HEAD_NAME) == 0) {
+               if (header->total_snaps)
+                       snapc->seq = header->snap_seq;
+               else
+                       snapc->seq = 0;
+               dev->cur_snap = 0;
+               dev->read_only = 0;
+               if (size)
+                       *size = header->image_size;
+       } else {
+               ret = snap_by_name(header, snap_name, &snapc->seq, size);
+               if (ret < 0)
+                       goto done;
+
+               dev->cur_snap = header->total_snaps - ret;
+               dev->read_only = 1;
+       }
+
+       ret = 0;
+done:
+       up_write(&header->snap_rwsem);
+       return ret;
+}
+
+static void rbd_header_free(struct rbd_image_header *header)
+{
+       kfree(header->snapc);
+       kfree(header->snap_names);
+       kfree(header->snap_sizes);
+}
+
+/*
+ * get the actual striped segment name, offset and length
+ */
+static u64 rbd_get_segment(struct rbd_image_header *header,
+                          const char *block_name,
+                          u64 ofs, u64 len,
+                          char *seg_name, u64 *segofs)
+{
+       u64 seg = ofs >> header->obj_order;
+
+       if (seg_name)
+               snprintf(seg_name, RBD_MAX_SEG_NAME_LEN,
+                        "%s.%012llx", block_name, seg);
+
+       ofs = ofs & ((1 << header->obj_order) - 1);
+       len = min_t(u64, len, (1 << header->obj_order) - ofs);
+
+       if (segofs)
+               *segofs = ofs;
+
+       return len;
+}
+
+/*
+ * bio helpers
+ */
+
+static void bio_chain_put(struct bio *chain)
+{
+       struct bio *tmp;
+
+       while (chain) {
+               tmp = chain;
+               chain = chain->bi_next;
+               bio_put(tmp);
+       }
+}
+
+/*
+ * zeros a bio chain, starting at specific offset
+ */
+static void zero_bio_chain(struct bio *chain, int start_ofs)
+{
+       struct bio_vec *bv;
+       unsigned long flags;
+       void *buf;
+       int i;
+       int pos = 0;
+
+       while (chain) {
+               bio_for_each_segment(bv, chain, i) {
+                       if (pos + bv->bv_len > start_ofs) {
+                               int remainder = max(start_ofs - pos, 0);
+                               buf = bvec_kmap_irq(bv, &flags);
+                               memset(buf + remainder, 0,
+                                      bv->bv_len - remainder);
+                               bvec_kunmap_irq(buf, &flags);
+                       }
+                       pos += bv->bv_len;
+               }
+
+               chain = chain->bi_next;
+       }
+}
+
+/*
+ * bio_chain_clone - clone a chain of bios up to a certain length.
+ * might return a bio_pair that will need to be released.
+ */
+static struct bio *bio_chain_clone(struct bio **old, struct bio **next,
+                                  struct bio_pair **bp,
+                                  int len, gfp_t gfpmask)
+{
+       struct bio *tmp, *old_chain = *old, *new_chain = NULL, *tail = NULL;
+       int total = 0;
+
+       if (*bp) {
+               bio_pair_release(*bp);
+               *bp = NULL;
+       }
+
+       while (old_chain && (total < len)) {
+               tmp = bio_kmalloc(gfpmask, old_chain->bi_max_vecs);
+               if (!tmp)
+                       goto err_out;
+
+               if (total + old_chain->bi_size > len) {
+                       struct bio_pair *bp;
+
+                       /*
+                        * this split can only happen with a single paged bio,
+                        * split_bio will BUG_ON if this is not the case
+                        */
+                       dout("bio_chain_clone split! total=%d remaining=%d"
+                            "bi_size=%d\n",
+                            (int)total, (int)len-total,
+                            (int)old_chain->bi_size);
+
+                       /* split the bio. We'll release it either in the next
+                          call, or it will have to be released outside */
+                       bp = bio_split(old_chain, (len - total) / 512ULL);
+                       if (!bp)
+                               goto err_out;
+
+                       __bio_clone(tmp, &bp->bio1);
+
+                       *next = &bp->bio2;
+               } else {
+                       __bio_clone(tmp, old_chain);
+                       *next = old_chain->bi_next;
+               }
+
+               tmp->bi_bdev = NULL;
+               gfpmask &= ~__GFP_WAIT;
+               tmp->bi_next = NULL;
+
+               if (!new_chain) {
+                       new_chain = tail = tmp;
+               } else {
+                       tail->bi_next = tmp;
+                       tail = tmp;
+               }
+               old_chain = old_chain->bi_next;
+
+               total += tmp->bi_size;
+       }
+
+       BUG_ON(total < len);
+
+       if (tail)
+               tail->bi_next = NULL;
+
+       *old = old_chain;
+
+       return new_chain;
+
+err_out:
+       dout("bio_chain_clone with err\n");
+       bio_chain_put(new_chain);
+       return NULL;
+}
+
+/*
+ * helpers for osd request op vectors.
+ */
+static int rbd_create_rw_ops(struct ceph_osd_req_op **ops,
+                           int num_ops,
+                           int opcode,
+                           u32 payload_len)
+{
+       *ops = kzalloc(sizeof(struct ceph_osd_req_op) * (num_ops + 1),
+                      GFP_NOIO);
+       if (!*ops)
+               return -ENOMEM;
+       (*ops)[0].op = opcode;
+       /*
+        * op extent offset and length will be set later on
+        * in calc_raw_layout()
+        */
+       (*ops)[0].payload_len = payload_len;
+       return 0;
+}
+
+static void rbd_destroy_ops(struct ceph_osd_req_op *ops)
+{
+       kfree(ops);
+}
+
+/*
+ * Send ceph osd request
+ */
+static int rbd_do_request(struct request *rq,
+                         struct rbd_device *dev,
+                         struct ceph_snap_context *snapc,
+                         u64 snapid,
+                         const char *obj, u64 ofs, u64 len,
+                         struct bio *bio,
+                         struct page **pages,
+                         int num_pages,
+                         int flags,
+                         struct ceph_osd_req_op *ops,
+                         int num_reply,
+                         void (*rbd_cb)(struct ceph_osd_request *req,
+                                        struct ceph_msg *msg))
+{
+       struct ceph_osd_request *req;
+       struct ceph_file_layout *layout;
+       int ret;
+       u64 bno;
+       struct timespec mtime = CURRENT_TIME;
+       struct rbd_request *req_data;
+       struct ceph_osd_request_head *reqhead;
+       struct rbd_image_header *header = &dev->header;
+
+       ret = -ENOMEM;
+       req_data = kzalloc(sizeof(*req_data), GFP_NOIO);
+       if (!req_data)
+               goto done;
+
+       dout("rbd_do_request len=%lld ofs=%lld\n", len, ofs);
+
+       down_read(&header->snap_rwsem);
+
+       req = ceph_osdc_alloc_request(&dev->client->osdc, flags,
+                                     snapc,
+                                     ops,
+                                     false,
+                                     GFP_NOIO, pages, bio);
+       if (IS_ERR(req)) {
+               up_read(&header->snap_rwsem);
+               ret = PTR_ERR(req);
+               goto done_pages;
+       }
+
+       req->r_callback = rbd_cb;
+
+       req_data->rq = rq;
+       req_data->bio = bio;
+       req_data->pages = pages;
+       req_data->len = len;
+
+       req->r_priv = req_data;
+
+       reqhead = req->r_request->front.iov_base;
+       reqhead->snapid = cpu_to_le64(CEPH_NOSNAP);
+
+       strncpy(req->r_oid, obj, sizeof(req->r_oid));
+       req->r_oid_len = strlen(req->r_oid);
+
+       layout = &req->r_file_layout;
+       memset(layout, 0, sizeof(*layout));
+       layout->fl_stripe_unit = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
+       layout->fl_stripe_count = cpu_to_le32(1);
+       layout->fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
+       layout->fl_pg_preferred = cpu_to_le32(-1);
+       layout->fl_pg_pool = cpu_to_le32(dev->poolid);
+       ceph_calc_raw_layout(&dev->client->osdc, layout, snapid,
+                            ofs, &len, &bno, req, ops);
+
+       ceph_osdc_build_request(req, ofs, &len,
+                               ops,
+                               snapc,
+                               &mtime,
+                               req->r_oid, req->r_oid_len);
+       up_read(&header->snap_rwsem);
+
+       ret = ceph_osdc_start_request(&dev->client->osdc, req, false);
+       if (ret < 0)
+               goto done_err;
+
+       if (!rbd_cb) {
+               ret = ceph_osdc_wait_request(&dev->client->osdc, req);
+               ceph_osdc_put_request(req);
+       }
+       return ret;
+
+done_err:
+       bio_chain_put(req_data->bio);
+       ceph_osdc_put_request(req);
+done_pages:
+       kfree(req_data);
+done:
+       if (rq)
+               blk_end_request(rq, ret, len);
+       return ret;
+}
+
+/*
+ * Ceph osd op callback
+ */
+static void rbd_req_cb(struct ceph_osd_request *req, struct ceph_msg *msg)
+{
+       struct rbd_request *req_data = req->r_priv;
+       struct ceph_osd_reply_head *replyhead;
+       struct ceph_osd_op *op;
+       __s32 rc;
+       u64 bytes;
+       int read_op;
+
+       /* parse reply */
+       replyhead = msg->front.iov_base;
+       WARN_ON(le32_to_cpu(replyhead->num_ops) == 0);
+       op = (void *)(replyhead + 1);
+       rc = le32_to_cpu(replyhead->result);
+       bytes = le64_to_cpu(op->extent.length);
+       read_op = (le32_to_cpu(op->op) == CEPH_OSD_OP_READ);
+
+       dout("rbd_req_cb bytes=%lld readop=%d rc=%d\n", bytes, read_op, rc);
+
+       if (rc == -ENOENT && read_op) {
+               zero_bio_chain(req_data->bio, 0);
+               rc = 0;
+       } else if (rc == 0 && read_op && bytes < req_data->len) {
+               zero_bio_chain(req_data->bio, bytes);
+               bytes = req_data->len;
+       }
+
+       blk_end_request(req_data->rq, rc, bytes);
+
+       if (req_data->bio)
+               bio_chain_put(req_data->bio);
+
+       ceph_osdc_put_request(req);
+       kfree(req_data);
+}
+
+/*
+ * Do a synchronous ceph osd operation
+ */
+static int rbd_req_sync_op(struct rbd_device *dev,
+                          struct ceph_snap_context *snapc,
+                          u64 snapid,
+                          int opcode,
+                          int flags,
+                          struct ceph_osd_req_op *orig_ops,
+                          int num_reply,
+                          const char *obj,
+                          u64 ofs, u64 len,
+                          char *buf)
+{
+       int ret;
+       struct page **pages;
+       int num_pages;
+       struct ceph_osd_req_op *ops = orig_ops;
+       u32 payload_len;
+
+       num_pages = calc_pages_for(ofs , len);
+       pages = ceph_alloc_page_vector(num_pages, GFP_KERNEL);
+       if (IS_ERR(pages))
+               return PTR_ERR(pages);
+
+       if (!orig_ops) {
+               payload_len = (flags & CEPH_OSD_FLAG_WRITE ? len : 0);
+               ret = rbd_create_rw_ops(&ops, 1, opcode, payload_len);
+               if (ret < 0)
+                       goto done;
+
+               if ((flags & CEPH_OSD_FLAG_WRITE) && buf) {
+                       ret = ceph_copy_to_page_vector(pages, buf, ofs, len);
+                       if (ret < 0)
+                               goto done_ops;
+               }
+       }
+
+       ret = rbd_do_request(NULL, dev, snapc, snapid,
+                         obj, ofs, len, NULL,
+                         pages, num_pages,
+                         flags,
+                         ops,
+                         2,
+                         NULL);
+       if (ret < 0)
+               goto done_ops;
+
+       if ((flags & CEPH_OSD_FLAG_READ) && buf)
+               ret = ceph_copy_from_page_vector(pages, buf, ofs, ret);
+
+done_ops:
+       if (!orig_ops)
+               rbd_destroy_ops(ops);
+done:
+       ceph_release_page_vector(pages, num_pages);
+       return ret;
+}
+
+/*
+ * Do an asynchronous ceph osd operation
+ */
+static int rbd_do_op(struct request *rq,
+                    struct rbd_device *rbd_dev ,
+                    struct ceph_snap_context *snapc,
+                    u64 snapid,
+                    int opcode, int flags, int num_reply,
+                    u64 ofs, u64 len,
+                    struct bio *bio)
+{
+       char *seg_name;
+       u64 seg_ofs;
+       u64 seg_len;
+       int ret;
+       struct ceph_osd_req_op *ops;
+       u32 payload_len;
+
+       seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO);
+       if (!seg_name)
+               return -ENOMEM;
+
+       seg_len = rbd_get_segment(&rbd_dev->header,
+                                 rbd_dev->header.block_name,
+                                 ofs, len,
+                                 seg_name, &seg_ofs);
+
+       payload_len = (flags & CEPH_OSD_FLAG_WRITE ? seg_len : 0);
+
+       ret = rbd_create_rw_ops(&ops, 1, opcode, payload_len);
+       if (ret < 0)
+               goto done;
+
+       /* we've taken care of segment sizes earlier when we
+          cloned the bios. We should never have a segment
+          truncated at this point */
+       BUG_ON(seg_len < len);
+
+       ret = rbd_do_request(rq, rbd_dev, snapc, snapid,
+                            seg_name, seg_ofs, seg_len,
+                            bio,
+                            NULL, 0,
+                            flags,
+                            ops,
+                            num_reply,
+                            rbd_req_cb);
+done:
+       kfree(seg_name);
+       return ret;
+}
+
+/*
+ * Request async osd write
+ */
+static int rbd_req_write(struct request *rq,
+                        struct rbd_device *rbd_dev,
+                        struct ceph_snap_context *snapc,
+                        u64 ofs, u64 len,
+                        struct bio *bio)
+{
+       return rbd_do_op(rq, rbd_dev, snapc, CEPH_NOSNAP,
+                        CEPH_OSD_OP_WRITE,
+                        CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+                        2,
+                        ofs, len, bio);
+}
+
+/*
+ * Request async osd read
+ */
+static int rbd_req_read(struct request *rq,
+                        struct rbd_device *rbd_dev,
+                        u64 snapid,
+                        u64 ofs, u64 len,
+                        struct bio *bio)
+{
+       return rbd_do_op(rq, rbd_dev, NULL,
+                        (snapid ? snapid : CEPH_NOSNAP),
+                        CEPH_OSD_OP_READ,
+                        CEPH_OSD_FLAG_READ,
+                        2,
+                        ofs, len, bio);
+}
+
+/*
+ * Request sync osd read
+ */
+static int rbd_req_sync_read(struct rbd_device *dev,
+                         struct ceph_snap_context *snapc,
+                         u64 snapid,
+                         const char *obj,
+                         u64 ofs, u64 len,
+                         char *buf)
+{
+       return rbd_req_sync_op(dev, NULL,
+                              (snapid ? snapid : CEPH_NOSNAP),
+                              CEPH_OSD_OP_READ,
+                              CEPH_OSD_FLAG_READ,
+                              NULL,
+                              1, obj, ofs, len, buf);
+}
+
+/*
+ * Request sync osd read
+ */
+static int rbd_req_sync_rollback_obj(struct rbd_device *dev,
+                                    u64 snapid,
+                                    const char *obj)
+{
+       struct ceph_osd_req_op *ops;
+       int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_ROLLBACK, 0);
+       if (ret < 0)
+               return ret;
+
+       ops[0].snap.snapid = snapid;
+
+       ret = rbd_req_sync_op(dev, NULL,
+                              CEPH_NOSNAP,
+                              0,
+                              CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+                              ops,
+                              1, obj, 0, 0, NULL);
+
+       rbd_destroy_ops(ops);
+
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+/*
+ * Request sync osd read
+ */
+static int rbd_req_sync_exec(struct rbd_device *dev,
+                            const char *obj,
+                            const char *cls,
+                            const char *method,
+                            const char *data,
+                            int len)
+{
+       struct ceph_osd_req_op *ops;
+       int cls_len = strlen(cls);
+       int method_len = strlen(method);
+       int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_CALL,
+                                   cls_len + method_len + len);
+       if (ret < 0)
+               return ret;
+
+       ops[0].cls.class_name = cls;
+       ops[0].cls.class_len = (__u8)cls_len;
+       ops[0].cls.method_name = method;
+       ops[0].cls.method_len = (__u8)method_len;
+       ops[0].cls.argc = 0;
+       ops[0].cls.indata = data;
+       ops[0].cls.indata_len = len;
+
+       ret = rbd_req_sync_op(dev, NULL,
+                              CEPH_NOSNAP,
+                              0,
+                              CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK,
+                              ops,
+                              1, obj, 0, 0, NULL);
+
+       rbd_destroy_ops(ops);
+
+       dout("cls_exec returned %d\n", ret);
+       return ret;
+}
+
+/*
+ * block device queue callback
+ */
+static void rbd_rq_fn(struct request_queue *q)
+{
+       struct rbd_device *rbd_dev = q->queuedata;
+       struct request *rq;
+       struct bio_pair *bp = NULL;
+
+       rq = blk_fetch_request(q);
+
+       while (1) {
+               struct bio *bio;
+               struct bio *rq_bio, *next_bio = NULL;
+               bool do_write;
+               int size, op_size = 0;
+               u64 ofs;
+
+               /* peek at request from block layer */
+               if (!rq)
+                       break;
+
+               dout("fetched request\n");
+
+               /* filter out block requests we don't understand */
+               if ((rq->cmd_type != REQ_TYPE_FS)) {
+                       __blk_end_request_all(rq, 0);
+                       goto next;
+               }
+
+               /* deduce our operation (read, write) */
+               do_write = (rq_data_dir(rq) == WRITE);
+
+               size = blk_rq_bytes(rq);
+               ofs = blk_rq_pos(rq) * 512ULL;
+               rq_bio = rq->bio;
+               if (do_write && rbd_dev->read_only) {
+                       __blk_end_request_all(rq, -EROFS);
+                       goto next;
+               }
+
+               spin_unlock_irq(q->queue_lock);
+
+               dout("%s 0x%x bytes at 0x%llx\n",
+                    do_write ? "write" : "read",
+                    size, blk_rq_pos(rq) * 512ULL);
+
+               do {
+                       /* a bio clone to be passed down to OSD req */
+                       dout("rq->bio->bi_vcnt=%d\n", rq->bio->bi_vcnt);
+                       op_size = rbd_get_segment(&rbd_dev->header,
+                                                 rbd_dev->header.block_name,
+                                                 ofs, size,
+                                                 NULL, NULL);
+                       bio = bio_chain_clone(&rq_bio, &next_bio, &bp,
+                                             op_size, GFP_ATOMIC);
+                       if (!bio) {
+                               spin_lock_irq(q->queue_lock);
+                               __blk_end_request_all(rq, -ENOMEM);
+                               goto next;
+                       }
+
+                       /* init OSD command: write or read */
+                       if (do_write)
+                               rbd_req_write(rq, rbd_dev,
+                                             rbd_dev->header.snapc,
+                                             ofs,
+                                             op_size, bio);
+                       else
+                               rbd_req_read(rq, rbd_dev,
+                                            cur_snap_id(rbd_dev),
+                                            ofs,
+                                            op_size, bio);
+
+                       size -= op_size;
+                       ofs += op_size;
+
+                       rq_bio = next_bio;
+               } while (size > 0);
+
+               if (bp)
+                       bio_pair_release(bp);
+
+               spin_lock_irq(q->queue_lock);
+next:
+               rq = blk_fetch_request(q);
+       }
+}
+
+/*
+ * a queue callback. Makes sure that we don't create a bio that spans across
+ * multiple osd objects. One exception would be with a single page bios,
+ * which we handle later at bio_chain_clone
+ */
+static int rbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd,
+                         struct bio_vec *bvec)
+{
+       struct rbd_device *rbd_dev = q->queuedata;
+       unsigned int chunk_sectors = 1 << (rbd_dev->header.obj_order - 9);
+       sector_t sector = bmd->bi_sector + get_start_sect(bmd->bi_bdev);
+       unsigned int bio_sectors = bmd->bi_size >> 9;
+       int max;
+
+       max =  (chunk_sectors - ((sector & (chunk_sectors - 1))
+                                + bio_sectors)) << 9;
+       if (max < 0)
+               max = 0; /* bio_add cannot handle a negative return */
+       if (max <= bvec->bv_len && bio_sectors == 0)
+               return bvec->bv_len;
+       return max;
+}
+
+static void rbd_free_disk(struct rbd_device *rbd_dev)
+{
+       struct gendisk *disk = rbd_dev->disk;
+
+       if (!disk)
+               return;
+
+       rbd_header_free(&rbd_dev->header);
+
+       if (disk->flags & GENHD_FL_UP)
+               del_gendisk(disk);
+       if (disk->queue)
+               blk_cleanup_queue(disk->queue);
+       put_disk(disk);
+}
+
+/*
+ * reload the ondisk the header 
+ */
+static int rbd_read_header(struct rbd_device *rbd_dev,
+                          struct rbd_image_header *header)
+{
+       ssize_t rc;
+       struct rbd_image_header_ondisk *dh;
+       int snap_count = 0;
+       u64 snap_names_len = 0;
+
+       while (1) {
+               int len = sizeof(*dh) +
+                         snap_count * sizeof(struct rbd_image_snap_ondisk) +
+                         snap_names_len;
+
+               rc = -ENOMEM;
+               dh = kmalloc(len, GFP_KERNEL);
+               if (!dh)
+                       return -ENOMEM;
+
+               rc = rbd_req_sync_read(rbd_dev,
+                                      NULL, CEPH_NOSNAP,
+                                      rbd_dev->obj_md_name,
+                                      0, len,
+                                      (char *)dh);
+               if (rc < 0)
+                       goto out_dh;
+
+               rc = rbd_header_from_disk(header, dh, snap_count, GFP_KERNEL);
+               if (rc < 0)
+                       goto out_dh;
+
+               if (snap_count != header->total_snaps) {
+                       snap_count = header->total_snaps;
+                       snap_names_len = header->snap_names_len;
+                       rbd_header_free(header);
+                       kfree(dh);
+                       continue;
+               }
+               break;
+       }
+
+out_dh:
+       kfree(dh);
+       return rc;
+}
+
+/*
+ * create a snapshot
+ */
+static int rbd_header_add_snap(struct rbd_device *dev,
+                              const char *snap_name,
+                              gfp_t gfp_flags)
+{
+       int name_len = strlen(snap_name);
+       u64 new_snapid;
+       int ret;
+       void *data, *data_start, *data_end;
+
+       /* we should create a snapshot only if we're pointing at the head */
+       if (dev->cur_snap)
+               return -EINVAL;
+
+       ret = ceph_monc_create_snapid(&dev->client->monc, dev->poolid,
+                                     &new_snapid);
+       dout("created snapid=%lld\n", new_snapid);
+       if (ret < 0)
+               return ret;
+
+       data = kmalloc(name_len + 16, gfp_flags);
+       if (!data)
+               return -ENOMEM;
+
+       data_start = data;
+       data_end = data + name_len + 16;
+
+       ceph_encode_string_safe(&data, data_end, snap_name, name_len, bad);
+       ceph_encode_64_safe(&data, data_end, new_snapid, bad);
+
+       ret = rbd_req_sync_exec(dev, dev->obj_md_name, "rbd", "snap_add",
+                               data_start, data - data_start);
+
+       kfree(data_start);
+
+       if (ret < 0)
+               return ret;
+
+       dev->header.snapc->seq =  new_snapid;
+
+       return 0;
+bad:
+       return -ERANGE;
+}
+
+/*
+ * only read the first part of the ondisk header, without the snaps info
+ */
+static int rbd_update_snaps(struct rbd_device *rbd_dev)
+{
+       int ret;
+       struct rbd_image_header h;
+       u64 snap_seq;
+
+       ret = rbd_read_header(rbd_dev, &h);
+       if (ret < 0)
+               return ret;
+
+       down_write(&rbd_dev->header.snap_rwsem);
+
+       snap_seq = rbd_dev->header.snapc->seq;
+
+       kfree(rbd_dev->header.snapc);
+       kfree(rbd_dev->header.snap_names);
+       kfree(rbd_dev->header.snap_sizes);
+
+       rbd_dev->header.total_snaps = h.total_snaps;
+       rbd_dev->header.snapc = h.snapc;
+       rbd_dev->header.snap_names = h.snap_names;
+       rbd_dev->header.snap_sizes = h.snap_sizes;
+       rbd_dev->header.snapc->seq = snap_seq;
+
+       up_write(&rbd_dev->header.snap_rwsem);
+
+       return 0;
+}
+
+static int rbd_init_disk(struct rbd_device *rbd_dev)
+{
+       struct gendisk *disk;
+       struct request_queue *q;
+       int rc;
+       u64 total_size = 0;
+
+       /* contact OSD, request size info about the object being mapped */
+       rc = rbd_read_header(rbd_dev, &rbd_dev->header);
+       if (rc)
+               return rc;
+
+       rc = rbd_header_set_snap(rbd_dev, rbd_dev->snap_name, &total_size);
+       if (rc)
+               return rc;
+
+       /* create gendisk info */
+       rc = -ENOMEM;
+       disk = alloc_disk(RBD_MINORS_PER_MAJOR);
+       if (!disk)
+               goto out;
+
+       sprintf(disk->disk_name, DRV_NAME "%d", rbd_dev->id);
+       disk->major = rbd_dev->major;
+       disk->first_minor = 0;
+       disk->fops = &rbd_bd_ops;
+       disk->private_data = rbd_dev;
+
+       /* init rq */
+       rc = -ENOMEM;
+       q = blk_init_queue(rbd_rq_fn, &rbd_dev->lock);
+       if (!q)
+               goto out_disk;
+       blk_queue_merge_bvec(q, rbd_merge_bvec);
+       disk->queue = q;
+
+       q->queuedata = rbd_dev;
+
+       rbd_dev->disk = disk;
+       rbd_dev->q = q;
+
+       /* finally, announce the disk to the world */
+       set_capacity(disk, total_size / 512ULL);
+       add_disk(disk);
+
+       pr_info("%s: added with size 0x%llx\n",
+               disk->disk_name, (unsigned long long)total_size);
+       return 0;
+
+out_disk:
+       put_disk(disk);
+out:
+       return rc;
+}
+
+/********************************************************************
+ * /sys/class/rbd/
+ *                   add       map rados objects to blkdev
+ *                   remove    unmap rados objects
+ *                   list      show mappings
+ *******************************************************************/
+
+static void class_rbd_release(struct class *cls)
+{
+       kfree(cls);
+}
+
+static ssize_t class_rbd_list(struct class *c,
+                             struct class_attribute *attr,
+                             char *data)
+{
+       int n = 0;
+       struct list_head *tmp;
+       int max = PAGE_SIZE;
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       n += snprintf(data, max,
+                     "#id\tmajor\tclient_name\tpool\tname\tsnap\tKB\n");
+
+       list_for_each(tmp, &rbd_dev_list) {
+               struct rbd_device *rbd_dev;
+
+               rbd_dev = list_entry(tmp, struct rbd_device, node);
+               n += snprintf(data+n, max-n,
+                             "%d\t%d\tclient%lld\t%s\t%s\t%s\t%lld\n",
+                             rbd_dev->id,
+                             rbd_dev->major,
+                             ceph_client_id(rbd_dev->client),
+                             rbd_dev->pool_name,
+                             rbd_dev->obj, rbd_dev->snap_name,
+                             rbd_dev->header.image_size >> 10);
+               if (n == max)
+                       break;
+       }
+
+       mutex_unlock(&ctl_mutex);
+       return n;
+}
+
+static ssize_t class_rbd_add(struct class *c,
+                            struct class_attribute *attr,
+                            const char *buf, size_t count)
+{
+       struct ceph_osd_client *osdc;
+       struct rbd_device *rbd_dev;
+       ssize_t rc = -ENOMEM;
+       int irc, new_id = 0;
+       struct list_head *tmp;
+       char *mon_dev_name;
+       char *options;
+
+       if (!try_module_get(THIS_MODULE))
+               return -ENODEV;
+
+       mon_dev_name = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL);
+       if (!mon_dev_name)
+               goto err_out_mod;
+
+       options = kmalloc(RBD_MAX_OPT_LEN, GFP_KERNEL);
+       if (!options)
+               goto err_mon_dev;
+
+       /* new rbd_device object */
+       rbd_dev = kzalloc(sizeof(*rbd_dev), GFP_KERNEL);
+       if (!rbd_dev)
+               goto err_out_opt;
+
+       /* static rbd_device initialization */
+       spin_lock_init(&rbd_dev->lock);
+       INIT_LIST_HEAD(&rbd_dev->node);
+
+       /* generate unique id: find highest unique id, add one */
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       list_for_each(tmp, &rbd_dev_list) {
+               struct rbd_device *rbd_dev;
+
+               rbd_dev = list_entry(tmp, struct rbd_device, node);
+               if (rbd_dev->id >= new_id)
+                       new_id = rbd_dev->id + 1;
+       }
+
+       rbd_dev->id = new_id;
+
+       /* add to global list */
+       list_add_tail(&rbd_dev->node, &rbd_dev_list);
+
+       /* parse add command */
+       if (sscanf(buf, "%" __stringify(RBD_MAX_OPT_LEN) "s "
+                  "%" __stringify(RBD_MAX_OPT_LEN) "s "
+                  "%" __stringify(RBD_MAX_POOL_NAME_LEN) "s "
+                  "%" __stringify(RBD_MAX_OBJ_NAME_LEN) "s"
+                  "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
+                  mon_dev_name, options, rbd_dev->pool_name,
+                  rbd_dev->obj, rbd_dev->snap_name) < 4) {
+               rc = -EINVAL;
+               goto err_out_slot;
+       }
+
+       if (rbd_dev->snap_name[0] == 0)
+               rbd_dev->snap_name[0] = '-';
+
+       rbd_dev->obj_len = strlen(rbd_dev->obj);
+       snprintf(rbd_dev->obj_md_name, sizeof(rbd_dev->obj_md_name), "%s%s",
+                rbd_dev->obj, RBD_SUFFIX);
+
+       /* initialize rest of new object */
+       snprintf(rbd_dev->name, DEV_NAME_LEN, DRV_NAME "%d", rbd_dev->id);
+       rc = rbd_get_client(rbd_dev, mon_dev_name, options);
+       if (rc < 0)
+               goto err_out_slot;
+
+       mutex_unlock(&ctl_mutex);
+
+       /* pick the pool */
+       osdc = &rbd_dev->client->osdc;
+       rc = ceph_pg_poolid_by_name(osdc->osdmap, rbd_dev->pool_name);
+       if (rc < 0)
+               goto err_out_client;
+       rbd_dev->poolid = rc;
+
+       /* register our block device */
+       irc = register_blkdev(0, rbd_dev->name);
+       if (irc < 0) {
+               rc = irc;
+               goto err_out_client;
+       }
+       rbd_dev->major = irc;
+
+       /* set up and announce blkdev mapping */
+       rc = rbd_init_disk(rbd_dev);
+       if (rc)
+               goto err_out_blkdev;
+
+       return count;
+
+err_out_blkdev:
+       unregister_blkdev(rbd_dev->major, rbd_dev->name);
+err_out_client:
+       rbd_put_client(rbd_dev);
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+err_out_slot:
+       list_del_init(&rbd_dev->node);
+       mutex_unlock(&ctl_mutex);
+
+       kfree(rbd_dev);
+err_out_opt:
+       kfree(options);
+err_mon_dev:
+       kfree(mon_dev_name);
+err_out_mod:
+       dout("Error adding device %s\n", buf);
+       module_put(THIS_MODULE);
+       return rc;
+}
+
+static struct rbd_device *__rbd_get_dev(unsigned long id)
+{
+       struct list_head *tmp;
+       struct rbd_device *rbd_dev;
+
+       list_for_each(tmp, &rbd_dev_list) {
+               rbd_dev = list_entry(tmp, struct rbd_device, node);
+               if (rbd_dev->id == id)
+                       return rbd_dev;
+       }
+       return NULL;
+}
+
+static ssize_t class_rbd_remove(struct class *c,
+                               struct class_attribute *attr,
+                               const char *buf,
+                               size_t count)
+{
+       struct rbd_device *rbd_dev = NULL;
+       int target_id, rc;
+       unsigned long ul;
+
+       rc = strict_strtoul(buf, 10, &ul);
+       if (rc)
+               return rc;
+
+       /* convert to int; abort if we lost anything in the conversion */
+       target_id = (int) ul;
+       if (target_id != ul)
+               return -EINVAL;
+
+       /* remove object from list immediately */
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       rbd_dev = __rbd_get_dev(target_id);
+       if (rbd_dev)
+               list_del_init(&rbd_dev->node);
+
+       mutex_unlock(&ctl_mutex);
+
+       if (!rbd_dev)
+               return -ENOENT;
+
+       rbd_put_client(rbd_dev);
+
+       /* clean up and free blkdev */
+       rbd_free_disk(rbd_dev);
+       unregister_blkdev(rbd_dev->major, rbd_dev->name);
+       kfree(rbd_dev);
+
+       /* release module ref */
+       module_put(THIS_MODULE);
+
+       return count;
+}
+
+static ssize_t class_rbd_snaps_list(struct class *c,
+                             struct class_attribute *attr,
+                             char *data)
+{
+       struct rbd_device *rbd_dev = NULL;
+       struct list_head *tmp;
+       struct rbd_image_header *header;
+       int i, n = 0, max = PAGE_SIZE;
+       int ret;
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       n += snprintf(data, max, "#id\tsnap\tKB\n");
+
+       list_for_each(tmp, &rbd_dev_list) {
+               char *names, *p;
+               struct ceph_snap_context *snapc;
+
+               rbd_dev = list_entry(tmp, struct rbd_device, node);
+               header = &rbd_dev->header;
+
+               down_read(&header->snap_rwsem);
+
+               names = header->snap_names;
+               snapc = header->snapc;
+
+               n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n",
+                             rbd_dev->id, RBD_SNAP_HEAD_NAME,
+                             header->image_size >> 10,
+                             (!rbd_dev->cur_snap ? " (*)" : ""));
+               if (n == max)
+                       break;
+
+               p = names;
+               for (i = 0; i < header->total_snaps; i++, p += strlen(p) + 1) {
+                       n += snprintf(data + n, max - n, "%d\t%s\t%lld%s\n",
+                             rbd_dev->id, p, header->snap_sizes[i] >> 10,
+                             (rbd_dev->cur_snap &&
+                              (snap_index(header, i) == rbd_dev->cur_snap) ?
+                              " (*)" : ""));
+                       if (n == max)
+                               break;
+               }
+
+               up_read(&header->snap_rwsem);
+       }
+
+
+       ret = n;
+       mutex_unlock(&ctl_mutex);
+       return ret;
+}
+
+static ssize_t class_rbd_snaps_refresh(struct class *c,
+                               struct class_attribute *attr,
+                               const char *buf,
+                               size_t count)
+{
+       struct rbd_device *rbd_dev = NULL;
+       int target_id, rc;
+       unsigned long ul;
+       int ret = count;
+
+       rc = strict_strtoul(buf, 10, &ul);
+       if (rc)
+               return rc;
+
+       /* convert to int; abort if we lost anything in the conversion */
+       target_id = (int) ul;
+       if (target_id != ul)
+               return -EINVAL;
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       rbd_dev = __rbd_get_dev(target_id);
+       if (!rbd_dev) {
+               ret = -ENOENT;
+               goto done;
+       }
+
+       rc = rbd_update_snaps(rbd_dev);
+       if (rc < 0)
+               ret = rc;
+
+done:
+       mutex_unlock(&ctl_mutex);
+       return ret;
+}
+
+static ssize_t class_rbd_snap_create(struct class *c,
+                               struct class_attribute *attr,
+                               const char *buf,
+                               size_t count)
+{
+       struct rbd_device *rbd_dev = NULL;
+       int target_id, ret;
+       char *name;
+
+       name = kmalloc(RBD_MAX_SNAP_NAME_LEN + 1, GFP_KERNEL);
+       if (!name)
+               return -ENOMEM;
+
+       /* parse snaps add command */
+       if (sscanf(buf, "%d "
+                  "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
+                  &target_id,
+                  name) != 2) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       rbd_dev = __rbd_get_dev(target_id);
+       if (!rbd_dev) {
+               ret = -ENOENT;
+               goto done_unlock;
+       }
+
+       ret = rbd_header_add_snap(rbd_dev,
+                                 name, GFP_KERNEL);
+       if (ret < 0)
+               goto done_unlock;
+
+       ret = rbd_update_snaps(rbd_dev);
+       if (ret < 0)
+               goto done_unlock;
+
+       ret = count;
+done_unlock:
+       mutex_unlock(&ctl_mutex);
+done:
+       kfree(name);
+       return ret;
+}
+
+static ssize_t class_rbd_rollback(struct class *c,
+                               struct class_attribute *attr,
+                               const char *buf,
+                               size_t count)
+{
+       struct rbd_device *rbd_dev = NULL;
+       int target_id, ret;
+       u64 snapid;
+       char snap_name[RBD_MAX_SNAP_NAME_LEN];
+       u64 cur_ofs;
+       char *seg_name;
+
+       /* parse snaps add command */
+       if (sscanf(buf, "%d "
+                  "%" __stringify(RBD_MAX_SNAP_NAME_LEN) "s",
+                  &target_id,
+                  snap_name) != 2) {
+               return -EINVAL;
+       }
+
+       ret = -ENOMEM;
+       seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO);
+       if (!seg_name)
+               return ret;
+
+       mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
+
+       rbd_dev = __rbd_get_dev(target_id);
+       if (!rbd_dev) {
+               ret = -ENOENT;
+               goto done_unlock;
+       }
+
+       ret = snap_by_name(&rbd_dev->header, snap_name, &snapid, NULL);
+       if (ret < 0)
+               goto done_unlock;
+
+       dout("snapid=%lld\n", snapid);
+
+       cur_ofs = 0;
+       while (cur_ofs < rbd_dev->header.image_size) {
+               cur_ofs += rbd_get_segment(&rbd_dev->header,
+                                          rbd_dev->obj,
+                                          cur_ofs, (u64)-1,
+                                          seg_name, NULL);
+               dout("seg_name=%s\n", seg_name);
+
+               ret = rbd_req_sync_rollback_obj(rbd_dev, snapid, seg_name);
+               if (ret < 0)
+                       pr_warning("could not roll back obj %s err=%d\n",
+                                  seg_name, ret);
+       }
+
+       ret = rbd_update_snaps(rbd_dev);
+       if (ret < 0)
+               goto done_unlock;
+
+       ret = count;
+
+done_unlock:
+       mutex_unlock(&ctl_mutex);
+       kfree(seg_name);
+
+       return ret;
+}
+
+static struct class_attribute class_rbd_attrs[] = {
+       __ATTR(add,             0200, NULL, class_rbd_add),
+       __ATTR(remove,          0200, NULL, class_rbd_remove),
+       __ATTR(list,            0444, class_rbd_list, NULL),
+       __ATTR(snaps_refresh,   0200, NULL, class_rbd_snaps_refresh),
+       __ATTR(snap_create,     0200, NULL, class_rbd_snap_create),
+       __ATTR(snaps_list,      0444, class_rbd_snaps_list, NULL),
+       __ATTR(snap_rollback,   0200, NULL, class_rbd_rollback),
+       __ATTR_NULL
+};
+
+/*
+ * create control files in sysfs
+ * /sys/class/rbd/...
+ */
+static int rbd_sysfs_init(void)
+{
+       int ret = -ENOMEM;
+
+       class_rbd = kzalloc(sizeof(*class_rbd), GFP_KERNEL);
+       if (!class_rbd)
+               goto out;
+
+       class_rbd->name = DRV_NAME;
+       class_rbd->owner = THIS_MODULE;
+       class_rbd->class_release = class_rbd_release;
+       class_rbd->class_attrs = class_rbd_attrs;
+
+       ret = class_register(class_rbd);
+       if (ret)
+               goto out_class;
+       return 0;
+
+out_class:
+       kfree(class_rbd);
+       class_rbd = NULL;
+       pr_err(DRV_NAME ": failed to create class rbd\n");
+out:
+       return ret;
+}
+
+static void rbd_sysfs_cleanup(void)
+{
+       if (class_rbd)
+               class_destroy(class_rbd);
+       class_rbd = NULL;
+}
+
+int __init rbd_init(void)
+{
+       int rc;
+
+       rc = rbd_sysfs_init();
+       if (rc)
+               return rc;
+       spin_lock_init(&node_lock);
+       pr_info("loaded " DRV_NAME_LONG "\n");
+       return 0;
+}
+
+void __exit rbd_exit(void)
+{
+       rbd_sysfs_cleanup();
+}
+
+module_init(rbd_init);
+module_exit(rbd_exit);
+
+MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
+MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
+MODULE_DESCRIPTION("rados block device");
+
+/* following authorship retained from original osdblk.c */
+MODULE_AUTHOR("Jeff Garzik <jeff@garzik.org>");
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/block/rbd_types.h b/drivers/block/rbd_types.h
new file mode 100644 (file)
index 0000000..fc6c678
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2010 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#ifndef CEPH_RBD_TYPES_H
+#define CEPH_RBD_TYPES_H
+
+#include <linux/types.h>
+
+/*
+ * rbd image 'foo' consists of objects
+ *   foo.rbd      - image metadata
+ *   foo.00000000
+ *   foo.00000001
+ *   ...          - data
+ */
+
+#define RBD_SUFFIX             ".rbd"
+#define RBD_DIRECTORY           "rbd_directory"
+#define RBD_INFO                "rbd_info"
+
+#define RBD_DEFAULT_OBJ_ORDER  22   /* 4MB */
+#define RBD_MIN_OBJ_ORDER       16
+#define RBD_MAX_OBJ_ORDER       30
+
+#define RBD_MAX_OBJ_NAME_LEN   96
+#define RBD_MAX_SEG_NAME_LEN   128
+
+#define RBD_COMP_NONE          0
+#define RBD_CRYPT_NONE         0
+
+#define RBD_HEADER_TEXT                "<<< Rados Block Device Image >>>\n"
+#define RBD_HEADER_SIGNATURE   "RBD"
+#define RBD_HEADER_VERSION     "001.005"
+
+struct rbd_info {
+       __le64 max_id;
+} __attribute__ ((packed));
+
+struct rbd_image_snap_ondisk {
+       __le64 id;
+       __le64 image_size;
+} __attribute__((packed));
+
+struct rbd_image_header_ondisk {
+       char text[40];
+       char block_name[24];
+       char signature[4];
+       char version[8];
+       struct {
+               __u8 order;
+               __u8 crypt_type;
+               __u8 comp_type;
+               __u8 unused;
+       } __attribute__((packed)) options;
+       __le64 image_size;
+       __le64 snap_seq;
+       __le32 snap_count;
+       __le32 reserved;
+       __le64 snap_names_len;
+       struct rbd_image_snap_ondisk snaps[0];
+} __attribute__((packed));
+
+
+#endif
index 1101e251a629343b0715b4b02a9b664828e1ef3e..8320490226b78145f95c7e7801a15080419adc19 100644 (file)
@@ -2,7 +2,6 @@
 #include <linux/spinlock.h>
 #include <linux/slab.h>
 #include <linux/blkdev.h>
-#include <linux/smp_lock.h>
 #include <linux/hdreg.h>
 #include <linux/virtio.h>
 #include <linux/virtio_blk.h>
@@ -222,8 +221,8 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str)
        return err;
 }
 
-static int virtblk_locked_ioctl(struct block_device *bdev, fmode_t mode,
-                        unsigned cmd, unsigned long data)
+static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
+                            unsigned int cmd, unsigned long data)
 {
        struct gendisk *disk = bdev->bd_disk;
        struct virtio_blk *vblk = disk->private_data;
@@ -238,18 +237,6 @@ static int virtblk_locked_ioctl(struct block_device *bdev, fmode_t mode,
                              (void __user *)data);
 }
 
-static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
-                            unsigned int cmd, unsigned long param)
-{
-       int ret;
-
-       lock_kernel();
-       ret = virtblk_locked_ioctl(bdev, mode, cmd, param);
-       unlock_kernel();
-
-       return ret;
-}
-
 /* We provide getgeo only to please some old bootloader/partitioning tools */
 static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
 {
index d52e90a5a61750494a6c740e4dd4565fb00f788e..4104b7feae6741c585af6d87db7c1333478e6891 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/skbuff.h>
 #include <linux/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -865,8 +864,7 @@ static int bluecard_probe(struct pcmcia_device *link)
        info->p_dev = link;
        link->priv = info;
 
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
+       link->config_flags |= CONF_ENABLE_IRQ;
 
        return bluecard_config(link);
 }
@@ -886,7 +884,7 @@ static int bluecard_config(struct pcmcia_device *link)
        bluecard_info_t *info = link->priv;
        int i, n;
 
-       link->conf.ConfigIndex = 0x20;
+       link->config_index = 0x20;
 
        link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
        link->resource[0]->end = 64;
@@ -906,7 +904,7 @@ static int bluecard_config(struct pcmcia_device *link)
        if (i != 0)
                goto failed;
 
-       i = pcmcia_request_configuration(link, &link->conf);
+       i = pcmcia_enable_device(link);
        if (i != 0)
                goto failed;
 
@@ -942,9 +940,7 @@ MODULE_DEVICE_TABLE(pcmcia, bluecard_ids);
 
 static struct pcmcia_driver bluecard_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "bluecard_cs",
-       },
+       .name           = "bluecard_cs",
        .probe          = bluecard_probe,
        .remove         = bluecard_detach,
        .id_table       = bluecard_ids,
index 7ab8f29d5e0dcb8df750bab81fc0bcce4494b12e..0c8a655874914d0604784d09c32c3b1651de03f5 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/device.h>
 #include <linux/firmware.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -657,11 +656,8 @@ static int bt3c_probe(struct pcmcia_device *link)
        info->p_dev = link;
        link->priv = info;
 
-       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-       link->resource[0]->end = 8;
-
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
+               CONF_AUTO_SET_IO;
 
        return bt3c_config(link);
 }
@@ -675,43 +671,41 @@ static void bt3c_detach(struct pcmcia_device *link)
        kfree(info);
 }
 
-static int bt3c_check_config(struct pcmcia_device *p_dev,
-                            cistpl_cftable_entry_t *cf,
-                            cistpl_cftable_entry_t *dflt,
-                            unsigned int vcc,
-                            void *priv_data)
+static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data)
 {
-       unsigned long try = (unsigned long) priv_data;
+       int *try = priv_data;
 
-       p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+       if (try == 0)
+               p_dev->io_lines = 16;
 
-       if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-       if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
-           (cf->io.win[0].base != 0)) {
-               p_dev->resource[0]->start = cf->io.win[0].base;
-               if (!pcmcia_request_io(p_dev))
-                       return 0;
-       }
-       return -ENODEV;
+       if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0))
+               return -EINVAL;
+
+       p_dev->resource[0]->end = 8;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+       return pcmcia_request_io(p_dev);
 }
 
 static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
-                                     cistpl_cftable_entry_t *cf,
-                                     cistpl_cftable_entry_t *dflt,
-                                     unsigned int vcc,
                                      void *priv_data)
 {
        static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
        int j;
 
-       if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-               for (j = 0; j < 5; j++) {
-                       p_dev->resource[0]->start = base[j];
-                       p_dev->io_lines = base[j] ? 16 : 3;
-                       if (!pcmcia_request_io(p_dev))
-                               return 0;
-               }
+       if (p_dev->io_lines > 3)
+               return -ENODEV;
+
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[0]->end = 8;
+
+       for (j = 0; j < 5; j++) {
+               p_dev->resource[0]->start = base[j];
+               p_dev->io_lines = base[j] ? 16 : 3;
+               if (!pcmcia_request_io(p_dev))
+                       return 0;
        }
        return -ENODEV;
 }
@@ -742,7 +736,7 @@ found_port:
        if (i != 0)
                goto failed;
 
-       i = pcmcia_request_configuration(link, &link->conf);
+       i = pcmcia_enable_device(link);
        if (i != 0)
                goto failed;
 
@@ -775,9 +769,7 @@ MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);
 
 static struct pcmcia_driver bt3c_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "bt3c_cs",
-       },
+       .name           = "bt3c_cs",
        .probe          = bt3c_probe,
        .remove         = bt3c_detach,
        .id_table       = bt3c_ids,
index 1c4f5e863b032d21d8a765a4d3b97c1ca1bb73e4..f8a0708e23110446de1f8a4ccc5e344306b88820 100644 (file)
@@ -41,7 +41,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -586,11 +585,8 @@ static int btuart_probe(struct pcmcia_device *link)
        info->p_dev = link;
        link->priv = info;
 
-       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-       link->resource[0]->end = 8;
-
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
+               CONF_AUTO_SET_IO;
 
        return btuart_config(link);
 }
@@ -604,43 +600,41 @@ static void btuart_detach(struct pcmcia_device *link)
        kfree(info);
 }
 
-static int btuart_check_config(struct pcmcia_device *p_dev,
-                              cistpl_cftable_entry_t *cf,
-                              cistpl_cftable_entry_t *dflt,
-                              unsigned int vcc,
-                              void *priv_data)
+static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data)
 {
        int *try = priv_data;
 
-       p_dev->io_lines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+       if (try == 0)
+               p_dev->io_lines = 16;
 
-       if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-       if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
-           (cf->io.win[0].base != 0)) {
-               p_dev->resource[0]->start = cf->io.win[0].base;
-               if (!pcmcia_request_io(p_dev))
-                       return 0;
-       }
-       return -ENODEV;
+       if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0))
+               return -EINVAL;
+
+       p_dev->resource[0]->end = 8;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+       return pcmcia_request_io(p_dev);
 }
 
 static int btuart_check_config_notpicky(struct pcmcia_device *p_dev,
-                                       cistpl_cftable_entry_t *cf,
-                                       cistpl_cftable_entry_t *dflt,
-                                       unsigned int vcc,
                                        void *priv_data)
 {
        static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
        int j;
 
-       if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-               for (j = 0; j < 5; j++) {
-                       p_dev->resource[0]->start = base[j];
-                       p_dev->io_lines = base[j] ? 16 : 3;
-                       if (!pcmcia_request_io(p_dev))
-                               return 0;
-               }
+       if (p_dev->io_lines > 3)
+               return -ENODEV;
+
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[0]->end = 8;
+
+       for (j = 0; j < 5; j++) {
+               p_dev->resource[0]->start = base[j];
+               p_dev->io_lines = base[j] ? 16 : 3;
+               if (!pcmcia_request_io(p_dev))
+                       return 0;
        }
        return -ENODEV;
 }
@@ -671,7 +665,7 @@ found_port:
        if (i != 0)
                goto failed;
 
-       i = pcmcia_request_configuration(link, &link->conf);
+       i = pcmcia_enable_device(link);
        if (i != 0)
                goto failed;
 
@@ -703,9 +697,7 @@ MODULE_DEVICE_TABLE(pcmcia, btuart_ids);
 
 static struct pcmcia_driver btuart_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "btuart_cs",
-       },
+       .name           = "btuart_cs",
        .probe          = btuart_probe,
        .remove         = btuart_detach,
        .id_table       = btuart_ids,
index db7c8db695fc643cff089670b721ef801dd14090..26ee0cf88d20487c0c830b5dec0c753bbf11a3b8 100644 (file)
@@ -41,7 +41,6 @@
 #include <asm/system.h>
 #include <asm/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -572,11 +571,7 @@ static int dtl1_probe(struct pcmcia_device *link)
        info->p_dev = link;
        link->priv = info;
 
-       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-       link->resource[0]->end = 8;
-
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 
        return dtl1_config(link);
 }
@@ -591,18 +586,14 @@ static void dtl1_detach(struct pcmcia_device *link)
        kfree(info);
 }
 
-static int dtl1_confcheck(struct pcmcia_device *p_dev,
-                         cistpl_cftable_entry_t *cf,
-                         cistpl_cftable_entry_t *dflt,
-                         unsigned int vcc,
-                         void *priv_data)
+static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if ((cf->io.nwin != 1) || (cf->io.win[0].len <= 8))
+       if ((p_dev->resource[1]->end) || (p_dev->resource[1]->end < 8))
                return -ENODEV;
 
-       p_dev->resource[0]->start = cf->io.win[0].base;
-       p_dev->resource[0]->end = cf->io.win[0].len;    /*yo */
-       p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
        return pcmcia_request_io(p_dev);
 }
 
@@ -620,7 +611,7 @@ static int dtl1_config(struct pcmcia_device *link)
        if (i != 0)
                goto failed;
 
-       i = pcmcia_request_configuration(link, &link->conf);
+       i = pcmcia_enable_device(link);
        if (i != 0)
                goto failed;
 
@@ -656,9 +647,7 @@ MODULE_DEVICE_TABLE(pcmcia, dtl1_ids);
 
 static struct pcmcia_driver dtl1_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "dtl1_cs",
-       },
+       .name           = "dtl1_cs",
        .probe          = dtl1_probe,
        .remove         = dtl1_detach,
        .id_table       = dtl1_ids,
index 4b66c69eaf5790d104cf653dd48a14e5eb2940bf..5ddf67e76f8bbccf3242da3bc2e2373d2255648c 100644 (file)
@@ -57,7 +57,7 @@ config AGP_AMD
 
 config AGP_AMD64
        tristate "AMD Opteron/Athlon64 on-CPU GART support"
-       depends on AGP && X86 && K8_NB
+       depends on AGP && X86 && AMD_NB
        help
          This option gives you AGP support for the GLX component of
          X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
index 70312da4c968f9e4af7c39e9a5a649b4952f8bd3..42396df555567660d597ac524631e9020edfbea3 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/mmzone.h>
 #include <asm/page.h>          /* PAGE_SIZE */
 #include <asm/e820.h>
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 #include <asm/gart.h>
 #include "agp.h"
 
@@ -124,7 +124,7 @@ static int amd64_fetch_size(void)
        u32 temp;
        struct aper_size_info_32 *values;
 
-       dev = k8_northbridges[0];
+       dev = k8_northbridges.nb_misc[0];
        if (dev==NULL)
                return 0;
 
@@ -181,10 +181,14 @@ static int amd_8151_configure(void)
        unsigned long gatt_bus = virt_to_phys(agp_bridge->gatt_table_real);
        int i;
 
+       if (!k8_northbridges.gart_supported)
+               return 0;
+
        /* Configure AGP regs in each x86-64 host bridge. */
-        for (i = 0; i < num_k8_northbridges; i++) {
+       for (i = 0; i < k8_northbridges.num; i++) {
                agp_bridge->gart_bus_addr =
-                               amd64_configure(k8_northbridges[i], gatt_bus);
+                               amd64_configure(k8_northbridges.nb_misc[i],
+                                               gatt_bus);
        }
        k8_flush_garts();
        return 0;
@@ -195,11 +199,15 @@ static void amd64_cleanup(void)
 {
        u32 tmp;
        int i;
-        for (i = 0; i < num_k8_northbridges; i++) {
-               struct pci_dev *dev = k8_northbridges[i];
+
+       if (!k8_northbridges.gart_supported)
+               return;
+
+       for (i = 0; i < k8_northbridges.num; i++) {
+               struct pci_dev *dev = k8_northbridges.nb_misc[i];
                /* disable gart translation */
                pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &tmp);
-               tmp &= ~AMD64_GARTEN;
+               tmp &= ~GARTEN;
                pci_write_config_dword(dev, AMD64_GARTAPERTURECTL, tmp);
        }
 }
@@ -313,22 +321,25 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
        if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order))
                return -1;
 
-       pci_write_config_dword(nb, AMD64_GARTAPERTURECTL, order << 1);
+       gart_set_size_and_enable(nb, order);
        pci_write_config_dword(nb, AMD64_GARTAPERTUREBASE, aper >> 25);
 
        return 0;
 }
 
-static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr)
+static __devinit int cache_nbs(struct pci_dev *pdev, u32 cap_ptr)
 {
        int i;
 
        if (cache_k8_northbridges() < 0)
                return -ENODEV;
 
+       if (!k8_northbridges.gart_supported)
+               return -ENODEV;
+
        i = 0;
-       for (i = 0; i < num_k8_northbridges; i++) {
-               struct pci_dev *dev = k8_northbridges[i];
+       for (i = 0; i < k8_northbridges.num; i++) {
+               struct pci_dev *dev = k8_northbridges.nb_misc[i];
                if (fix_northbridge(dev, pdev, cap_ptr) < 0) {
                        dev_err(&dev->dev, "no usable aperture found\n");
 #ifdef __x86_64__
@@ -405,7 +416,8 @@ static int __devinit uli_agp_init(struct pci_dev *pdev)
        }
 
        /* shadow x86-64 registers into ULi registers */
-       pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &httfea);
+       pci_read_config_dword (k8_northbridges.nb_misc[0], AMD64_GARTAPERTUREBASE,
+                              &httfea);
 
        /* if x86-64 aperture base is beyond 4G, exit here */
        if ((httfea & 0x7fff) >> (32 - 25)) {
@@ -472,7 +484,8 @@ static int nforce3_agp_init(struct pci_dev *pdev)
        pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp);
 
        /* shadow x86-64 registers into NVIDIA registers */
-       pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &apbase);
+       pci_read_config_dword (k8_northbridges.nb_misc[0], AMD64_GARTAPERTUREBASE,
+                              &apbase);
 
        /* if x86-64 aperture base is beyond 4G, exit here */
        if ( (apbase & 0x7fff) >> (32 - 25) ) {
index d2abf51439836383fd9b03612a44bdf1779448fa..64255cef8a7db93f780c700d712c5fa4b7fe5907 100644 (file)
@@ -984,7 +984,9 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge)
 
        bridge->driver->cache_flush();
 #ifdef CONFIG_X86
-       set_memory_uc((unsigned long)table, 1 << page_order);
+       if (set_memory_uc((unsigned long)table, 1 << page_order))
+               printk(KERN_WARNING "Could not set GATT table memory to UC!");
+
        bridge->gatt_table = (void *)table;
 #else
        bridge->gatt_table = ioremap_nocache(virt_to_phys(table),
index ec73d9f6d9ed92c9fa527718ff44871bd7d64669..c7b482d15e2adb0416785fc837cc9c18b9884667 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/uaccess.h>
 #include <linux/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
@@ -55,8 +54,6 @@
                           __func__ , ## args);         \
        } while (0)
 
-static char *version = "cm4000_cs.c v2.4.0gm6 - All bugs added by Harald Welte";
-
 #define        T_1SEC          (HZ)
 #define        T_10MSEC        msecs_to_jiffies(10)
 #define        T_20MSEC        msecs_to_jiffies(20)
@@ -1742,20 +1739,8 @@ static void cmm_cm4000_release(struct pcmcia_device * link)
 
 /*==== Interface to PCMCIA Layer =======================================*/
 
-static int cm4000_config_check(struct pcmcia_device *p_dev,
-                              cistpl_cftable_entry_t *cfg,
-                              cistpl_cftable_entry_t *dflt,
-                              unsigned int vcc,
-                              void *priv_data)
+static int cm4000_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (!cfg->io.nwin)
-               return -ENODEV;
-
-       p_dev->resource[0]->start = cfg->io.win[0].base;
-       p_dev->resource[0]->end = cfg->io.win[0].len;
-       p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags);
-       p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
-
        return pcmcia_request_io(p_dev);
 }
 
@@ -1763,13 +1748,13 @@ static int cm4000_config(struct pcmcia_device * link, int devno)
 {
        struct cm4000_dev *dev;
 
+       link->config_flags |= CONF_AUTO_SET_IO;
+
        /* read the config-tuples */
        if (pcmcia_loop_config(link, cm4000_config_check, NULL))
                goto cs_release;
 
-       link->conf.IntType = 00000002;
-
-       if (pcmcia_request_configuration(link, &link->conf))
+       if (pcmcia_enable_device(link))
                goto cs_release;
 
        dev = link->priv;
@@ -1829,7 +1814,6 @@ static int cm4000_probe(struct pcmcia_device *link)
 
        dev->p_dev = link;
        link->priv = dev;
-       link->conf.IntType = INT_MEMORY_AND_IO;
        dev_table[i] = link;
 
        init_waitqueue_head(&dev->devq);
@@ -1891,9 +1875,7 @@ MODULE_DEVICE_TABLE(pcmcia, cm4000_ids);
 
 static struct pcmcia_driver cm4000_driver = {
        .owner    = THIS_MODULE,
-       .drv      = {
-               .name = "cm4000_cs",
-               },
+       .name     = "cm4000_cs",
        .probe    = cm4000_probe,
        .remove   = cm4000_detach,
        .suspend  = cm4000_suspend,
@@ -1905,8 +1887,6 @@ static int __init cmm_init(void)
 {
        int rc;
 
-       printk(KERN_INFO "%s\n", version);
-
        cmm_class = class_create(THIS_MODULE, "cardman_4000");
        if (IS_ERR(cmm_class))
                return PTR_ERR(cmm_class);
@@ -1931,7 +1911,6 @@ static int __init cmm_init(void)
 
 static void __exit cmm_exit(void)
 {
-       printk(KERN_INFO MODULE_NAME ": unloading\n");
        pcmcia_unregister_driver(&cm4000_driver);
        unregister_chrdev(major, DEVICE_NAME);
        class_destroy(cmm_class);
index 815cde1d0570e86d4ba0e8970ef60248997a3302..bf2f046fc2c122d6464dcd4c407433be9c83aa20 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
@@ -49,9 +48,6 @@
                           __func__ , ## args);         \
        } while (0)
 
-static char *version =
-"OMNIKEY CardMan 4040 v1.1.0gm5 - All bugs added by Harald Welte";
-
 #define        CCID_DRIVER_BULK_DEFAULT_TIMEOUT        (150*HZ)
 #define        CCID_DRIVER_ASYNC_POWERUP_TIMEOUT       (35*HZ)
 #define        CCID_DRIVER_MINIMUM_TIMEOUT             (3*HZ)
@@ -516,26 +512,9 @@ static void cm4040_reader_release(struct pcmcia_device *link)
        return;
 }
 
-static int cm4040_config_check(struct pcmcia_device *p_dev,
-                              cistpl_cftable_entry_t *cfg,
-                              cistpl_cftable_entry_t *dflt,
-                              unsigned int vcc,
-                              void *priv_data)
+static int cm4040_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       int rc;
-       if (!cfg->io.nwin)
-               return -ENODEV;
-
-       /* Get the IOaddr */
-       p_dev->resource[0]->start = cfg->io.win[0].base;
-       p_dev->resource[0]->end = cfg->io.win[0].len;
-       p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags);
-       p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
-       rc = pcmcia_request_io(p_dev);
-
-       dev_printk(KERN_INFO, &p_dev->dev,
-                  "pcmcia_request_io returned 0x%x\n", rc);
-       return rc;
+       return pcmcia_request_io(p_dev);
 }
 
 
@@ -544,15 +523,15 @@ static int reader_config(struct pcmcia_device *link, int devno)
        struct reader_dev *dev;
        int fail_rc;
 
+       link->config_flags |= CONF_AUTO_SET_IO;
+
        if (pcmcia_loop_config(link, cm4040_config_check, NULL))
                goto cs_release;
 
-       link->conf.IntType = 00000002;
-
-       fail_rc = pcmcia_request_configuration(link, &link->conf);
+       fail_rc = pcmcia_enable_device(link);
        if (fail_rc != 0) {
                dev_printk(KERN_INFO, &link->dev,
-                          "pcmcia_request_configuration failed 0x%x\n",
+                          "pcmcia_enable_device failed 0x%x\n",
                           fail_rc);
                goto cs_release;
        }
@@ -599,7 +578,6 @@ static int reader_probe(struct pcmcia_device *link)
        link->priv = dev;
        dev->p_dev = link;
 
-       link->conf.IntType = INT_MEMORY_AND_IO;
        dev_table[i] = link;
 
        init_waitqueue_head(&dev->devq);
@@ -662,9 +640,7 @@ MODULE_DEVICE_TABLE(pcmcia, cm4040_ids);
 
 static struct pcmcia_driver reader_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "cm4040_cs",
-       },
+       .name           = "cm4040_cs",
        .probe          = reader_probe,
        .remove         = reader_detach,
        .id_table       = cm4040_ids,
@@ -674,7 +650,6 @@ static int __init cm4040_init(void)
 {
        int rc;
 
-       printk(KERN_INFO "%s\n", version);
        cmx_class = class_create(THIS_MODULE, "cardman_4040");
        if (IS_ERR(cmx_class))
                return PTR_ERR(cmx_class);
@@ -699,7 +674,6 @@ static int __init cm4040_init(void)
 
 static void __exit cm4040_exit(void)
 {
-       printk(KERN_INFO MODULE_NAME ": unloading\n");
        pcmcia_unregister_driver(&reader_driver);
        unregister_chrdev(major, DEVICE_NAME);
        class_destroy(cmx_class);
index 67bdb05798b1943c8c2242f85494f70c6e2c7e3c..94b8eb4d691d6b95fd0f32ffeea780dc28a6121c 100644 (file)
@@ -32,7 +32,6 @@
 #include <pcmcia/device_id.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/ds.h>
-#include <pcmcia/cs.h>
 
 static struct pcmcia_device_id ipw_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x02f2, 0x0100),
@@ -76,23 +75,18 @@ static void signalled_reboot_callback(void *callback_data)
        schedule_work(&ipw->work_reboot);
 }
 
-static int ipwireless_probe(struct pcmcia_device *p_dev,
-                           cistpl_cftable_entry_t *cfg,
-                           cistpl_cftable_entry_t *dflt,
-                           unsigned int vcc,
-                           void *priv_data)
+static int ipwireless_probe(struct pcmcia_device *p_dev, void *priv_data)
 {
        struct ipw_dev *ipw = priv_data;
        struct resource *io_resource;
        int ret;
 
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
        p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-       p_dev->resource[0]->start = cfg->io.win[0].base;
-       p_dev->resource[0]->end = cfg->io.win[0].len;
 
        /* 0x40 causes it to generate level mode interrupts. */
        /* 0x04 enables IREQ pin. */
-       p_dev->conf.ConfigIndex = cfg->index | 0x44;
+       p_dev->config_index |= 0x44;
        p_dev->io_lines = 16;
        ret = pcmcia_request_io(p_dev);
        if (ret)
@@ -102,65 +96,49 @@ static int ipwireless_probe(struct pcmcia_device *p_dev,
                                resource_size(p_dev->resource[0]),
                                IPWIRELESS_PCCARD_NAME);
 
-       if (cfg->mem.nwin == 0)
-               return 0;
-
-       ipw->request_common_memory.Attributes =
+       p_dev->resource[2]->flags |=
                WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE;
-       ipw->request_common_memory.Base = cfg->mem.win[0].host_addr;
-       ipw->request_common_memory.Size = cfg->mem.win[0].len;
-       if (ipw->request_common_memory.Size < 0x1000)
-               ipw->request_common_memory.Size = 0x1000;
-       ipw->request_common_memory.AccessSpeed = 0;
-
-       ret = pcmcia_request_window(p_dev, &ipw->request_common_memory,
-                               &ipw->handle_common_memory);
 
+       ret = pcmcia_request_window(p_dev, p_dev->resource[2], 0);
        if (ret != 0)
                goto exit1;
 
-       ret = pcmcia_map_mem_page(p_dev, ipw->handle_common_memory,
-                               cfg->mem.win[0].card_addr);
-
+       ret = pcmcia_map_mem_page(p_dev, p_dev->resource[2], p_dev->card_addr);
        if (ret != 0)
                goto exit2;
 
-       ipw->is_v2_card = cfg->mem.win[0].len == 0x100;
+       ipw->is_v2_card = resource_size(p_dev->resource[2]) == 0x100;
 
-       ipw->common_memory = ioremap(ipw->request_common_memory.Base,
-                               ipw->request_common_memory.Size);
-       request_mem_region(ipw->request_common_memory.Base,
-                       ipw->request_common_memory.Size,
+       ipw->attr_memory = ioremap(p_dev->resource[2]->start,
+                               resource_size(p_dev->resource[2]));
+       request_mem_region(p_dev->resource[2]->start,
+                       resource_size(p_dev->resource[2]),
                        IPWIRELESS_PCCARD_NAME);
 
-       ipw->request_attr_memory.Attributes =
-               WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM | WIN_ENABLE;
-       ipw->request_attr_memory.Base = 0;
-       ipw->request_attr_memory.Size = 0;      /* this used to be 0x1000 */
-       ipw->request_attr_memory.AccessSpeed = 0;
-
-       ret = pcmcia_request_window(p_dev, &ipw->request_attr_memory,
-                               &ipw->handle_attr_memory);
-
+       p_dev->resource[3]->flags |= WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_AM |
+                                       WIN_ENABLE;
+       p_dev->resource[3]->end = 0; /* this used to be 0x1000 */
+       ret = pcmcia_request_window(p_dev, p_dev->resource[3], 0);
        if (ret != 0)
                goto exit2;
 
-       ret = pcmcia_map_mem_page(p_dev, ipw->handle_attr_memory, 0);
+       ret = pcmcia_map_mem_page(p_dev, p_dev->resource[3], 0);
        if (ret != 0)
                goto exit3;
 
-       ipw->attr_memory = ioremap(ipw->request_attr_memory.Base,
-                               ipw->request_attr_memory.Size);
-       request_mem_region(ipw->request_attr_memory.Base,
-                       ipw->request_attr_memory.Size, IPWIRELESS_PCCARD_NAME);
+       ipw->attr_memory = ioremap(p_dev->resource[3]->start,
+                               resource_size(p_dev->resource[3]));
+       request_mem_region(p_dev->resource[3]->start,
+                       resource_size(p_dev->resource[3]),
+                       IPWIRELESS_PCCARD_NAME);
 
        return 0;
 
 exit3:
 exit2:
        if (ipw->common_memory) {
-               release_mem_region(ipw->request_common_memory.Base,
-                               ipw->request_common_memory.Size);
+               release_mem_region(p_dev->resource[2]->start,
+                               resource_size(p_dev->resource[2]));
                iounmap(ipw->common_memory);
        }
 exit1:
@@ -175,14 +153,13 @@ static int config_ipwireless(struct ipw_dev *ipw)
        int ret = 0;
 
        ipw->is_v2_card = 0;
+       link->config_flags |= CONF_AUTO_SET_IO | CONF_AUTO_SET_IOMEM |
+               CONF_ENABLE_IRQ;
 
        ret = pcmcia_loop_config(link, ipwireless_probe, ipw);
        if (ret != 0)
                return ret;
 
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        INIT_WORK(&ipw->work_reboot, signalled_reboot_work);
 
        ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start,
@@ -201,13 +178,9 @@ static int config_ipwireless(struct ipw_dev *ipw)
                        (unsigned int) link->irq);
        if (ipw->attr_memory && ipw->common_memory)
                printk(KERN_INFO IPWIRELESS_PCCARD_NAME
-                       ": attr memory 0x%08lx-0x%08lx, common memory 0x%08lx-0x%08lx\n",
-                       ipw->request_attr_memory.Base,
-                       ipw->request_attr_memory.Base
-                       + ipw->request_attr_memory.Size - 1,
-                       ipw->request_common_memory.Base,
-                       ipw->request_common_memory.Base
-                       + ipw->request_common_memory.Size - 1);
+                       ": attr memory %pR, common memory %pR\n",
+                       link->resource[3],
+                       link->resource[2]);
 
        ipw->network = ipwireless_network_create(ipw->hardware);
        if (!ipw->network)
@@ -223,25 +196,23 @@ static int config_ipwireless(struct ipw_dev *ipw)
         * Do the RequestConfiguration last, because it enables interrupts.
         * Then we don't get any interrupts before we're ready for them.
         */
-       ret = pcmcia_request_configuration(link, &link->conf);
-
+       ret = pcmcia_enable_device(link);
        if (ret != 0)
                goto exit;
 
        return 0;
 
 exit:
-       if (ipw->attr_memory) {
-               release_mem_region(ipw->request_attr_memory.Base,
-                               ipw->request_attr_memory.Size);
-               iounmap(ipw->attr_memory);
-
-       }
        if (ipw->common_memory) {
-               release_mem_region(ipw->request_common_memory.Base,
-                               ipw->request_common_memory.Size);
+               release_mem_region(link->resource[2]->start,
+                               resource_size(link->resource[2]));
                iounmap(ipw->common_memory);
        }
+       if (ipw->attr_memory) {
+               release_mem_region(link->resource[3]->start,
+                               resource_size(link->resource[3]));
+               iounmap(ipw->attr_memory);
+       }
        pcmcia_disable_device(link);
        return -1;
 }
@@ -249,13 +220,13 @@ exit:
 static void release_ipwireless(struct ipw_dev *ipw)
 {
        if (ipw->common_memory) {
-               release_mem_region(ipw->request_common_memory.Base,
-                               ipw->request_common_memory.Size);
+               release_mem_region(ipw->link->resource[2]->start,
+                               resource_size(ipw->link->resource[2]));
                iounmap(ipw->common_memory);
        }
        if (ipw->attr_memory) {
-               release_mem_region(ipw->request_attr_memory.Base,
-                               ipw->request_attr_memory.Size);
+               release_mem_region(ipw->link->resource[3]->start,
+                               resource_size(ipw->link->resource[3]));
                iounmap(ipw->attr_memory);
        }
        pcmcia_disable_device(ipw->link);
@@ -324,7 +295,7 @@ static struct pcmcia_driver me = {
        .owner          = THIS_MODULE,
        .probe          = ipwireless_attach,
        .remove         = ipwireless_detach,
-       .drv = { .name  = IPWIRELESS_PCCARD_NAME },
+       .name           = IPWIRELESS_PCCARD_NAME,
        .id_table       = ipw_ids
 };
 
@@ -336,9 +307,6 @@ static int __init init_ipwireless(void)
 {
        int ret;
 
-       printk(KERN_INFO IPWIRELESS_PCCARD_NAME " "
-              IPWIRELESS_PCMCIA_VERSION " by " IPWIRELESS_PCMCIA_AUTHOR "\n");
-
        ret = ipwireless_tty_init();
        if (ret != 0)
                return ret;
@@ -355,9 +323,6 @@ static int __init init_ipwireless(void)
  */
 static void __exit exit_ipwireless(void)
 {
-       printk(KERN_INFO IPWIRELESS_PCCARD_NAME " "
-                       IPWIRELESS_PCMCIA_VERSION " removed\n");
-
        pcmcia_unregister_driver(&me);
        ipwireless_tty_release();
 }
index c207be87b597fe3cecfec61da71d8fdf3386b36f..f2cbb116bccb51d2c3c548cf5053b782fb84f9de 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/sched.h>
 #include <linux/types.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -45,13 +44,9 @@ struct ipw_dev {
        struct pcmcia_device *link;
        int is_v2_card;
 
-       window_handle_t handle_attr_memory;
        void __iomem *attr_memory;
-       win_req_t request_attr_memory;
 
-       window_handle_t handle_common_memory;
        void __iomem *common_memory;
-       win_req_t request_common_memory;
 
        /* Reference to attribute memory, containing CIS data */
        void *attribute_memory;
index 3e163d4cab15b034d14153d5dcb2d1f6bdeae36e..747b2d63786093058213b5aea75724a9cc68960e 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
index 9ecd6bef5d3b5457ec5bcc6566db7621c1d791f3..be18100576075a7b476c5be534640349679ff280 100644 (file)
@@ -70,7 +70,6 @@
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -550,9 +549,6 @@ static int mgslpc_probe(struct pcmcia_device *link)
 
     /* Initialize the struct pcmcia_device structure */
 
-    link->conf.Attributes = 0;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-
     ret = mgslpc_config(link);
     if (ret)
            return ret;
@@ -565,20 +561,8 @@ static int mgslpc_probe(struct pcmcia_device *link)
 /* Card has been inserted.
  */
 
-static int mgslpc_ioprobe(struct pcmcia_device *p_dev,
-                         cistpl_cftable_entry_t *cfg,
-                         cistpl_cftable_entry_t *dflt,
-                         unsigned int vcc,
-                         void *priv_data)
+static int mgslpc_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (!cfg->io.nwin)
-               return -ENODEV;
-
-       p_dev->resource[0]->start = cfg->io.win[0].base;
-       p_dev->resource[0]->end = cfg->io.win[0].len;
-       p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags);
-       p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
-
        return pcmcia_request_io(p_dev);
 }
 
@@ -590,32 +574,24 @@ static int mgslpc_config(struct pcmcia_device *link)
     if (debug_level >= DEBUG_LEVEL_INFO)
            printk("mgslpc_config(0x%p)\n", link);
 
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+
     ret = pcmcia_loop_config(link, mgslpc_ioprobe, NULL);
     if (ret != 0)
            goto failed;
 
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.ConfigIndex = 8;
-    link->conf.Present = PRESENT_OPTION;
+    link->config_index = 8;
+    link->config_regs = PRESENT_OPTION;
 
     ret = pcmcia_request_irq(link, mgslpc_isr);
     if (ret)
            goto failed;
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
 
     info->io_base = link->resource[0]->start;
     info->irq_level = link->irq;
-
-    dev_info(&link->dev, "index 0x%02x:",
-           link->conf.ConfigIndex);
-    if (link->conf.Attributes & CONF_ENABLE_IRQ)
-           printk(", irq %d", link->irq);
-    if (link->resource[0])
-           printk(", io %pR", link->resource[0]);
-    printk("\n");
     return 0;
 
 failed:
@@ -2797,9 +2773,7 @@ MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids);
 
 static struct pcmcia_driver mgslpc_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "synclink_cs",
-       },
+       .name           = "synclink_cs",
        .probe          = mgslpc_probe,
        .remove         = mgslpc_detach,
        .id_table       = mgslpc_ids,
@@ -2835,8 +2809,6 @@ static void synclink_cs_cleanup(void)
 {
        int rc;
 
-       printk("Unloading %s: version %s\n", driver_name, driver_version);
-
        while(mgslpc_device_list)
                mgslpc_remove_device(mgslpc_device_list);
 
@@ -2859,8 +2831,6 @@ static int __init synclink_cs_init(void)
            BREAKPOINT();
     }
 
-    printk("%s %s\n", driver_name, driver_version);
-
     if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0)
            return rc;
 
@@ -4127,6 +4097,8 @@ static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        if (cmd != SIOCWANDEV)
                return hdlc_ioctl(dev, ifr, cmd);
 
+       memset(&new_line, 0, size);
+
        switch(ifr->ifr_settings.type) {
        case IF_GET_IFACE: /* return current sync_serial_settings */
 
index 05ad4a17a28f238ecc197e67051f60a50faad769..7c4133582dbae484f449d49f97b2ee0f179a9891 100644 (file)
@@ -47,6 +47,16 @@ enum tpm_duration {
 #define TPM_MAX_PROTECTED_ORDINAL 12
 #define TPM_PROTECTED_ORDINAL_MASK 0xFF
 
+/*
+ * Bug workaround - some TPM's don't flush the most
+ * recently changed pcr on suspend, so force the flush
+ * with an extend to the selected _unused_ non-volatile pcr.
+ */
+static int tpm_suspend_pcr;
+module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
+MODULE_PARM_DESC(suspend_pcr,
+                "PCR to use for dummy writes to faciltate flush on suspend.");
+
 static LIST_HEAD(tpm_chip_list);
 static DEFINE_SPINLOCK(driver_lock);
 static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
@@ -1077,18 +1087,6 @@ static struct tpm_input_header savestate_header = {
        .ordinal = TPM_ORD_SAVESTATE
 };
 
-/* Bug workaround - some TPM's don't flush the most
- * recently changed pcr on suspend, so force the flush
- * with an extend to the selected _unused_ non-volatile pcr.
- */
-static int tpm_suspend_pcr;
-static int __init tpm_suspend_setup(char *str)
-{
-       get_option(&str, &tpm_suspend_pcr);
-       return 1;
-}
-__setup("tpm_suspend_pcr=", tpm_suspend_setup);
-
 /*
  * We are about to suspend. Save the TPM state
  * so that it can be restored.
index c810481a5bc23ae3ca57127729c83e454d681534..6c1b676643a9ef43fe3984bb8495996960cf4337 100644 (file)
@@ -48,6 +48,9 @@ struct ports_driver_data {
        /* Used for exporting per-port information to debugfs */
        struct dentry *debugfs_dir;
 
+       /* List of all the devices we're handling */
+       struct list_head portdevs;
+
        /* Number of devices this driver is handling */
        unsigned int index;
 
@@ -108,6 +111,9 @@ struct port_buffer {
  * ports for that device (vdev->priv).
  */
 struct ports_device {
+       /* Next portdev in the list, head is in the pdrvdata struct */
+       struct list_head list;
+
        /*
         * Workqueue handlers where we process deferred work after
         * notification
@@ -178,15 +184,21 @@ struct port {
        struct console cons;
 
        /* Each port associates with a separate char device */
-       struct cdev cdev;
+       struct cdev *cdev;
        struct device *dev;
 
+       /* Reference-counting to handle port hot-unplugs and file operations */
+       struct kref kref;
+
        /* A waitqueue for poll() or blocking read operations */
        wait_queue_head_t waitqueue;
 
        /* The 'name' of the port that we expose via sysfs properties */
        char *name;
 
+       /* We can notify apps of host connect / disconnect events via SIGIO */
+       struct fasync_struct *async_queue;
+
        /* The 'id' to identify the port with the Host */
        u32 id;
 
@@ -221,6 +233,41 @@ out:
        return port;
 }
 
+static struct port *find_port_by_devt_in_portdev(struct ports_device *portdev,
+                                                dev_t dev)
+{
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&portdev->ports_lock, flags);
+       list_for_each_entry(port, &portdev->ports, list)
+               if (port->cdev->dev == dev)
+                       goto out;
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&portdev->ports_lock, flags);
+
+       return port;
+}
+
+static struct port *find_port_by_devt(dev_t dev)
+{
+       struct ports_device *portdev;
+       struct port *port;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pdrvdata_lock, flags);
+       list_for_each_entry(portdev, &pdrvdata.portdevs, list) {
+               port = find_port_by_devt_in_portdev(portdev, dev);
+               if (port)
+                       goto out;
+       }
+       port = NULL;
+out:
+       spin_unlock_irqrestore(&pdrvdata_lock, flags);
+       return port;
+}
+
 static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
 {
        struct port *port;
@@ -410,7 +457,10 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
 static ssize_t send_control_msg(struct port *port, unsigned int event,
                                unsigned int value)
 {
-       return __send_control_msg(port->portdev, port->id, event, value);
+       /* Did the port get unplugged before userspace closed it? */
+       if (port->portdev)
+               return __send_control_msg(port->portdev, port->id, event, value);
+       return 0;
 }
 
 /* Callers must take the port->outvq_lock */
@@ -459,9 +509,12 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
 
        /*
         * Wait till the host acknowledges it pushed out the data we
-        * sent.  This is done for ports in blocking mode or for data
-        * from the hvc_console; the tty operations are performed with
-        * spinlocks held so we can't sleep here.
+        * sent.  This is done for data from the hvc_console; the tty
+        * operations are performed with spinlocks held so we can't
+        * sleep here.  An alternative would be to copy the data to a
+        * buffer and relax the spinning requirement.  The downside is
+        * we need to kmalloc a GFP_ATOMIC buffer each time the
+        * console driver writes something out.
         */
        while (!virtqueue_get_buf(out_vq, &len))
                cpu_relax();
@@ -522,6 +575,10 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
 /* The condition that must be true for polling to end */
 static bool will_read_block(struct port *port)
 {
+       if (!port->guest_connected) {
+               /* Port got hot-unplugged. Let's exit. */
+               return false;
+       }
        return !port_has_data(port) && port->host_connected;
 }
 
@@ -572,6 +629,9 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
                if (ret < 0)
                        return ret;
        }
+       /* Port got hot-unplugged. */
+       if (!port->guest_connected)
+               return -ENODEV;
        /*
         * We could've received a disconnection message while we were
         * waiting for more data.
@@ -613,6 +673,9 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
                if (ret < 0)
                        return ret;
        }
+       /* Port got hot-unplugged. */
+       if (!port->guest_connected)
+               return -ENODEV;
 
        count = min((size_t)(32 * 1024), count);
 
@@ -626,6 +689,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
                goto free_buf;
        }
 
+       /*
+        * We now ask send_buf() to not spin for generic ports -- we
+        * can re-use the same code path that non-blocking file
+        * descriptors take for blocking file descriptors since the
+        * wait is already done and we're certain the write will go
+        * through to the host.
+        */
+       nonblock = true;
        ret = send_buf(port, buf, count, nonblock);
 
        if (nonblock && ret > 0)
@@ -645,6 +716,10 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
        port = filp->private_data;
        poll_wait(filp, &port->waitqueue, wait);
 
+       if (!port->guest_connected) {
+               /* Port got unplugged */
+               return POLLHUP;
+       }
        ret = 0;
        if (!will_read_block(port))
                ret |= POLLIN | POLLRDNORM;
@@ -656,6 +731,8 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
        return ret;
 }
 
+static void remove_port(struct kref *kref);
+
 static int port_fops_release(struct inode *inode, struct file *filp)
 {
        struct port *port;
@@ -676,6 +753,16 @@ static int port_fops_release(struct inode *inode, struct file *filp)
        reclaim_consumed_buffers(port);
        spin_unlock_irq(&port->outvq_lock);
 
+       /*
+        * Locks aren't necessary here as a port can't be opened after
+        * unplug, and if a port isn't unplugged, a kref would already
+        * exist for the port.  Plus, taking ports_lock here would
+        * create a dependency on other locks taken by functions
+        * inside remove_port if we're the last holder of the port,
+        * creating many problems.
+        */
+       kref_put(&port->kref, remove_port);
+
        return 0;
 }
 
@@ -683,22 +770,31 @@ static int port_fops_open(struct inode *inode, struct file *filp)
 {
        struct cdev *cdev = inode->i_cdev;
        struct port *port;
+       int ret;
 
-       port = container_of(cdev, struct port, cdev);
+       port = find_port_by_devt(cdev->dev);
        filp->private_data = port;
 
+       /* Prevent against a port getting hot-unplugged at the same time */
+       spin_lock_irq(&port->portdev->ports_lock);
+       kref_get(&port->kref);
+       spin_unlock_irq(&port->portdev->ports_lock);
+
        /*
         * Don't allow opening of console port devices -- that's done
         * via /dev/hvc
         */
-       if (is_console_port(port))
-               return -ENXIO;
+       if (is_console_port(port)) {
+               ret = -ENXIO;
+               goto out;
+       }
 
        /* Allow only one process to open a particular port at a time */
        spin_lock_irq(&port->inbuf_lock);
        if (port->guest_connected) {
                spin_unlock_irq(&port->inbuf_lock);
-               return -EMFILE;
+               ret = -EMFILE;
+               goto out;
        }
 
        port->guest_connected = true;
@@ -713,10 +809,23 @@ static int port_fops_open(struct inode *inode, struct file *filp)
        reclaim_consumed_buffers(port);
        spin_unlock_irq(&port->outvq_lock);
 
+       nonseekable_open(inode, filp);
+
        /* Notify host of port being opened */
        send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
 
        return 0;
+out:
+       kref_put(&port->kref, remove_port);
+       return ret;
+}
+
+static int port_fops_fasync(int fd, struct file *filp, int mode)
+{
+       struct port *port;
+
+       port = filp->private_data;
+       return fasync_helper(fd, filp, mode, &port->async_queue);
 }
 
 /*
@@ -732,6 +841,8 @@ static const struct file_operations port_fops = {
        .write = port_fops_write,
        .poll  = port_fops_poll,
        .release = port_fops_release,
+       .fasync = port_fops_fasync,
+       .llseek = no_llseek,
 };
 
 /*
@@ -990,6 +1101,12 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
        return nr_added_bufs;
 }
 
+static void send_sigio_to_port(struct port *port)
+{
+       if (port->async_queue && port->guest_connected)
+               kill_fasync(&port->async_queue, SIGIO, POLL_OUT);
+}
+
 static int add_port(struct ports_device *portdev, u32 id)
 {
        char debugfs_name[16];
@@ -1004,6 +1121,7 @@ static int add_port(struct ports_device *portdev, u32 id)
                err = -ENOMEM;
                goto fail;
        }
+       kref_init(&port->kref);
 
        port->portdev = portdev;
        port->id = id;
@@ -1011,6 +1129,7 @@ static int add_port(struct ports_device *portdev, u32 id)
        port->name = NULL;
        port->inbuf = NULL;
        port->cons.hvc = NULL;
+       port->async_queue = NULL;
 
        port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
 
@@ -1021,14 +1140,20 @@ static int add_port(struct ports_device *portdev, u32 id)
        port->in_vq = portdev->in_vqs[port->id];
        port->out_vq = portdev->out_vqs[port->id];
 
-       cdev_init(&port->cdev, &port_fops);
+       port->cdev = cdev_alloc();
+       if (!port->cdev) {
+               dev_err(&port->portdev->vdev->dev, "Error allocating cdev\n");
+               err = -ENOMEM;
+               goto free_port;
+       }
+       port->cdev->ops = &port_fops;
 
        devt = MKDEV(portdev->chr_major, id);
-       err = cdev_add(&port->cdev, devt, 1);
+       err = cdev_add(port->cdev, devt, 1);
        if (err < 0) {
                dev_err(&port->portdev->vdev->dev,
                        "Error %d adding cdev for port %u\n", err, id);
-               goto free_port;
+               goto free_cdev;
        }
        port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
                                  devt, port, "vport%up%u",
@@ -1093,7 +1218,7 @@ free_inbufs:
 free_device:
        device_destroy(pdrvdata.class, port->dev->devt);
 free_cdev:
-       cdev_del(&port->cdev);
+       cdev_del(port->cdev);
 free_port:
        kfree(port);
 fail:
@@ -1102,21 +1227,45 @@ fail:
        return err;
 }
 
-/* Remove all port-specific data. */
-static int remove_port(struct port *port)
+/* No users remain, remove all port-specific data. */
+static void remove_port(struct kref *kref)
+{
+       struct port *port;
+
+       port = container_of(kref, struct port, kref);
+
+       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
+       device_destroy(pdrvdata.class, port->dev->devt);
+       cdev_del(port->cdev);
+
+       kfree(port->name);
+
+       debugfs_remove(port->debugfs_file);
+
+       kfree(port);
+}
+
+/*
+ * Port got unplugged.  Remove port from portdev's list and drop the
+ * kref reference.  If no userspace has this port opened, it will
+ * result in immediate removal the port.
+ */
+static void unplug_port(struct port *port)
 {
        struct port_buffer *buf;
 
+       spin_lock_irq(&port->portdev->ports_lock);
+       list_del(&port->list);
+       spin_unlock_irq(&port->portdev->ports_lock);
+
        if (port->guest_connected) {
                port->guest_connected = false;
                port->host_connected = false;
                wake_up_interruptible(&port->waitqueue);
-               send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
-       }
 
-       spin_lock_irq(&port->portdev->ports_lock);
-       list_del(&port->list);
-       spin_unlock_irq(&port->portdev->ports_lock);
+               /* Let the app know the port is going down. */
+               send_sigio_to_port(port);
+       }
 
        if (is_console_port(port)) {
                spin_lock_irq(&pdrvdata_lock);
@@ -1135,9 +1284,6 @@ static int remove_port(struct port *port)
                hvc_remove(port->cons.hvc);
 #endif
        }
-       sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
-       device_destroy(pdrvdata.class, port->dev->devt);
-       cdev_del(&port->cdev);
 
        /* Remove unused data this port might have received. */
        discard_port_data(port);
@@ -1148,12 +1294,19 @@ static int remove_port(struct port *port)
        while ((buf = virtqueue_detach_unused_buf(port->in_vq)))
                free_buf(buf);
 
-       kfree(port->name);
-
-       debugfs_remove(port->debugfs_file);
+       /*
+        * We should just assume the device itself has gone off --
+        * else a close on an open port later will try to send out a
+        * control message.
+        */
+       port->portdev = NULL;
 
-       kfree(port);
-       return 0;
+       /*
+        * Locks around here are not necessary - a port can't be
+        * opened after we removed the port struct from ports_list
+        * above.
+        */
+       kref_put(&port->kref, remove_port);
 }
 
 /* Any private messages that the Host and Guest want to share */
@@ -1192,7 +1345,7 @@ static void handle_control_message(struct ports_device *portdev,
                add_port(portdev, cpkt->id);
                break;
        case VIRTIO_CONSOLE_PORT_REMOVE:
-               remove_port(port);
+               unplug_port(port);
                break;
        case VIRTIO_CONSOLE_CONSOLE_PORT:
                if (!cpkt->value)
@@ -1234,6 +1387,12 @@ static void handle_control_message(struct ports_device *portdev,
                spin_lock_irq(&port->outvq_lock);
                reclaim_consumed_buffers(port);
                spin_unlock_irq(&port->outvq_lock);
+
+               /*
+                * If the guest is connected, it'll be interested in
+                * knowing the host connection state changed.
+                */
+               send_sigio_to_port(port);
                break;
        case VIRTIO_CONSOLE_PORT_NAME:
                /*
@@ -1330,6 +1489,9 @@ static void in_intr(struct virtqueue *vq)
 
        wake_up_interruptible(&port->waitqueue);
 
+       /* Send a SIGIO indicating new data in case the process asked for it */
+       send_sigio_to_port(port);
+
        if (is_console_port(port) && hvc_poll(port->cons.hvc))
                hvc_kick();
 }
@@ -1566,6 +1728,10 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
                add_port(portdev, 0);
        }
 
+       spin_lock_irq(&pdrvdata_lock);
+       list_add_tail(&portdev->list, &pdrvdata.portdevs);
+       spin_unlock_irq(&pdrvdata_lock);
+
        __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
                           VIRTIO_CONSOLE_DEVICE_READY, 1);
        return 0;
@@ -1589,23 +1755,41 @@ static void virtcons_remove(struct virtio_device *vdev)
 {
        struct ports_device *portdev;
        struct port *port, *port2;
-       struct port_buffer *buf;
-       unsigned int len;
 
        portdev = vdev->priv;
 
+       spin_lock_irq(&pdrvdata_lock);
+       list_del(&portdev->list);
+       spin_unlock_irq(&pdrvdata_lock);
+
+       /* Disable interrupts for vqs */
+       vdev->config->reset(vdev);
+       /* Finish up work that's lined up */
        cancel_work_sync(&portdev->control_work);
 
        list_for_each_entry_safe(port, port2, &portdev->ports, list)
-               remove_port(port);
+               unplug_port(port);
 
        unregister_chrdev(portdev->chr_major, "virtio-portsdev");
 
-       while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
-               free_buf(buf);
+       /*
+        * When yanking out a device, we immediately lose the
+        * (device-side) queues.  So there's no point in keeping the
+        * guest side around till we drop our final reference.  This
+        * also means that any ports which are in an open state will
+        * have to just stop using the port, as the vqs are going
+        * away.
+        */
+       if (use_multiport(portdev)) {
+               struct port_buffer *buf;
+               unsigned int len;
 
-       while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
-               free_buf(buf);
+               while ((buf = virtqueue_get_buf(portdev->c_ivq, &len)))
+                       free_buf(buf);
+
+               while ((buf = virtqueue_detach_unused_buf(portdev->c_ivq)))
+                       free_buf(buf);
+       }
 
        vdev->config->del_vqs(vdev);
        kfree(portdev->in_vqs);
@@ -1652,6 +1836,7 @@ static int __init init(void)
                           PTR_ERR(pdrvdata.debugfs_dir));
        }
        INIT_LIST_HEAD(&pdrvdata.consoles);
+       INIT_LIST_HEAD(&pdrvdata.portdevs);
 
        return register_virtio_driver(&virtio_console);
 }
index 70bb350de9964a813b6e4627e6c4a709e23ff930..9dbb28b9559f7d794dd7f6899a5ff52056ce4017 100644 (file)
@@ -39,7 +39,7 @@ config EDAC_DEBUG
          there're four debug levels (x=0,1,2,3 from low to high).
          Usually you should select 'N'.
 
- config EDAC_DECODE_MCE
+config EDAC_DECODE_MCE
        tristate "Decode MCEs in human-readable form (only on AMD for now)"
        depends on CPU_SUP_AMD && X86_MCE
        default y
@@ -51,6 +51,16 @@ config EDAC_DEBUG
          which occur really early upon boot, before the module infrastructure
          has been initialized.
 
+config EDAC_MCE_INJ
+       tristate "Simple MCE injection interface over /sysfs"
+       depends on EDAC_DECODE_MCE
+       default n
+       help
+         This is a simple interface to inject MCEs over /sysfs and test
+         the MCE decoding code in EDAC.
+
+         This is currently AMD-only.
+
 config EDAC_MM_EDAC
        tristate "Main Memory EDAC (Error Detection And Correction) reporting"
        help
@@ -66,13 +76,13 @@ config EDAC_MCE
 
 config EDAC_AMD64
        tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
-       depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE
+       depends on EDAC_MM_EDAC && AMD_NB && X86_64 && PCI && EDAC_DECODE_MCE
        help
          Support for error detection and correction on the AMD 64
          Families of Memory Controllers (K8, F10h and F11h)
 
 config EDAC_AMD64_ERROR_INJECTION
-       bool "Sysfs Error Injection facilities"
+       bool "Sysfs HW Error injection facilities"
        depends on EDAC_AMD64
        help
          Recent Opterons (Family 10h and later) provide for Memory Error
index ca6b1bb24ccc8e76109b13f38e1237eec98ec09e..32c7bc93c525ef1613d1c116b14b0e1a0e0f4f8a 100644 (file)
@@ -17,6 +17,9 @@ ifdef CONFIG_PCI
 edac_core-objs += edac_pci.o edac_pci_sysfs.o
 endif
 
+obj-$(CONFIG_EDAC_MCE_INJ)             += mce_amd_inj.o
+
+edac_mce_amd-objs                      := mce_amd.o
 obj-$(CONFIG_EDAC_DECODE_MCE)          += edac_mce_amd.o
 
 obj-$(CONFIG_EDAC_AMD76X)              += amd76x_edac.o
index e7d5d6b5dcf69683d5ac7c59d6608643c5ae4e53..8521401bbd751406e6f2752e10868f63c7e3b48a 100644 (file)
@@ -1,5 +1,5 @@
 #include "amd64_edac.h"
-#include <asm/k8.h>
+#include <asm/amd_nb.h>
 
 static struct edac_pci_ctl_info *amd64_ctl_pci;
 
@@ -2073,11 +2073,18 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
                amd64_handle_ue(mci, info);
 }
 
-void amd64_decode_bus_error(int node_id, struct err_regs *regs)
+void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
 {
        struct mem_ctl_info *mci = mci_lookup[node_id];
+       struct err_regs regs;
 
-       __amd64_decode_bus_error(mci, regs);
+       regs.nbsl  = (u32) m->status;
+       regs.nbsh  = (u32)(m->status >> 32);
+       regs.nbeal = (u32) m->addr;
+       regs.nbeah = (u32)(m->addr >> 32);
+       regs.nbcfg = nbcfg;
+
+       __amd64_decode_bus_error(mci, &regs);
 
        /*
         * Check the UE bit of the NB status high register, if set generate some
@@ -2086,7 +2093,7 @@ void amd64_decode_bus_error(int node_id, struct err_regs *regs)
         *
         * FIXME: this should go somewhere else, if at all.
         */
-       if (regs->nbsh & K8_NBSH_UC_ERR && !report_gart_errors)
+       if (regs.nbsh & K8_NBSH_UC_ERR && !report_gart_errors)
                edac_mc_handle_ue_no_info(mci, "UE bit is set");
 
 }
@@ -2927,7 +2934,7 @@ static int __init amd64_edac_init(void)
         * to finish initialization of the MC instances.
         */
        err = -ENODEV;
-       for (nb = 0; nb < num_k8_northbridges; nb++) {
+       for (nb = 0; nb < k8_northbridges.num; nb++) {
                if (!pvt_lookup[nb])
                        continue;
 
index 613b9381e71a658e76fd312beb0e1d05e5f10616..044aee4f944da6ae9a709584ae243c3e97c151a9 100644 (file)
@@ -72,7 +72,7 @@
 #include <linux/edac.h>
 #include <asm/msr.h>
 #include "edac_core.h"
-#include "edac_mce_amd.h"
+#include "mce_amd.h"
 
 #define amd64_printk(level, fmt, arg...) \
        edac_printk(level, "amd64", fmt, ##arg)
@@ -482,11 +482,10 @@ extern const char *rrrr_msgs[16];
 extern const char *to_msgs[2];
 extern const char *pp_msgs[4];
 extern const char *ii_msgs[4];
-extern const char *ext_msgs[32];
 extern const char *htlink_msgs[8];
 
 #ifdef CONFIG_EDAC_DEBUG
-#define NUM_DBG_ATTRS 9
+#define NUM_DBG_ATTRS 5
 #else
 #define NUM_DBG_ATTRS 0
 #endif
index 59cf2cf6e11ec3fc9628b5f6b32aa525ae3a80cf..e3562288f4ce80589ab0680f4fc179335da80822 100644 (file)
 #include "amd64_edac.h"
 
-/*
- * accept a hex value and store it into the virtual error register file, field:
- * nbeal and nbeah. Assume virtual error values have already been set for: NBSL,
- * NBSH and NBCFG. Then proceed to map the error values to a MC, CSROW and
- * CHANNEL
- */
-static ssize_t amd64_nbea_store(struct mem_ctl_info *mci, const char *data,
-                               size_t count)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-       unsigned long long value;
-       int ret = 0;
-
-       ret = strict_strtoull(data, 16, &value);
-       if (ret != -EINVAL) {
-               debugf0("received NBEA= 0x%llx\n", value);
-
-               /* place the value into the virtual error packet */
-               pvt->ctl_error_info.nbeal = (u32) value;
-               value >>= 32;
-               pvt->ctl_error_info.nbeah = (u32) value;
-
-               /* Process the Mapping request */
-               /* TODO: Add race prevention */
-               amd_decode_nb_mce(pvt->mc_node_id, &pvt->ctl_error_info, 1);
-
-               return count;
-       }
-       return ret;
-}
-
-/* display back what the last NBEA (MCA NB Address (MC4_ADDR)) was written */
-static ssize_t amd64_nbea_show(struct mem_ctl_info *mci, char *data)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-       u64 value;
-
-       value = pvt->ctl_error_info.nbeah;
-       value <<= 32;
-       value |= pvt->ctl_error_info.nbeal;
-
-       return sprintf(data, "%llx\n", value);
-}
-
-/* store the NBSL (MCA NB Status Low (MC4_STATUS)) value user desires */
-static ssize_t amd64_nbsl_store(struct mem_ctl_info *mci, const char *data,
-                               size_t count)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-       unsigned long value;
-       int ret = 0;
-
-       ret = strict_strtoul(data, 16, &value);
-       if (ret != -EINVAL) {
-               debugf0("received NBSL= 0x%lx\n", value);
-
-               pvt->ctl_error_info.nbsl = (u32) value;
-
-               return count;
-       }
-       return ret;
-}
-
-/* display back what the last NBSL value written */
-static ssize_t amd64_nbsl_show(struct mem_ctl_info *mci, char *data)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-       u32 value;
-
-       value = pvt->ctl_error_info.nbsl;
-
-       return sprintf(data, "%x\n", value);
-}
-
-/* store the NBSH (MCA NB Status High) value user desires */
-static ssize_t amd64_nbsh_store(struct mem_ctl_info *mci, const char *data,
-                               size_t count)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-       unsigned long value;
-       int ret = 0;
-
-       ret = strict_strtoul(data, 16, &value);
-       if (ret != -EINVAL) {
-               debugf0("received NBSH= 0x%lx\n", value);
-
-               pvt->ctl_error_info.nbsh = (u32) value;
-
-               return count;
-       }
-       return ret;
-}
-
-/* display back what the last NBSH value written */
-static ssize_t amd64_nbsh_show(struct mem_ctl_info *mci, char *data)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-       u32 value;
-
-       value = pvt->ctl_error_info.nbsh;
-
-       return sprintf(data, "%x\n", value);
+#define EDAC_DCT_ATTR_SHOW(reg)                                                \
+static ssize_t amd64_##reg##_show(struct mem_ctl_info *mci, char *data)        \
+{                                                                      \
+       struct amd64_pvt *pvt = mci->pvt_info;                          \
+               return sprintf(data, "0x%016llx\n", (u64)pvt->reg);     \
 }
 
-/* accept and store the NBCFG (MCA NB Configuration) value user desires */
-static ssize_t amd64_nbcfg_store(struct mem_ctl_info *mci,
-                                       const char *data, size_t count)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-       unsigned long value;
-       int ret = 0;
-
-       ret = strict_strtoul(data, 16, &value);
-       if (ret != -EINVAL) {
-               debugf0("received NBCFG= 0x%lx\n", value);
-
-               pvt->ctl_error_info.nbcfg = (u32) value;
-
-               return count;
-       }
-       return ret;
-}
-
-/* various show routines for the controls of a MCI */
-static ssize_t amd64_nbcfg_show(struct mem_ctl_info *mci, char *data)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-
-       return sprintf(data, "%x\n", pvt->ctl_error_info.nbcfg);
-}
-
-
-static ssize_t amd64_dhar_show(struct mem_ctl_info *mci, char *data)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-
-       return sprintf(data, "%x\n", pvt->dhar);
-}
-
-
-static ssize_t amd64_dbam_show(struct mem_ctl_info *mci, char *data)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-
-       return sprintf(data, "%x\n", pvt->dbam0);
-}
-
-
-static ssize_t amd64_topmem_show(struct mem_ctl_info *mci, char *data)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-
-       return sprintf(data, "%llx\n", pvt->top_mem);
-}
-
-
-static ssize_t amd64_topmem2_show(struct mem_ctl_info *mci, char *data)
-{
-       struct amd64_pvt *pvt = mci->pvt_info;
-
-       return sprintf(data, "%llx\n", pvt->top_mem2);
-}
+EDAC_DCT_ATTR_SHOW(dhar);
+EDAC_DCT_ATTR_SHOW(dbam0);
+EDAC_DCT_ATTR_SHOW(top_mem);
+EDAC_DCT_ATTR_SHOW(top_mem2);
 
 static ssize_t amd64_hole_show(struct mem_ctl_info *mci, char *data)
 {
@@ -180,38 +29,6 @@ static ssize_t amd64_hole_show(struct mem_ctl_info *mci, char *data)
  */
 struct mcidev_sysfs_attribute amd64_dbg_attrs[] = {
 
-       {
-               .attr = {
-                       .name = "nbea_ctl",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show = amd64_nbea_show,
-               .store = amd64_nbea_store,
-       },
-       {
-               .attr = {
-                       .name = "nbsl_ctl",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show = amd64_nbsl_show,
-               .store = amd64_nbsl_store,
-       },
-       {
-               .attr = {
-                       .name = "nbsh_ctl",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show = amd64_nbsh_show,
-               .store = amd64_nbsh_store,
-       },
-       {
-               .attr = {
-                       .name = "nbcfg_ctl",
-                       .mode = (S_IRUGO | S_IWUSR)
-               },
-               .show = amd64_nbcfg_show,
-               .store = amd64_nbcfg_store,
-       },
        {
                .attr = {
                        .name = "dhar",
@@ -225,7 +42,7 @@ struct mcidev_sysfs_attribute amd64_dbg_attrs[] = {
                        .name = "dbam",
                        .mode = (S_IRUGO)
                },
-               .show = amd64_dbam_show,
+               .show = amd64_dbam0_show,
                .store = NULL,
        },
        {
@@ -233,7 +50,7 @@ struct mcidev_sysfs_attribute amd64_dbg_attrs[] = {
                        .name = "topmem",
                        .mode = (S_IRUGO)
                },
-               .show = amd64_topmem_show,
+               .show = amd64_top_mem_show,
                .store = NULL,
        },
        {
@@ -241,7 +58,7 @@ struct mcidev_sysfs_attribute amd64_dbg_attrs[] = {
                        .name = "topmem2",
                        .mode = (S_IRUGO)
                },
-               .show = amd64_topmem2_show,
+               .show = amd64_top_mem2_show,
                .store = NULL,
        },
        {
index 070968178a24a80703708dd50ba363301ad71aac..2941dca91aae3f949a04a29b02f32eed5a107bb8 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/ctype.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/edac.h>
 
 #include "edac_core.h"
 #include "edac_module.h"
@@ -235,7 +236,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
        debugf1("%s()\n", __func__);
 
        /* get the /sys/devices/system/edac reference */
-       edac_class = edac_get_edac_class();
+       edac_class = edac_get_sysfs_class();
        if (edac_class == NULL) {
                debugf1("%s() no edac_class error\n", __func__);
                err = -ENODEV;
@@ -255,7 +256,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 
        if (!try_module_get(edac_dev->owner)) {
                err = -ENODEV;
-               goto err_out;
+               goto err_mod_get;
        }
 
        /* register */
@@ -282,6 +283,9 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
 err_kobj_reg:
        module_put(edac_dev->owner);
 
+err_mod_get:
+       edac_put_sysfs_class();
+
 err_out:
        return err;
 }
@@ -290,12 +294,11 @@ err_out:
  * edac_device_unregister_sysfs_main_kobj:
  *     the '..../edac/<name>' kobject
  */
-void edac_device_unregister_sysfs_main_kobj(
-                                       struct edac_device_ctl_info *edac_dev)
+void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
 {
        debugf0("%s()\n", __func__);
        debugf4("%s() name of kobject is: %s\n",
-               __func__, kobject_name(&edac_dev->kobj));
+               __func__, kobject_name(&dev->kobj));
 
        /*
         * Unregister the edac device's kobject and
@@ -304,7 +307,8 @@ void edac_device_unregister_sysfs_main_kobj(
         *   a) module_put() this module
         *   b) 'kfree' the memory
         */
-       kobject_put(&edac_dev->kobj);
+       kobject_put(&dev->kobj);
+       edac_put_sysfs_class();
 }
 
 /* edac_dev -> instance information */
index 8aad94d10c0cced51d10746f22b5086068c48d74..a4135860149b5592e6e73e8036796f63e6f045d4 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/ctype.h>
 #include <linux/slab.h>
+#include <linux/edac.h>
 #include <linux/bug.h>
 
 #include "edac_core.h"
@@ -1011,13 +1012,13 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
  */
 int edac_sysfs_setup_mc_kset(void)
 {
-       int err = 0;
+       int err = -EINVAL;
        struct sysdev_class *edac_class;
 
        debugf1("%s()\n", __func__);
 
        /* get the /sys/devices/system/edac class reference */
-       edac_class = edac_get_edac_class();
+       edac_class = edac_get_sysfs_class();
        if (edac_class == NULL) {
                debugf1("%s() no edac_class error=%d\n", __func__, err);
                goto fail_out;
@@ -1028,15 +1029,16 @@ int edac_sysfs_setup_mc_kset(void)
        if (!mc_kset) {
                err = -ENOMEM;
                debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
-               goto fail_out;
+               goto fail_kset;
        }
 
        debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
 
        return 0;
 
+fail_kset:
+       edac_put_sysfs_class();
 
-       /* error unwind stack */
 fail_out:
        return err;
 }
@@ -1049,5 +1051,6 @@ fail_out:
 void edac_sysfs_teardown_mc_kset(void)
 {
        kset_unregister(mc_kset);
+       edac_put_sysfs_class();
 }
 
diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c
deleted file mode 100644 (file)
index 9014df6..0000000
+++ /dev/null
@@ -1,452 +0,0 @@
-#include <linux/module.h>
-#include "edac_mce_amd.h"
-
-static bool report_gart_errors;
-static void (*nb_bus_decoder)(int node_id, struct err_regs *regs);
-
-void amd_report_gart_errors(bool v)
-{
-       report_gart_errors = v;
-}
-EXPORT_SYMBOL_GPL(amd_report_gart_errors);
-
-void amd_register_ecc_decoder(void (*f)(int, struct err_regs *))
-{
-       nb_bus_decoder = f;
-}
-EXPORT_SYMBOL_GPL(amd_register_ecc_decoder);
-
-void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *))
-{
-       if (nb_bus_decoder) {
-               WARN_ON(nb_bus_decoder != f);
-
-               nb_bus_decoder = NULL;
-       }
-}
-EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder);
-
-/*
- * string representation for the different MCA reported error types, see F3x48
- * or MSR0000_0411.
- */
-const char *tt_msgs[] = {        /* transaction type */
-       "instruction",
-       "data",
-       "generic",
-       "reserved"
-};
-EXPORT_SYMBOL_GPL(tt_msgs);
-
-const char *ll_msgs[] = {      /* cache level */
-       "L0",
-       "L1",
-       "L2",
-       "L3/generic"
-};
-EXPORT_SYMBOL_GPL(ll_msgs);
-
-const char *rrrr_msgs[] = {
-       "generic",
-       "generic read",
-       "generic write",
-       "data read",
-       "data write",
-       "inst fetch",
-       "prefetch",
-       "evict",
-       "snoop",
-       "reserved RRRR= 9",
-       "reserved RRRR= 10",
-       "reserved RRRR= 11",
-       "reserved RRRR= 12",
-       "reserved RRRR= 13",
-       "reserved RRRR= 14",
-       "reserved RRRR= 15"
-};
-EXPORT_SYMBOL_GPL(rrrr_msgs);
-
-const char *pp_msgs[] = {      /* participating processor */
-       "local node originated (SRC)",
-       "local node responded to request (RES)",
-       "local node observed as 3rd party (OBS)",
-       "generic"
-};
-EXPORT_SYMBOL_GPL(pp_msgs);
-
-const char *to_msgs[] = {
-       "no timeout",
-       "timed out"
-};
-EXPORT_SYMBOL_GPL(to_msgs);
-
-const char *ii_msgs[] = {      /* memory or i/o */
-       "mem access",
-       "reserved",
-       "i/o access",
-       "generic"
-};
-EXPORT_SYMBOL_GPL(ii_msgs);
-
-/*
- * Map the 4 or 5 (family-specific) bits of Extended Error code to the
- * string table.
- */
-const char *ext_msgs[] = {
-       "K8 ECC error",                                 /* 0_0000b */
-       "CRC error on link",                            /* 0_0001b */
-       "Sync error packets on link",                   /* 0_0010b */
-       "Master Abort during link operation",           /* 0_0011b */
-       "Target Abort during link operation",           /* 0_0100b */
-       "Invalid GART PTE entry during table walk",     /* 0_0101b */
-       "Unsupported atomic RMW command received",      /* 0_0110b */
-       "WDT error: NB transaction timeout",            /* 0_0111b */
-       "ECC/ChipKill ECC error",                       /* 0_1000b */
-       "SVM DEV Error",                                /* 0_1001b */
-       "Link Data error",                              /* 0_1010b */
-       "Link/L3/Probe Filter Protocol error",          /* 0_1011b */
-       "NB Internal Arrays Parity error",              /* 0_1100b */
-       "DRAM Address/Control Parity error",            /* 0_1101b */
-       "Link Transmission error",                      /* 0_1110b */
-       "GART/DEV Table Walk Data error"                /* 0_1111b */
-       "Res 0x100 error",                              /* 1_0000b */
-       "Res 0x101 error",                              /* 1_0001b */
-       "Res 0x102 error",                              /* 1_0010b */
-       "Res 0x103 error",                              /* 1_0011b */
-       "Res 0x104 error",                              /* 1_0100b */
-       "Res 0x105 error",                              /* 1_0101b */
-       "Res 0x106 error",                              /* 1_0110b */
-       "Res 0x107 error",                              /* 1_0111b */
-       "Res 0x108 error",                              /* 1_1000b */
-       "Res 0x109 error",                              /* 1_1001b */
-       "Res 0x10A error",                              /* 1_1010b */
-       "Res 0x10B error",                              /* 1_1011b */
-       "ECC error in L3 Cache Data",                   /* 1_1100b */
-       "L3 Cache Tag error",                           /* 1_1101b */
-       "L3 Cache LRU Parity error",                    /* 1_1110b */
-       "Probe Filter error"                            /* 1_1111b */
-};
-EXPORT_SYMBOL_GPL(ext_msgs);
-
-static void amd_decode_dc_mce(u64 mc0_status)
-{
-       u32 ec  = mc0_status & 0xffff;
-       u32 xec = (mc0_status >> 16) & 0xf;
-
-       pr_emerg("Data Cache Error");
-
-       if (xec == 1 && TLB_ERROR(ec))
-               pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
-       else if (xec == 0) {
-               if (mc0_status & (1ULL << 40))
-                       pr_cont(" during Data Scrub.\n");
-               else if (TLB_ERROR(ec))
-                       pr_cont(": %s TLB parity error.\n", LL_MSG(ec));
-               else if (MEM_ERROR(ec)) {
-                       u8 ll   = ec & 0x3;
-                       u8 tt   = (ec >> 2) & 0x3;
-                       u8 rrrr = (ec >> 4) & 0xf;
-
-                       /* see F10h BKDG (31116), Table 92. */
-                       if (ll == 0x1) {
-                               if (tt != 0x1)
-                                       goto wrong_dc_mce;
-
-                               pr_cont(": Data/Tag %s error.\n", RRRR_MSG(ec));
-
-                       } else if (ll == 0x2 && rrrr == 0x3)
-                               pr_cont(" during L1 linefill from L2.\n");
-                       else
-                               goto wrong_dc_mce;
-               } else if (BUS_ERROR(ec) && boot_cpu_data.x86 == 0xf)
-                       pr_cont(" during system linefill.\n");
-               else
-                       goto wrong_dc_mce;
-       } else
-               goto wrong_dc_mce;
-
-       return;
-
-wrong_dc_mce:
-       pr_warning("Corrupted DC MCE info?\n");
-}
-
-static void amd_decode_ic_mce(u64 mc1_status)
-{
-       u32 ec  = mc1_status & 0xffff;
-       u32 xec = (mc1_status >> 16) & 0xf;
-
-       pr_emerg("Instruction Cache Error");
-
-       if (xec == 1 && TLB_ERROR(ec))
-               pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
-       else if (xec == 0) {
-               if (TLB_ERROR(ec))
-                       pr_cont(": %s TLB Parity error.\n", LL_MSG(ec));
-               else if (BUS_ERROR(ec)) {
-                       if (boot_cpu_data.x86 == 0xf &&
-                           (mc1_status & (1ULL << 58)))
-                               pr_cont(" during system linefill.\n");
-                       else
-                               pr_cont(" during attempted NB data read.\n");
-               } else if (MEM_ERROR(ec)) {
-                       u8 ll   = ec & 0x3;
-                       u8 rrrr = (ec >> 4) & 0xf;
-
-                       if (ll == 0x2)
-                               pr_cont(" during a linefill from L2.\n");
-                       else if (ll == 0x1) {
-
-                               switch (rrrr) {
-                               case 0x5:
-                                       pr_cont(": Parity error during "
-                                              "data load.\n");
-                                       break;
-
-                               case 0x7:
-                                       pr_cont(": Copyback Parity/Victim"
-                                               " error.\n");
-                                       break;
-
-                               case 0x8:
-                                       pr_cont(": Tag Snoop error.\n");
-                                       break;
-
-                               default:
-                                       goto wrong_ic_mce;
-                                       break;
-                               }
-                       }
-               } else
-                       goto wrong_ic_mce;
-       } else
-               goto wrong_ic_mce;
-
-       return;
-
-wrong_ic_mce:
-       pr_warning("Corrupted IC MCE info?\n");
-}
-
-static void amd_decode_bu_mce(u64 mc2_status)
-{
-       u32 ec = mc2_status & 0xffff;
-       u32 xec = (mc2_status >> 16) & 0xf;
-
-       pr_emerg("Bus Unit Error");
-
-       if (xec == 0x1)
-               pr_cont(" in the write data buffers.\n");
-       else if (xec == 0x3)
-               pr_cont(" in the victim data buffers.\n");
-       else if (xec == 0x2 && MEM_ERROR(ec))
-               pr_cont(": %s error in the L2 cache tags.\n", RRRR_MSG(ec));
-       else if (xec == 0x0) {
-               if (TLB_ERROR(ec))
-                       pr_cont(": %s error in a Page Descriptor Cache or "
-                               "Guest TLB.\n", TT_MSG(ec));
-               else if (BUS_ERROR(ec))
-                       pr_cont(": %s/ECC error in data read from NB: %s.\n",
-                               RRRR_MSG(ec), PP_MSG(ec));
-               else if (MEM_ERROR(ec)) {
-                       u8 rrrr = (ec >> 4) & 0xf;
-
-                       if (rrrr >= 0x7)
-                               pr_cont(": %s error during data copyback.\n",
-                                       RRRR_MSG(ec));
-                       else if (rrrr <= 0x1)
-                               pr_cont(": %s parity/ECC error during data "
-                                       "access from L2.\n", RRRR_MSG(ec));
-                       else
-                               goto wrong_bu_mce;
-               } else
-                       goto wrong_bu_mce;
-       } else
-               goto wrong_bu_mce;
-
-       return;
-
-wrong_bu_mce:
-       pr_warning("Corrupted BU MCE info?\n");
-}
-
-static void amd_decode_ls_mce(u64 mc3_status)
-{
-       u32 ec  = mc3_status & 0xffff;
-       u32 xec = (mc3_status >> 16) & 0xf;
-
-       pr_emerg("Load Store Error");
-
-       if (xec == 0x0) {
-               u8 rrrr = (ec >> 4) & 0xf;
-
-               if (!BUS_ERROR(ec) || (rrrr != 0x3 && rrrr != 0x4))
-                       goto wrong_ls_mce;
-
-               pr_cont(" during %s.\n", RRRR_MSG(ec));
-       }
-       return;
-
-wrong_ls_mce:
-       pr_warning("Corrupted LS MCE info?\n");
-}
-
-void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors)
-{
-       u32 ec  = ERROR_CODE(regs->nbsl);
-
-       if (!handle_errors)
-               return;
-
-       /*
-        * GART TLB error reporting is disabled by default. Bail out early.
-        */
-       if (TLB_ERROR(ec) && !report_gart_errors)
-               return;
-
-       pr_emerg("Northbridge Error, node %d", node_id);
-
-       /*
-        * F10h, revD can disable ErrCpu[3:0] so check that first and also the
-        * value encoding has changed so interpret those differently
-        */
-       if ((boot_cpu_data.x86 == 0x10) &&
-           (boot_cpu_data.x86_model > 7)) {
-               if (regs->nbsh & K8_NBSH_ERR_CPU_VAL)
-                       pr_cont(", core: %u\n", (u8)(regs->nbsh & 0xf));
-       } else {
-               u8 assoc_cpus = regs->nbsh & 0xf;
-
-               if (assoc_cpus > 0)
-                       pr_cont(", core: %d", fls(assoc_cpus) - 1);
-
-               pr_cont("\n");
-       }
-
-       pr_emerg("%s.\n", EXT_ERR_MSG(regs->nbsl));
-
-       if (BUS_ERROR(ec) && nb_bus_decoder)
-               nb_bus_decoder(node_id, regs);
-}
-EXPORT_SYMBOL_GPL(amd_decode_nb_mce);
-
-static void amd_decode_fr_mce(u64 mc5_status)
-{
-       /* we have only one error signature so match all fields at once. */
-       if ((mc5_status & 0xffff) == 0x0f0f)
-               pr_emerg(" FR Error: CPU Watchdog timer expire.\n");
-       else
-               pr_warning("Corrupted FR MCE info?\n");
-}
-
-static inline void amd_decode_err_code(unsigned int ec)
-{
-       if (TLB_ERROR(ec)) {
-               pr_emerg("Transaction: %s, Cache Level %s\n",
-                        TT_MSG(ec), LL_MSG(ec));
-       } else if (MEM_ERROR(ec)) {
-               pr_emerg("Transaction: %s, Type: %s, Cache Level: %s",
-                        RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec));
-       } else if (BUS_ERROR(ec)) {
-               pr_emerg("Transaction type: %s(%s), %s, Cache Level: %s, "
-                        "Participating Processor: %s\n",
-                         RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec),
-                         PP_MSG(ec));
-       } else
-               pr_warning("Huh? Unknown MCE error 0x%x\n", ec);
-}
-
-static int amd_decode_mce(struct notifier_block *nb, unsigned long val,
-                          void *data)
-{
-       struct mce *m = (struct mce *)data;
-       struct err_regs regs;
-       int node, ecc;
-
-       pr_emerg("MC%d_STATUS: ", m->bank);
-
-       pr_cont("%sorrected error, other errors lost: %s, "
-                "CPU context corrupt: %s",
-                ((m->status & MCI_STATUS_UC) ? "Unc"  : "C"),
-                ((m->status & MCI_STATUS_OVER) ? "yes"  : "no"),
-                ((m->status & MCI_STATUS_PCC) ? "yes" : "no"));
-
-       /* do the two bits[14:13] together */
-       ecc = (m->status >> 45) & 0x3;
-       if (ecc)
-               pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U"));
-
-       pr_cont("\n");
-
-       switch (m->bank) {
-       case 0:
-               amd_decode_dc_mce(m->status);
-               break;
-
-       case 1:
-               amd_decode_ic_mce(m->status);
-               break;
-
-       case 2:
-               amd_decode_bu_mce(m->status);
-               break;
-
-       case 3:
-               amd_decode_ls_mce(m->status);
-               break;
-
-       case 4:
-               regs.nbsl  = (u32) m->status;
-               regs.nbsh  = (u32)(m->status >> 32);
-               regs.nbeal = (u32) m->addr;
-               regs.nbeah = (u32)(m->addr >> 32);
-               node       = amd_get_nb_id(m->extcpu);
-
-               amd_decode_nb_mce(node, &regs, 1);
-               break;
-
-       case 5:
-               amd_decode_fr_mce(m->status);
-               break;
-
-       default:
-               break;
-       }
-
-       amd_decode_err_code(m->status & 0xffff);
-
-       return NOTIFY_STOP;
-}
-
-static struct notifier_block amd_mce_dec_nb = {
-       .notifier_call  = amd_decode_mce,
-};
-
-static int __init mce_amd_init(void)
-{
-       /*
-        * We can decode MCEs for K8, F10h and F11h CPUs:
-        */
-       if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
-               return 0;
-
-       if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
-               return 0;
-
-       atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb);
-
-       return 0;
-}
-early_initcall(mce_amd_init);
-
-#ifdef MODULE
-static void __exit mce_amd_exit(void)
-{
-       atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb);
-}
-
-MODULE_DESCRIPTION("AMD MCE decoder");
-MODULE_ALIAS("edac-mce-amd");
-MODULE_LICENSE("GPL");
-module_exit(mce_amd_exit);
-#endif
index 7e1374afd967256054be17b687954151576d60ae..be4b075c30984c1b408246a306664c0a6bb626f0 100644 (file)
@@ -26,15 +26,6 @@ EXPORT_SYMBOL_GPL(edac_debug_level);
 /* scope is to module level only */
 struct workqueue_struct *edac_workqueue;
 
-/*
- * sysfs object: /sys/devices/system/edac
- *     need to export to other files in this modules
- */
-static struct sysdev_class edac_class = {
-       .name = "edac",
-};
-static int edac_class_valid;
-
 /*
  * edac_op_state_to_string()
  */
@@ -54,60 +45,6 @@ char *edac_op_state_to_string(int opstate)
        return "UNKNOWN";
 }
 
-/*
- * edac_get_edac_class()
- *
- *     return pointer to the edac class of 'edac'
- */
-struct sysdev_class *edac_get_edac_class(void)
-{
-       struct sysdev_class *classptr = NULL;
-
-       if (edac_class_valid)
-               classptr = &edac_class;
-
-       return classptr;
-}
-
-/*
- * edac_register_sysfs_edac_name()
- *
- *     register the 'edac' into /sys/devices/system
- *
- * return:
- *     0  success
- *     !0 error
- */
-static int edac_register_sysfs_edac_name(void)
-{
-       int err;
-
-       /* create the /sys/devices/system/edac directory */
-       err = sysdev_class_register(&edac_class);
-
-       if (err) {
-               debugf1("%s() error=%d\n", __func__, err);
-               return err;
-       }
-
-       edac_class_valid = 1;
-       return 0;
-}
-
-/*
- * sysdev_class_unregister()
- *
- *     unregister the 'edac' from /sys/devices/system
- */
-static void edac_unregister_sysfs_edac_name(void)
-{
-       /* only if currently registered, then unregister it */
-       if (edac_class_valid)
-               sysdev_class_unregister(&edac_class);
-
-       edac_class_valid = 0;
-}
-
 /*
  * edac_workqueue_setup
  *     initialize the edac work queue for polling operations
@@ -153,22 +90,12 @@ static int __init edac_init(void)
         */
        edac_pci_clear_parity_errors();
 
-       /*
-        * perform the registration of the /sys/devices/system/edac class object
-        */
-       if (edac_register_sysfs_edac_name()) {
-               edac_printk(KERN_ERR, EDAC_MC,
-                       "Error initializing 'edac' kobject\n");
-               err = -ENODEV;
-               goto error;
-       }
-
        /*
         * now set up the mc_kset under the edac class object
         */
        err = edac_sysfs_setup_mc_kset();
        if (err)
-               goto sysfs_setup_fail;
+               goto error;
 
        /* Setup/Initialize the workq for this core */
        err = edac_workqueue_setup();
@@ -183,9 +110,6 @@ static int __init edac_init(void)
 workq_fail:
        edac_sysfs_teardown_mc_kset();
 
-sysfs_setup_fail:
-       edac_unregister_sysfs_edac_name();
-
 error:
        return err;
 }
@@ -201,7 +125,6 @@ static void __exit edac_exit(void)
        /* tear down the various subsystems */
        edac_workqueue_teardown();
        edac_sysfs_teardown_mc_kset();
-       edac_unregister_sysfs_edac_name();
 }
 
 /*
index 233d4798c3aa2ecf18f3875d45a138b8bc2f2fe8..17aabb7b90ecff1ac09a7344ea9fe17a86fb9c8a 100644 (file)
@@ -42,7 +42,6 @@ extern void edac_device_unregister_sysfs_main_kobj(
                                struct edac_device_ctl_info *edac_dev);
 extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
 extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
-extern struct sysdev_class *edac_get_edac_class(void);
 
 /* edac core workqueue: single CPU mode */
 extern struct workqueue_struct *edac_workqueue;
index c39697df9cb41e87c8177c76bab788b85567003e..023b01cb5175c70a15804faba0c356ecacfb1809 100644 (file)
@@ -7,7 +7,7 @@
  *
  */
 #include <linux/module.h>
-#include <linux/sysdev.h>
+#include <linux/edac.h>
 #include <linux/slab.h>
 #include <linux/ctype.h>
 
@@ -354,7 +354,7 @@ static int edac_pci_main_kobj_setup(void)
        /* First time, so create the main kobject and its
         * controls and atributes
         */
-       edac_class = edac_get_edac_class();
+       edac_class = edac_get_sysfs_class();
        if (edac_class == NULL) {
                debugf1("%s() no edac_class\n", __func__);
                err = -ENODEV;
@@ -368,7 +368,7 @@ static int edac_pci_main_kobj_setup(void)
        if (!try_module_get(THIS_MODULE)) {
                debugf1("%s() try_module_get() failed\n", __func__);
                err = -ENODEV;
-               goto decrement_count_fail;
+               goto mod_get_fail;
        }
 
        edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
@@ -403,6 +403,9 @@ kobject_init_and_add_fail:
 kzalloc_fail:
        module_put(THIS_MODULE);
 
+mod_get_fail:
+       edac_put_sysfs_class();
+
 decrement_count_fail:
        /* if are on this error exit, nothing to tear down */
        atomic_dec(&edac_pci_sysfs_refcount);
@@ -429,6 +432,7 @@ static void edac_pci_main_kobj_teardown(void)
                        __func__);
                kobject_put(edac_pci_top_main_kobj);
        }
+       edac_put_sysfs_class();
 }
 
 /*
index 20b428aa155e144413aeaeed2928b059ebd659d4..aab970760b755b4a5e3f848829bcbd74b3122a37 100644 (file)
@@ -3,10 +3,13 @@
  *
  * Author: Dave Jiang <djiang@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.
+ * 2007 (c) MontaVista Software, Inc.
+ * 2010 (c) Advanced Micro Devices Inc.
+ *         Borislav Petkov <borislav.petkov@amd.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>
@@ -23,6 +26,8 @@ EXPORT_SYMBOL_GPL(edac_handlers);
 int edac_err_assert = 0;
 EXPORT_SYMBOL_GPL(edac_err_assert);
 
+static atomic_t edac_class_valid = ATOMIC_INIT(0);
+
 /*
  * called to determine if there is an EDAC driver interested in
  * knowing an event (such as NMI) occurred
@@ -44,3 +49,41 @@ void edac_atomic_assert_error(void)
        edac_err_assert++;
 }
 EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
+
+/*
+ * sysfs object: /sys/devices/system/edac
+ *     need to export to other files
+ */
+struct sysdev_class edac_class = {
+       .name = "edac",
+};
+EXPORT_SYMBOL_GPL(edac_class);
+
+/* return pointer to the 'edac' node in sysfs */
+struct sysdev_class *edac_get_sysfs_class(void)
+{
+       int err = 0;
+
+       if (atomic_read(&edac_class_valid))
+               goto out;
+
+       /* create the /sys/devices/system/edac directory */
+       err = sysdev_class_register(&edac_class);
+       if (err) {
+               printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n");
+               return NULL;
+       }
+
+out:
+       atomic_inc(&edac_class_valid);
+       return &edac_class;
+}
+EXPORT_SYMBOL_GPL(edac_get_sysfs_class);
+
+void edac_put_sysfs_class(void)
+{
+       /* last user unregisters it */
+       if (atomic_dec_and_test(&edac_class_valid))
+               sysdev_class_unregister(&edac_class);
+}
+EXPORT_SYMBOL_GPL(edac_put_sysfs_class);
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
new file mode 100644 (file)
index 0000000..c018109
--- /dev/null
@@ -0,0 +1,680 @@
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "mce_amd.h"
+
+static struct amd_decoder_ops *fam_ops;
+
+static u8 nb_err_cpumask = 0xf;
+
+static bool report_gart_errors;
+static void (*nb_bus_decoder)(int node_id, struct mce *m, u32 nbcfg);
+
+void amd_report_gart_errors(bool v)
+{
+       report_gart_errors = v;
+}
+EXPORT_SYMBOL_GPL(amd_report_gart_errors);
+
+void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32))
+{
+       nb_bus_decoder = f;
+}
+EXPORT_SYMBOL_GPL(amd_register_ecc_decoder);
+
+void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32))
+{
+       if (nb_bus_decoder) {
+               WARN_ON(nb_bus_decoder != f);
+
+               nb_bus_decoder = NULL;
+       }
+}
+EXPORT_SYMBOL_GPL(amd_unregister_ecc_decoder);
+
+/*
+ * string representation for the different MCA reported error types, see F3x48
+ * or MSR0000_0411.
+ */
+
+/* transaction type */
+const char *tt_msgs[] = { "INSN", "DATA", "GEN", "RESV" };
+EXPORT_SYMBOL_GPL(tt_msgs);
+
+/* cache level */
+const char *ll_msgs[] = { "RESV", "L1", "L2", "L3/GEN" };
+EXPORT_SYMBOL_GPL(ll_msgs);
+
+/* memory transaction type */
+const char *rrrr_msgs[] = {
+       "GEN", "RD", "WR", "DRD", "DWR", "IRD", "PRF", "EV", "SNP"
+};
+EXPORT_SYMBOL_GPL(rrrr_msgs);
+
+/* participating processor */
+const char *pp_msgs[] = { "SRC", "RES", "OBS", "GEN" };
+EXPORT_SYMBOL_GPL(pp_msgs);
+
+/* request timeout */
+const char *to_msgs[] = { "no timeout",        "timed out" };
+EXPORT_SYMBOL_GPL(to_msgs);
+
+/* memory or i/o */
+const char *ii_msgs[] = { "MEM", "RESV", "IO", "GEN" };
+EXPORT_SYMBOL_GPL(ii_msgs);
+
+static const char *f10h_nb_mce_desc[] = {
+       "HT link data error",
+       "Protocol error (link, L3, probe filter, etc.)",
+       "Parity error in NB-internal arrays",
+       "Link Retry due to IO link transmission error",
+       "L3 ECC data cache error",
+       "ECC error in L3 cache tag",
+       "L3 LRU parity bits error",
+       "ECC Error in the Probe Filter directory"
+};
+
+static bool f12h_dc_mce(u16 ec)
+{
+       bool ret = false;
+
+       if (MEM_ERROR(ec)) {
+               u8 ll = ec & 0x3;
+               ret = true;
+
+               if (ll == LL_L2)
+                       pr_cont("during L1 linefill from L2.\n");
+               else if (ll == LL_L1)
+                       pr_cont("Data/Tag %s error.\n", RRRR_MSG(ec));
+               else
+                       ret = false;
+       }
+       return ret;
+}
+
+static bool f10h_dc_mce(u16 ec)
+{
+       u8 r4  = (ec >> 4) & 0xf;
+       u8 ll  = ec & 0x3;
+
+       if (r4 == R4_GEN && ll == LL_L1) {
+               pr_cont("during data scrub.\n");
+               return true;
+       }
+       return f12h_dc_mce(ec);
+}
+
+static bool k8_dc_mce(u16 ec)
+{
+       if (BUS_ERROR(ec)) {
+               pr_cont("during system linefill.\n");
+               return true;
+       }
+
+       return f10h_dc_mce(ec);
+}
+
+static bool f14h_dc_mce(u16 ec)
+{
+       u8 r4    = (ec >> 4) & 0xf;
+       u8 ll    = ec & 0x3;
+       u8 tt    = (ec >> 2) & 0x3;
+       u8 ii    = tt;
+       bool ret = true;
+
+       if (MEM_ERROR(ec)) {
+
+               if (tt != TT_DATA || ll != LL_L1)
+                       return false;
+
+               switch (r4) {
+               case R4_DRD:
+               case R4_DWR:
+                       pr_cont("Data/Tag parity error due to %s.\n",
+                               (r4 == R4_DRD ? "load/hw prf" : "store"));
+                       break;
+               case R4_EVICT:
+                       pr_cont("Copyback parity error on a tag miss.\n");
+                       break;
+               case R4_SNOOP:
+                       pr_cont("Tag parity error during snoop.\n");
+                       break;
+               default:
+                       ret = false;
+               }
+       } else if (BUS_ERROR(ec)) {
+
+               if ((ii != II_MEM && ii != II_IO) || ll != LL_LG)
+                       return false;
+
+               pr_cont("System read data error on a ");
+
+               switch (r4) {
+               case R4_RD:
+                       pr_cont("TLB reload.\n");
+                       break;
+               case R4_DWR:
+                       pr_cont("store.\n");
+                       break;
+               case R4_DRD:
+                       pr_cont("load.\n");
+                       break;
+               default:
+                       ret = false;
+               }
+       } else {
+               ret = false;
+       }
+
+       return ret;
+}
+
+static void amd_decode_dc_mce(struct mce *m)
+{
+       u16 ec = m->status & 0xffff;
+       u8 xec = (m->status >> 16) & 0xf;
+
+       pr_emerg(HW_ERR "Data Cache Error: ");
+
+       /* TLB error signatures are the same across families */
+       if (TLB_ERROR(ec)) {
+               u8 tt = (ec >> 2) & 0x3;
+
+               if (tt == TT_DATA) {
+                       pr_cont("%s TLB %s.\n", LL_MSG(ec),
+                               (xec ? "multimatch" : "parity error"));
+                       return;
+               }
+               else
+                       goto wrong_dc_mce;
+       }
+
+       if (!fam_ops->dc_mce(ec))
+               goto wrong_dc_mce;
+
+       return;
+
+wrong_dc_mce:
+       pr_emerg(HW_ERR "Corrupted DC MCE info?\n");
+}
+
+static bool k8_ic_mce(u16 ec)
+{
+       u8 ll    = ec & 0x3;
+       u8 r4    = (ec >> 4) & 0xf;
+       bool ret = true;
+
+       if (!MEM_ERROR(ec))
+               return false;
+
+       if (ll == 0x2)
+               pr_cont("during a linefill from L2.\n");
+       else if (ll == 0x1) {
+               switch (r4) {
+               case R4_IRD:
+                       pr_cont("Parity error during data load.\n");
+                       break;
+
+               case R4_EVICT:
+                       pr_cont("Copyback Parity/Victim error.\n");
+                       break;
+
+               case R4_SNOOP:
+                       pr_cont("Tag Snoop error.\n");
+                       break;
+
+               default:
+                       ret = false;
+                       break;
+               }
+       } else
+               ret = false;
+
+       return ret;
+}
+
+static bool f14h_ic_mce(u16 ec)
+{
+       u8 ll    = ec & 0x3;
+       u8 tt    = (ec >> 2) & 0x3;
+       u8 r4  = (ec >> 4) & 0xf;
+       bool ret = true;
+
+       if (MEM_ERROR(ec)) {
+               if (tt != 0 || ll != 1)
+                       ret = false;
+
+               if (r4 == R4_IRD)
+                       pr_cont("Data/tag array parity error for a tag hit.\n");
+               else if (r4 == R4_SNOOP)
+                       pr_cont("Tag error during snoop/victimization.\n");
+               else
+                       ret = false;
+       }
+       return ret;
+}
+
+static void amd_decode_ic_mce(struct mce *m)
+{
+       u16 ec = m->status & 0xffff;
+       u8 xec = (m->status >> 16) & 0xf;
+
+       pr_emerg(HW_ERR "Instruction Cache Error: ");
+
+       if (TLB_ERROR(ec))
+               pr_cont("%s TLB %s.\n", LL_MSG(ec),
+                       (xec ? "multimatch" : "parity error"));
+       else if (BUS_ERROR(ec)) {
+               bool k8 = (boot_cpu_data.x86 == 0xf && (m->status & BIT_64(58)));
+
+               pr_cont("during %s.\n", (k8 ? "system linefill" : "NB data read"));
+       } else if (fam_ops->ic_mce(ec))
+               ;
+       else
+               pr_emerg(HW_ERR "Corrupted IC MCE info?\n");
+}
+
+static void amd_decode_bu_mce(struct mce *m)
+{
+       u32 ec = m->status & 0xffff;
+       u32 xec = (m->status >> 16) & 0xf;
+
+       pr_emerg(HW_ERR "Bus Unit Error");
+
+       if (xec == 0x1)
+               pr_cont(" in the write data buffers.\n");
+       else if (xec == 0x3)
+               pr_cont(" in the victim data buffers.\n");
+       else if (xec == 0x2 && MEM_ERROR(ec))
+               pr_cont(": %s error in the L2 cache tags.\n", RRRR_MSG(ec));
+       else if (xec == 0x0) {
+               if (TLB_ERROR(ec))
+                       pr_cont(": %s error in a Page Descriptor Cache or "
+                               "Guest TLB.\n", TT_MSG(ec));
+               else if (BUS_ERROR(ec))
+                       pr_cont(": %s/ECC error in data read from NB: %s.\n",
+                               RRRR_MSG(ec), PP_MSG(ec));
+               else if (MEM_ERROR(ec)) {
+                       u8 rrrr = (ec >> 4) & 0xf;
+
+                       if (rrrr >= 0x7)
+                               pr_cont(": %s error during data copyback.\n",
+                                       RRRR_MSG(ec));
+                       else if (rrrr <= 0x1)
+                               pr_cont(": %s parity/ECC error during data "
+                                       "access from L2.\n", RRRR_MSG(ec));
+                       else
+                               goto wrong_bu_mce;
+               } else
+                       goto wrong_bu_mce;
+       } else
+               goto wrong_bu_mce;
+
+       return;
+
+wrong_bu_mce:
+       pr_emerg(HW_ERR "Corrupted BU MCE info?\n");
+}
+
+static void amd_decode_ls_mce(struct mce *m)
+{
+       u16 ec = m->status & 0xffff;
+       u8 xec = (m->status >> 16) & 0xf;
+
+       if (boot_cpu_data.x86 == 0x14) {
+               pr_emerg("You shouldn't be seeing an LS MCE on this cpu family,"
+                        " please report on LKML.\n");
+               return;
+       }
+
+       pr_emerg(HW_ERR "Load Store Error");
+
+       if (xec == 0x0) {
+               u8 r4 = (ec >> 4) & 0xf;
+
+               if (!BUS_ERROR(ec) || (r4 != R4_DRD && r4 != R4_DWR))
+                       goto wrong_ls_mce;
+
+               pr_cont(" during %s.\n", RRRR_MSG(ec));
+       } else
+               goto wrong_ls_mce;
+
+       return;
+
+wrong_ls_mce:
+       pr_emerg(HW_ERR "Corrupted LS MCE info?\n");
+}
+
+static bool k8_nb_mce(u16 ec, u8 xec)
+{
+       bool ret = true;
+
+       switch (xec) {
+       case 0x1:
+               pr_cont("CRC error detected on HT link.\n");
+               break;
+
+       case 0x5:
+               pr_cont("Invalid GART PTE entry during GART table walk.\n");
+               break;
+
+       case 0x6:
+               pr_cont("Unsupported atomic RMW received from an IO link.\n");
+               break;
+
+       case 0x0:
+       case 0x8:
+               if (boot_cpu_data.x86 == 0x11)
+                       return false;
+
+               pr_cont("DRAM ECC error detected on the NB.\n");
+               break;
+
+       case 0xd:
+               pr_cont("Parity error on the DRAM addr/ctl signals.\n");
+               break;
+
+       default:
+               ret = false;
+               break;
+       }
+
+       return ret;
+}
+
+static bool f10h_nb_mce(u16 ec, u8 xec)
+{
+       bool ret = true;
+       u8 offset = 0;
+
+       if (k8_nb_mce(ec, xec))
+               return true;
+
+       switch(xec) {
+       case 0xa ... 0xc:
+               offset = 10;
+               break;
+
+       case 0xe:
+               offset = 11;
+               break;
+
+       case 0xf:
+               if (TLB_ERROR(ec))
+                       pr_cont("GART Table Walk data error.\n");
+               else if (BUS_ERROR(ec))
+                       pr_cont("DMA Exclusion Vector Table Walk error.\n");
+               else
+                       ret = false;
+
+               goto out;
+               break;
+
+       case 0x1c ... 0x1f:
+               offset = 24;
+               break;
+
+       default:
+               ret = false;
+
+               goto out;
+               break;
+       }
+
+       pr_cont("%s.\n", f10h_nb_mce_desc[xec - offset]);
+
+out:
+       return ret;
+}
+
+static bool nb_noop_mce(u16 ec, u8 xec)
+{
+       return false;
+}
+
+void amd_decode_nb_mce(int node_id, struct mce *m, u32 nbcfg)
+{
+       u8 xec   = (m->status >> 16) & 0x1f;
+       u16 ec   = m->status & 0xffff;
+       u32 nbsh = (u32)(m->status >> 32);
+
+       pr_emerg(HW_ERR "Northbridge Error, node %d: ", node_id);
+
+       /*
+        * F10h, revD can disable ErrCpu[3:0] so check that first and also the
+        * value encoding has changed so interpret those differently
+        */
+       if ((boot_cpu_data.x86 == 0x10) &&
+           (boot_cpu_data.x86_model > 7)) {
+               if (nbsh & K8_NBSH_ERR_CPU_VAL)
+                       pr_cont(", core: %u", (u8)(nbsh & nb_err_cpumask));
+       } else {
+               u8 assoc_cpus = nbsh & nb_err_cpumask;
+
+               if (assoc_cpus > 0)
+                       pr_cont(", core: %d", fls(assoc_cpus) - 1);
+       }
+
+       switch (xec) {
+       case 0x2:
+               pr_cont("Sync error (sync packets on HT link detected).\n");
+               return;
+
+       case 0x3:
+               pr_cont("HT Master abort.\n");
+               return;
+
+       case 0x4:
+               pr_cont("HT Target abort.\n");
+               return;
+
+       case 0x7:
+               pr_cont("NB Watchdog timeout.\n");
+               return;
+
+       case 0x9:
+               pr_cont("SVM DMA Exclusion Vector error.\n");
+               return;
+
+       default:
+               break;
+       }
+
+       if (!fam_ops->nb_mce(ec, xec))
+               goto wrong_nb_mce;
+
+       if (boot_cpu_data.x86 == 0xf || boot_cpu_data.x86 == 0x10)
+               if ((xec == 0x8 || xec == 0x0) && nb_bus_decoder)
+                       nb_bus_decoder(node_id, m, nbcfg);
+
+       return;
+
+wrong_nb_mce:
+       pr_emerg(HW_ERR "Corrupted NB MCE info?\n");
+}
+EXPORT_SYMBOL_GPL(amd_decode_nb_mce);
+
+static void amd_decode_fr_mce(struct mce *m)
+{
+       if (boot_cpu_data.x86 == 0xf ||
+           boot_cpu_data.x86 == 0x11)
+               goto wrong_fr_mce;
+
+       /* we have only one error signature so match all fields at once. */
+       if ((m->status & 0xffff) == 0x0f0f) {
+               pr_emerg(HW_ERR "FR Error: CPU Watchdog timer expire.\n");
+               return;
+       }
+
+wrong_fr_mce:
+       pr_emerg(HW_ERR "Corrupted FR MCE info?\n");
+}
+
+static inline void amd_decode_err_code(u16 ec)
+{
+       if (TLB_ERROR(ec)) {
+               pr_emerg(HW_ERR "Transaction: %s, Cache Level: %s\n",
+                        TT_MSG(ec), LL_MSG(ec));
+       } else if (MEM_ERROR(ec)) {
+               pr_emerg(HW_ERR "Transaction: %s, Type: %s, Cache Level: %s\n",
+                        RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec));
+       } else if (BUS_ERROR(ec)) {
+               pr_emerg(HW_ERR "Transaction: %s (%s), %s, Cache Level: %s, "
+                        "Participating Processor: %s\n",
+                         RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec),
+                         PP_MSG(ec));
+       } else
+               pr_emerg(HW_ERR "Huh? Unknown MCE error 0x%x\n", ec);
+}
+
+/*
+ * Filter out unwanted MCE signatures here.
+ */
+static bool amd_filter_mce(struct mce *m)
+{
+       u8 xec = (m->status >> 16) & 0x1f;
+
+       /*
+        * NB GART TLB error reporting is disabled by default.
+        */
+       if (m->bank == 4 && xec == 0x5 && !report_gart_errors)
+               return true;
+
+       return false;
+}
+
+int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
+{
+       struct mce *m = (struct mce *)data;
+       int node, ecc;
+
+       if (amd_filter_mce(m))
+               return NOTIFY_STOP;
+
+       pr_emerg(HW_ERR "MC%d_STATUS: ", m->bank);
+
+       pr_cont("%sorrected error, other errors lost: %s, "
+                "CPU context corrupt: %s",
+                ((m->status & MCI_STATUS_UC) ? "Unc"  : "C"),
+                ((m->status & MCI_STATUS_OVER) ? "yes"  : "no"),
+                ((m->status & MCI_STATUS_PCC) ? "yes" : "no"));
+
+       /* do the two bits[14:13] together */
+       ecc = (m->status >> 45) & 0x3;
+       if (ecc)
+               pr_cont(", %sECC Error", ((ecc == 2) ? "C" : "U"));
+
+       pr_cont("\n");
+
+       switch (m->bank) {
+       case 0:
+               amd_decode_dc_mce(m);
+               break;
+
+       case 1:
+               amd_decode_ic_mce(m);
+               break;
+
+       case 2:
+               amd_decode_bu_mce(m);
+               break;
+
+       case 3:
+               amd_decode_ls_mce(m);
+               break;
+
+       case 4:
+               node = amd_get_nb_id(m->extcpu);
+               amd_decode_nb_mce(node, m, 0);
+               break;
+
+       case 5:
+               amd_decode_fr_mce(m);
+               break;
+
+       default:
+               break;
+       }
+
+       amd_decode_err_code(m->status & 0xffff);
+
+       return NOTIFY_STOP;
+}
+EXPORT_SYMBOL_GPL(amd_decode_mce);
+
+static struct notifier_block amd_mce_dec_nb = {
+       .notifier_call  = amd_decode_mce,
+};
+
+static int __init mce_amd_init(void)
+{
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+               return 0;
+
+       if ((boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x12) &&
+           (boot_cpu_data.x86 != 0x14 || boot_cpu_data.x86_model > 0xf))
+               return 0;
+
+       fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL);
+       if (!fam_ops)
+               return -ENOMEM;
+
+       switch (boot_cpu_data.x86) {
+       case 0xf:
+               fam_ops->dc_mce = k8_dc_mce;
+               fam_ops->ic_mce = k8_ic_mce;
+               fam_ops->nb_mce = k8_nb_mce;
+               break;
+
+       case 0x10:
+               fam_ops->dc_mce = f10h_dc_mce;
+               fam_ops->ic_mce = k8_ic_mce;
+               fam_ops->nb_mce = f10h_nb_mce;
+               break;
+
+       case 0x11:
+               fam_ops->dc_mce = k8_dc_mce;
+               fam_ops->ic_mce = k8_ic_mce;
+               fam_ops->nb_mce = f10h_nb_mce;
+               break;
+
+       case 0x12:
+               fam_ops->dc_mce = f12h_dc_mce;
+               fam_ops->ic_mce = k8_ic_mce;
+               fam_ops->nb_mce = nb_noop_mce;
+               break;
+
+       case 0x14:
+               nb_err_cpumask  = 0x3;
+               fam_ops->dc_mce = f14h_dc_mce;
+               fam_ops->ic_mce = f14h_ic_mce;
+               fam_ops->nb_mce = nb_noop_mce;
+               break;
+
+       default:
+               printk(KERN_WARNING "Huh? What family is that: %d?!\n",
+                                   boot_cpu_data.x86);
+               kfree(fam_ops);
+               return -EINVAL;
+       }
+
+       pr_info("MCE: In-kernel MCE decoding enabled.\n");
+
+       atomic_notifier_chain_register(&x86_mce_decoder_chain, &amd_mce_dec_nb);
+
+       return 0;
+}
+early_initcall(mce_amd_init);
+
+#ifdef MODULE
+static void __exit mce_amd_exit(void)
+{
+       atomic_notifier_chain_unregister(&x86_mce_decoder_chain, &amd_mce_dec_nb);
+       kfree(fam_ops);
+}
+
+MODULE_DESCRIPTION("AMD MCE decoder");
+MODULE_ALIAS("edac-mce-amd");
+MODULE_LICENSE("GPL");
+module_exit(mce_amd_exit);
+#endif
similarity index 65%
rename from drivers/edac/edac_mce_amd.h
rename to drivers/edac/mce_amd.h
index df23ee065f7981fe9f4084b461efa1de0f5d6836..35f6e0e3b297de16ad5e7c0ccac18dae0c388590 100644 (file)
@@ -1,11 +1,14 @@
 #ifndef _EDAC_MCE_AMD_H
 #define _EDAC_MCE_AMD_H
 
+#include <linux/notifier.h>
+
 #include <asm/mce.h>
 
+#define BIT_64(n)                      (U64_C(1) << (n))
+
 #define ERROR_CODE(x)                  ((x) & 0xffff)
 #define EXT_ERROR_CODE(x)              (((x) >> 16) & 0x1f)
-#define EXT_ERR_MSG(x)                 ext_msgs[EXT_ERROR_CODE(x)]
 
 #define LOW_SYNDROME(x)                        (((x) >> 15) & 0xff)
 #define HIGH_SYNDROME(x)               (((x) >> 24) & 0xff)
 #define II_MSG(x)                      ii_msgs[II(x)]
 #define LL(x)                          (((x) >> 0) & 0x3)
 #define LL_MSG(x)                      ll_msgs[LL(x)]
-#define RRRR(x)                                (((x) >> 4) & 0xf)
-#define RRRR_MSG(x)                    rrrr_msgs[RRRR(x)]
 #define TO(x)                          (((x) >> 8) & 0x1)
 #define TO_MSG(x)                      to_msgs[TO(x)]
 #define PP(x)                          (((x) >> 9) & 0x3)
 #define PP_MSG(x)                      pp_msgs[PP(x)]
 
+#define RRRR(x)                                (((x) >> 4) & 0xf)
+#define RRRR_MSG(x)                    ((RRRR(x) < 9) ?  rrrr_msgs[RRRR(x)] : "Wrong R4!")
+
 #define K8_NBSH                                0x4C
 
 #define K8_NBSH_VALID_BIT              BIT(31)
 #define K8_NBSH_UECC                   BIT(13)
 #define K8_NBSH_ERR_SCRUBER            BIT(8)
 
+enum tt_ids {
+       TT_INSTR = 0,
+       TT_DATA,
+       TT_GEN,
+       TT_RESV,
+};
+
+enum ll_ids {
+       LL_RESV = 0,
+       LL_L1,
+       LL_L2,
+       LL_LG,
+};
+
+enum ii_ids {
+       II_MEM = 0,
+       II_RESV,
+       II_IO,
+       II_GEN,
+};
+
+enum rrrr_ids {
+       R4_GEN  = 0,
+       R4_RD,
+       R4_WR,
+       R4_DRD,
+       R4_DWR,
+       R4_IRD,
+       R4_PREF,
+       R4_EVICT,
+       R4_SNOOP,
+};
+
 extern const char *tt_msgs[];
 extern const char *ll_msgs[];
 extern const char *rrrr_msgs[];
 extern const char *pp_msgs[];
 extern const char *to_msgs[];
 extern const char *ii_msgs[];
-extern const char *ext_msgs[];
 
 /*
  * relevant NB regs
@@ -60,10 +96,19 @@ struct err_regs {
        u32 nbeal;
 };
 
+/*
+ * per-family decoder ops
+ */
+struct amd_decoder_ops {
+       bool (*dc_mce)(u16);
+       bool (*ic_mce)(u16);
+       bool (*nb_mce)(u16, u8);
+};
 
 void amd_report_gart_errors(bool);
-void amd_register_ecc_decoder(void (*f)(int, struct err_regs *));
-void amd_unregister_ecc_decoder(void (*f)(int, struct err_regs *));
-void amd_decode_nb_mce(int, struct err_regs *, int);
+void amd_register_ecc_decoder(void (*f)(int, struct mce *, u32));
+void amd_unregister_ecc_decoder(void (*f)(int, struct mce *, u32));
+void amd_decode_nb_mce(int, struct mce *, u32);
+int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data);
 
 #endif /* _EDAC_MCE_AMD_H */
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
new file mode 100644 (file)
index 0000000..8d0688f
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * A simple MCE injection facility for testing the MCE decoding code. This
+ * driver should be built as module so that it can be loaded on production
+ * kernels for testing purposes.
+ *
+ * This file may be distributed under the terms of the GNU General Public
+ * License version 2.
+ *
+ * Copyright (c) 2010:  Borislav Petkov <borislav.petkov@amd.com>
+ *                     Advanced Micro Devices Inc.
+ */
+
+#include <linux/kobject.h>
+#include <linux/sysdev.h>
+#include <linux/edac.h>
+#include <asm/mce.h>
+
+#include "mce_amd.h"
+
+struct edac_mce_attr {
+       struct attribute attr;
+       ssize_t (*show) (struct kobject *kobj, struct edac_mce_attr *attr, char *buf);
+       ssize_t (*store)(struct kobject *kobj, struct edac_mce_attr *attr,
+                        const char *buf, size_t count);
+};
+
+#define EDAC_MCE_ATTR(_name, _mode, _show, _store)                     \
+static struct edac_mce_attr mce_attr_##_name = __ATTR(_name, _mode, _show, _store)
+
+static struct kobject *mce_kobj;
+
+/*
+ * Collect all the MCi_XXX settings
+ */
+static struct mce i_mce;
+
+#define MCE_INJECT_STORE(reg)                                          \
+static ssize_t edac_inject_##reg##_store(struct kobject *kobj,         \
+                                        struct edac_mce_attr *attr,    \
+                                        const char *data, size_t count)\
+{                                                                      \
+       int ret = 0;                                                    \
+       unsigned long value;                                            \
+                                                                       \
+       ret = strict_strtoul(data, 16, &value);                         \
+       if (ret < 0)                                                    \
+               printk(KERN_ERR "Error writing MCE " #reg " field.\n"); \
+                                                                       \
+       i_mce.reg = value;                                              \
+                                                                       \
+       return count;                                                   \
+}
+
+MCE_INJECT_STORE(status);
+MCE_INJECT_STORE(misc);
+MCE_INJECT_STORE(addr);
+
+#define MCE_INJECT_SHOW(reg)                                           \
+static ssize_t edac_inject_##reg##_show(struct kobject *kobj,          \
+                                       struct edac_mce_attr *attr,     \
+                                       char *buf)                      \
+{                                                                      \
+       return sprintf(buf, "0x%016llx\n", i_mce.reg);                  \
+}
+
+MCE_INJECT_SHOW(status);
+MCE_INJECT_SHOW(misc);
+MCE_INJECT_SHOW(addr);
+
+EDAC_MCE_ATTR(status, 0644, edac_inject_status_show, edac_inject_status_store);
+EDAC_MCE_ATTR(misc, 0644, edac_inject_misc_show, edac_inject_misc_store);
+EDAC_MCE_ATTR(addr, 0644, edac_inject_addr_show, edac_inject_addr_store);
+
+/*
+ * This denotes into which bank we're injecting and triggers
+ * the injection, at the same time.
+ */
+static ssize_t edac_inject_bank_store(struct kobject *kobj,
+                                     struct edac_mce_attr *attr,
+                                     const char *data, size_t count)
+{
+       int ret = 0;
+       unsigned long value;
+
+       ret = strict_strtoul(data, 10, &value);
+       if (ret < 0) {
+               printk(KERN_ERR "Invalid bank value!\n");
+               return -EINVAL;
+       }
+
+       if (value > 5) {
+               printk(KERN_ERR "Non-existant MCE bank: %lu\n", value);
+               return -EINVAL;
+       }
+
+       i_mce.bank = value;
+
+       amd_decode_mce(NULL, 0, &i_mce);
+
+       return count;
+}
+
+static ssize_t edac_inject_bank_show(struct kobject *kobj,
+                                    struct edac_mce_attr *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", i_mce.bank);
+}
+
+EDAC_MCE_ATTR(bank, 0644, edac_inject_bank_show, edac_inject_bank_store);
+
+static struct edac_mce_attr *sysfs_attrs[] = { &mce_attr_status, &mce_attr_misc,
+                                              &mce_attr_addr, &mce_attr_bank
+};
+
+static int __init edac_init_mce_inject(void)
+{
+       struct sysdev_class *edac_class = NULL;
+       int i, err = 0;
+
+       edac_class = edac_get_sysfs_class();
+       if (!edac_class)
+               return -EINVAL;
+
+       mce_kobj = kobject_create_and_add("mce", &edac_class->kset.kobj);
+       if (!mce_kobj) {
+               printk(KERN_ERR "Error creating a mce kset.\n");
+               err = -ENOMEM;
+               goto err_mce_kobj;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++) {
+               err = sysfs_create_file(mce_kobj, &sysfs_attrs[i]->attr);
+               if (err) {
+                       printk(KERN_ERR "Error creating %s in sysfs.\n",
+                                       sysfs_attrs[i]->attr.name);
+                       goto err_sysfs_create;
+               }
+       }
+       return 0;
+
+err_sysfs_create:
+       while (i-- >= 0)
+               sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr);
+
+       kobject_del(mce_kobj);
+
+err_mce_kobj:
+       edac_put_sysfs_class();
+
+       return err;
+}
+
+static void __exit edac_exit_mce_inject(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++)
+               sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr);
+
+       kobject_del(mce_kobj);
+
+       edac_put_sysfs_class();
+}
+
+module_init(edac_init_mce_inject);
+module_exit(edac_exit_mce_inject);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Borislav Petkov <borislav.petkov@amd.com>");
+MODULE_AUTHOR("AMD Inc.");
+MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding");
index 280c9b5ad9e375afafd3116cc75d8b6fc3eb12fd..88a3ae6cd02306784184fd3f31399da88840defd 100644 (file)
@@ -125,7 +125,7 @@ config ISCSI_IBFT_FIND
 config ISCSI_IBFT
        tristate "iSCSI Boot Firmware Table Attributes module"
        select ISCSI_BOOT_SYSFS
-       depends on ISCSI_IBFT_FIND && SCSI
+       depends on ISCSI_IBFT_FIND && SCSI && SCSI_LOWLEVEL
        default n
        help
          This option enables support for detection and exposing of iSCSI
index 1be6288780de9aad04b54aaa3976e770be8c229e..7e10c935a047553d7c9203acf00aa807b9853de4 100644 (file)
@@ -322,6 +322,9 @@ static int __devinit tc35892_gpio_probe(struct platform_device *pdev)
                goto out_freeirq;
        }
 
+       if (pdata->setup)
+               pdata->setup(tc35892, tc35892_gpio->chip.base);
+
        platform_set_drvdata(pdev, tc35892_gpio);
 
        return 0;
@@ -338,9 +341,14 @@ out_free:
 static int __devexit tc35892_gpio_remove(struct platform_device *pdev)
 {
        struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev);
+       struct tc35892 *tc35892 = tc35892_gpio->tc35892;
+       struct tc35892_gpio_platform_data *pdata = tc35892->pdata->gpio;
        int irq = platform_get_irq(pdev, 0);
        int ret;
 
+       if (pdata->remove)
+               pdata->remove(tc35892, tc35892_gpio->chip.base);
+
        ret = gpiochip_remove(&tc35892_gpio->chip);
        if (ret < 0) {
                dev_err(tc35892_gpio->dev,
index 4174101660c91430782620ce0df8895c1d3c734a..837b8c1aa02a494ef92899c46ccaf67cb709f9c1 100644 (file)
@@ -88,7 +88,7 @@ static void pasemi_smb_clear(struct pasemi_smbus *smbus)
        reg_write(smbus, REG_SMSTA, status);
 }
 
-static unsigned int pasemi_smb_waitready(struct pasemi_smbus *smbus)
+static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
 {
        int timeout = 10;
        unsigned int status;
index 2a4cb9c18f01706ce7a3c6b17126882321185612..404843e8611b158d3feb1efc5a4c281d3fde660b 100644 (file)
@@ -43,7 +43,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/cisreg.h>
@@ -72,17 +71,6 @@ static int ide_config(struct pcmcia_device *);
 
 static void ide_detach(struct pcmcia_device *p_dev);
 
-
-
-
-/*======================================================================
-
-    ide_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
 static int ide_probe(struct pcmcia_device *link)
 {
     ide_info_t *info;
@@ -97,23 +85,12 @@ static int ide_probe(struct pcmcia_device *link)
     info->p_dev = link;
     link->priv = info;
 
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO |
+           CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC;
 
     return ide_config(link);
 } /* ide_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void ide_detach(struct pcmcia_device *link)
 {
     ide_info_t *info = link->priv;
@@ -187,79 +164,31 @@ out_release:
     return NULL;
 }
 
-/*======================================================================
-
-    ide_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ide device available to the system.
-
-======================================================================*/
-
-struct pcmcia_config_check {
-       unsigned long ctl_base;
-       int skip_vcc;
-       int is_kme;
-};
-
-static int pcmcia_check_one_config(struct pcmcia_device *pdev,
-                                  cistpl_cftable_entry_t *cfg,
-                                  cistpl_cftable_entry_t *dflt,
-                                  unsigned int vcc,
-                                  void *priv_data)
+static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
 {
-       struct pcmcia_config_check *stk = priv_data;
-
-       /* Check for matching Vcc, unless we're desperate */
-       if (!stk->skip_vcc) {
-               if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                       if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
-                               return -ENODEV;
-               } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-                       if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
-                               return -ENODEV;
-               }
-       }
+       int *is_kme = priv_data;
 
-       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               pdev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               pdev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-
-               pdev->conf.ConfigIndex = cfg->index;
-               pdev->resource[0]->start = io->win[0].base;
-               if (!(io->flags & CISTPL_IO_16BIT)) {
-                       pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-                       pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-               }
-               if (io->nwin == 2) {
-                       pdev->resource[0]->end = 8;
-                       pdev->resource[1]->start = io->win[1].base;
-                       pdev->resource[1]->end = (stk->is_kme) ? 2 : 1;
-                       if (pcmcia_request_io(pdev) != 0)
-                               return -ENODEV;
-                       stk->ctl_base = pdev->resource[1]->start;
-               } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
-                       pdev->resource[0]->end = io->win[0].len;
-                       pdev->resource[1]->end = 0;
-                       if (pcmcia_request_io(pdev) != 0)
-                               return -ENODEV;
-                       stk->ctl_base = pdev->resource[0]->start + 0x0e;
-               } else
+       if (!(pdev->resource[0]->flags & IO_DATA_PATH_WIDTH_8)) {
+               pdev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+               pdev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+       }
+       pdev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+       pdev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+
+       if (pdev->resource[1]->end) {
+               pdev->resource[0]->end = 8;
+               pdev->resource[1]->end = (*is_kme) ? 2 : 1;
+       } else {
+               if (pdev->resource[0]->end < 16)
                        return -ENODEV;
-               /* If we've got this far, we're done */
-               return 0;
        }
-       return -ENODEV;
+
+       return pcmcia_request_io(pdev);
 }
 
 static int ide_config(struct pcmcia_device *link)
 {
     ide_info_t *info = link->priv;
-    struct pcmcia_config_check *stk = NULL;
     int ret = 0, is_kme = 0;
     unsigned long io_base, ctl_base;
     struct ide_host *host;
@@ -270,23 +199,21 @@ static int ide_config(struct pcmcia_device *link)
              ((link->card_id == PRODID_KME_KXLC005_A) ||
               (link->card_id == PRODID_KME_KXLC005_B)));
 
-    stk = kzalloc(sizeof(*stk), GFP_KERNEL);
-    if (!stk)
-           goto err_mem;
-    stk->is_kme = is_kme;
-    stk->skip_vcc = io_base = ctl_base = 0;
-
-    if (pcmcia_loop_config(link, pcmcia_check_one_config, stk)) {
-           stk->skip_vcc = 1;
-           if (pcmcia_loop_config(link, pcmcia_check_one_config, stk))
+    if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme)) {
+           link->config_flags &= ~CONF_AUTO_CHECK_VCC;
+           if (pcmcia_loop_config(link, pcmcia_check_one_config, &is_kme))
                    goto failed; /* No suitable config found */
     }
     io_base = link->resource[0]->start;
-    ctl_base = stk->ctl_base;
+    if (link->resource[1]->end)
+           ctl_base = link->resource[1]->start;
+    else
+           ctl_base = link->resource[0]->start + 0x0e;
 
     if (!link->irq)
            goto failed;
-    ret = pcmcia_request_configuration(link, &link->conf);
+
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
 
@@ -311,29 +238,15 @@ static int ide_config(struct pcmcia_device *link)
     info->host = host;
     dev_info(&link->dev, "ide-cs: hd%c: Vpp = %d.%d\n",
            'a' + host->ports[0]->index * 2,
-           link->conf.Vpp / 10, link->conf.Vpp % 10);
+           link->vpp / 10, link->vpp % 10);
 
-    kfree(stk);
     return 0;
 
-err_mem:
-    printk(KERN_NOTICE "ide-cs: ide_config failed memory allocation\n");
-    goto failed;
-
 failed:
-    kfree(stk);
     ide_release(link);
     return -ENODEV;
 } /* ide_config */
 
-/*======================================================================
-
-    After a card is removed, ide_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void ide_release(struct pcmcia_device *link)
 {
     ide_info_t *info = link->priv;
@@ -359,15 +272,6 @@ static void ide_release(struct pcmcia_device *link)
 } /* ide_release */
 
 
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.  A CARD_REMOVAL event
-    also sets some flags to discourage the ide drivers from
-    talking to the ports.
-
-======================================================================*/
-
 static struct pcmcia_device_id ide_ids[] = {
        PCMCIA_DEVICE_FUNC_ID(4),
        PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000),        /* Corsair */
@@ -440,9 +344,7 @@ MODULE_DEVICE_TABLE(pcmcia, ide_ids);
 
 static struct pcmcia_driver ide_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "ide-cs",
-       },
+       .name           = "ide-cs",
        .probe          = ide_probe,
        .remove         = ide_detach,
        .id_table       = ide_ids,
index c37ef64d1465a7dac9bcab420699ba2d2b349138..cb3ccf3ed221ecef98c996fc50206b17ba1f1c1a 100644 (file)
 #include <linux/hrtimer.h>     /* ktime_get_real() */
 #include <trace/events/power.h>
 #include <linux/sched.h>
+#include <asm/mwait.h>
 
 #define INTEL_IDLE_VERSION "0.4"
 #define PREFIX "intel_idle: "
 
-#define MWAIT_SUBSTATE_MASK    (0xf)
-#define MWAIT_CSTATE_MASK      (0xf)
-#define MWAIT_SUBSTATE_SIZE    (4)
-#define MWAIT_MAX_NUM_CSTATES  8
-#define CPUID_MWAIT_LEAF (5)
-#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
-#define CPUID5_ECX_INTERRUPT_BREAK     (0x2)
-
 static struct cpuidle_driver intel_idle_driver = {
        .name = "intel_idle",
        .owner = THIS_MODULE,
index 9ddafc30f432236539f9304468d77e2daf761f7e..af9ee313c10b67b9f0a034e6806757aca085c4ed 100644 (file)
@@ -28,7 +28,7 @@ struct evdev {
        int minor;
        struct input_handle handle;
        wait_queue_head_t wait;
-       struct evdev_client *grab;
+       struct evdev_client __rcu *grab;
        struct list_head client_list;
        spinlock_t client_lock; /* protects client_list */
        struct mutex mutex;
index 9cc488d2149019626101d3c5f76d0b2bdab0fe57..aa037fec2f86122500cbd5d14cfca0c59e614804 100644 (file)
@@ -338,7 +338,7 @@ config KEYBOARD_OPENCORES
 
 config KEYBOARD_PXA27x
        tristate "PXA27x/PXA3xx keypad support"
-       depends on PXA27x || PXA3xx
+       depends on PXA27x || PXA3xx || ARCH_MMP
        help
          Enable support for PXA27x/PXA3xx keypad controller.
 
index f32404f991893ef4584ab5540d213945cbb0c738..4b0ec35259a17f70357df965ae4f9b698bf4e01a 100644 (file)
@@ -32,7 +32,7 @@
 #include <asm/mach/map.h>
 
 #include <mach/hardware.h>
-#include <mach/pxa27x_keypad.h>
+#include <plat/pxa27x_keypad.h>
 /*
  * Keypad Controller registers
  */
@@ -330,11 +330,21 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
        keypad->direct_key_state = new_state;
 }
 
+static void clear_wakeup_event(struct pxa27x_keypad *keypad)
+{
+       struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
+
+       if (pdata->clear_wakeup_event)
+               (pdata->clear_wakeup_event)();
+}
+
 static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
 {
        struct pxa27x_keypad *keypad = dev_id;
        unsigned long kpc = keypad_readl(KPC);
 
+       clear_wakeup_event(keypad);
+
        if (kpc & KPC_DI)
                pxa27x_keypad_scan_direct(keypad);
 
index c19066479057ff3567d7168c38922e0fd0b84da3..7e2c12a5b83933e23ce665783d2886b4ee6f211f 100644 (file)
@@ -104,7 +104,7 @@ static int hp_sdc_rtc_do_read_bbrtc (struct rtc_time *rtctm)
        t.endidx =              91;
        t.seq =                 tseq;
        t.act.semaphore =       &tsem;
-       init_MUTEX_LOCKED(&tsem);
+       sema_init(&tsem, 0);
        
        if (hp_sdc_enqueue_transaction(&t)) return -1;
        
@@ -698,7 +698,7 @@ static int __init hp_sdc_rtc_init(void)
                return -ENODEV;
 #endif
 
-       init_MUTEX(&i8042tregs);
+       sema_init(&i8042tregs, 1);
 
        if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr)))
                return ret;
index c92f4edfee7beef3a326e0af4e43275093fba8dc..e5624d8f1709e6c576547c6e78ba66e766d39743 100644 (file)
@@ -915,15 +915,15 @@ int hil_mlc_register(hil_mlc *mlc)
        mlc->ostarted = 0;
 
        rwlock_init(&mlc->lock);
-       init_MUTEX(&mlc->osem);
+       sema_init(&mlc->osem, 1);
 
-       init_MUTEX(&mlc->isem);
+       sema_init(&mlc->isem, 1);
        mlc->icount = -1;
        mlc->imatch = 0;
 
        mlc->opercnt = 0;
 
-       init_MUTEX_LOCKED(&(mlc->csem));
+       sema_init(&(mlc->csem), 0);
 
        hil_mlc_clear_di_scratch(mlc);
        hil_mlc_clear_di_map(mlc, 0);
index bcc2d30ec245ef8349e81745958e0cf8112dfcbf..8c0b51c31424ce2e0c9b15a2a9eb467424e9b3ec 100644 (file)
@@ -905,7 +905,7 @@ static int __init hp_sdc_init(void)
        ts_sync[1]      = 0x0f;
        ts_sync[2] = ts_sync[3] = ts_sync[4] = ts_sync[5] = 0;
        t_sync.act.semaphore = &s_sync;
-       init_MUTEX_LOCKED(&s_sync);
+       sema_init(&s_sync, 0);
        hp_sdc_enqueue_transaction(&t_sync);
        down(&s_sync); /* Wait for t_sync to complete */
 
@@ -1039,7 +1039,7 @@ static int __init hp_sdc_register(void)
                return hp_sdc.dev_err;
        }
 
-       init_MUTEX_LOCKED(&tq_init_sem);
+       sema_init(&tq_init_sem, 0);
 
        tq_init.actidx          = 0;
        tq_init.idx             = 1;
index d4c50512a1ffc038795acb06248e1b245f63f3a5..88c9423500d838a1748c74b283d9b612a754d7fd 100644 (file)
@@ -141,9 +141,9 @@ typedef struct irq_data_isa {
        __u8            rcvhdr[8];
 } irq_data_isa;
 
-typedef union irq_data {
+typedef union act2000_irq_data {
        irq_data_isa isa;
-} irq_data;
+} act2000_irq_data;
 
 /*
  * Per card driver data
@@ -176,7 +176,7 @@ typedef struct act2000_card {
        char   *status_buf_read;
        char   *status_buf_write;
        char   *status_buf_end;
-       irq_data idat;                  /* Data used for IRQ handler        */
+       act2000_irq_data idat;          /* Data used for IRQ handler        */
        isdn_if interface;              /* Interface to upper layer         */
        char regname[35];               /* Name used for request_region     */
 } act2000_card;
index 09b1795516f4e95c4e49f0ce6e1e91c9eefa5bd1..91f06a3ef00223a4403230579fa71f9cc404c7c1 100644 (file)
@@ -20,7 +20,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -39,87 +38,32 @@ MODULE_LICENSE("GPL");
 
 /*====================================================================*/
 
-/*
-   The event() function is this driver's Card Services event handler.
-   It will be called by Card Services when an appropriate card status
-   event is received.  The config() and release() entry points are
-   used to configure or release a socket, in response to card insertion
-   and ejection events.  They are invoked from the skeleton event
-   handler.
-*/
-
 static int avmcs_config(struct pcmcia_device *link);
 static void avmcs_release(struct pcmcia_device *link);
-
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static void avmcs_detach(struct pcmcia_device *p_dev);
 
-/*======================================================================
-
-    avmcs_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-    
-======================================================================*/
-
 static int avmcs_probe(struct pcmcia_device *p_dev)
 {
-
-    /* The io structure describes IO port mapping */
-    p_dev->resource[0]->end = 16;
-    p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-
     /* General socket configuration */
-    p_dev->conf.Attributes = CONF_ENABLE_IRQ;
-    p_dev->conf.IntType = INT_MEMORY_AND_IO;
-    p_dev->conf.ConfigIndex = 1;
-    p_dev->conf.Present = PRESENT_OPTION;
+    p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+    p_dev->config_index = 1;
+    p_dev->config_regs = PRESENT_OPTION;
 
     return avmcs_config(p_dev);
 } /* avmcs_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
 
 static void avmcs_detach(struct pcmcia_device *link)
 {
        avmcs_release(link);
 } /* avmcs_detach */
 
-/*======================================================================
-
-    avmcs_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ethernet device available to the system.
-    
-======================================================================*/
-
-static int avmcs_configcheck(struct pcmcia_device *p_dev,
-                            cistpl_cftable_entry_t *cf,
-                            cistpl_cftable_entry_t *dflt,
-                            unsigned int vcc,
-                            void *priv_data)
+static int avmcs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (cf->io.nwin <= 0)
-               return -ENODEV;
+       p_dev->resource[0]->end = 16;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
 
-       p_dev->resource[0]->start = cf->io.win[0].base;
-       p_dev->resource[0]->end = cf->io.win[0].len;
        return pcmcia_request_io(p_dev);
 }
 
@@ -150,7 +94,7 @@ static int avmcs_config(struct pcmcia_device *link)
        /*
          * configure the PCMCIA socket
          */
-       i = pcmcia_request_configuration(link, &link->conf);
+       i = pcmcia_enable_device(link);
        if (i != 0) {
            pcmcia_disable_device(link);
            break;
@@ -197,13 +141,6 @@ static int avmcs_config(struct pcmcia_device *link)
 
 } /* avmcs_config */
 
-/*======================================================================
-
-    After a card is removed, avmcs_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-    
-======================================================================*/
 
 static void avmcs_release(struct pcmcia_device *link)
 {
@@ -222,9 +159,7 @@ MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
 
 static struct pcmcia_driver avmcs_driver = {
        .owner  = THIS_MODULE,
-       .drv    = {
-               .name   = "avm_cs",
-       },
+       .name           = "avm_cs",
        .probe = avmcs_probe,
        .remove = avmcs_detach,
        .id_table = avmcs_ids,
index 94263c22b8746965109cc6b1654a8a30df2355fd..ac4dd7857cbd3e50edb12b3eb715614a0e17643c 100644 (file)
@@ -20,7 +20,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include "hisax_cfg.h"
@@ -40,67 +39,22 @@ module_param(isdnprot, int, 0);
 
 /*====================================================================*/
 
-/*
-   The event() function is this driver's Card Services event handler.
-   It will be called by Card Services when an appropriate card status
-   event is received.  The config() and release() entry points are
-   used to configure or release a socket, in response to card insertion
-   and ejection events.  They are invoked from the skeleton event
-   handler.
-*/
-
 static int avma1cs_config(struct pcmcia_device *link) __devinit ;
 static void avma1cs_release(struct pcmcia_device *link);
-
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static void avma1cs_detach(struct pcmcia_device *p_dev) __devexit ;
 
-
-/*======================================================================
-
-    avma1cs_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-    
-======================================================================*/
-
 static int __devinit avma1cs_probe(struct pcmcia_device *p_dev)
 {
     dev_dbg(&p_dev->dev, "avma1cs_attach()\n");
 
-    /* The io structure describes IO port mapping */
-    p_dev->resource[0]->end = 16;
-    p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-    p_dev->resource[1]->end = 16;
-    p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_16;
-
     /* General socket configuration */
-    p_dev->conf.Attributes = CONF_ENABLE_IRQ;
-    p_dev->conf.IntType = INT_MEMORY_AND_IO;
-    p_dev->conf.ConfigIndex = 1;
-    p_dev->conf.Present = PRESENT_OPTION;
+    p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+    p_dev->config_index = 1;
+    p_dev->config_regs = PRESENT_OPTION;
 
     return avma1cs_config(p_dev);
 } /* avma1cs_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void __devexit avma1cs_detach(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "avma1cs_detach(0x%p)\n", link);
@@ -108,26 +62,13 @@ static void __devexit avma1cs_detach(struct pcmcia_device *link)
        kfree(link->priv);
 } /* avma1cs_detach */
 
-/*======================================================================
-
-    avma1cs_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ethernet device available to the system.
-    
-======================================================================*/
-
-static int avma1cs_configcheck(struct pcmcia_device *p_dev,
-                              cistpl_cftable_entry_t *cf,
-                              cistpl_cftable_entry_t *dflt,
-                              unsigned int vcc,
-                              void *priv_data)
+static int avma1cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (cf->io.nwin <= 0)
-               return -ENODEV;
-
-       p_dev->resource[0]->start = cf->io.win[0].base;
-       p_dev->resource[0]->end = cf->io.win[0].len;
+       p_dev->resource[0]->end = 16;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
        p_dev->io_lines = 5;
+
        return pcmcia_request_io(p_dev);
 }
 
@@ -161,7 +102,7 @@ static int __devinit avma1cs_config(struct pcmcia_device *link)
        /*
         * configure the PCMCIA socket
         */
-       i = pcmcia_request_configuration(link, &link->conf);
+       i = pcmcia_enable_device(link);
        if (i != 0) {
            pcmcia_disable_device(link);
            break;
@@ -175,9 +116,6 @@ static int __devinit avma1cs_config(struct pcmcia_device *link)
        return -ENODEV;
     }
 
-    printk(KERN_NOTICE "avma1_cs: checking at i/o %#x, irq %d\n",
-               (unsigned int) link->resource[0]->start, link->irq);
-
     icard.para[0] = link->irq;
     icard.para[1] = link->resource[0]->start;
     icard.protocol = isdnprot;
@@ -196,14 +134,6 @@ static int __devinit avma1cs_config(struct pcmcia_device *link)
     return 0;
 } /* avma1cs_config */
 
-/*======================================================================
-
-    After a card is removed, avma1cs_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-    
-======================================================================*/
-
 static void avma1cs_release(struct pcmcia_device *link)
 {
        unsigned long minor = (unsigned long) link->priv;
@@ -216,7 +146,6 @@ static void avma1cs_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 } /* avma1cs_release */
 
-
 static struct pcmcia_device_id avma1cs_ids[] = {
        PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
        PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
@@ -226,19 +155,15 @@ MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
 
 static struct pcmcia_driver avma1cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "avma1_cs",
-       },
+       .name           = "avma1_cs",
        .probe          = avma1cs_probe,
        .remove         = __devexit_p(avma1cs_detach),
        .id_table       = avma1cs_ids,
 };
 
-/*====================================================================*/
-
 static int __init init_avma1_cs(void)
 {
-       return(pcmcia_register_driver(&avma1cs_driver));
+       return pcmcia_register_driver(&avma1cs_driver);
 }
 
 static void __exit exit_avma1_cs(void)
index 6f9afcd5ca4e9301a07c8ec5a4c0473e255363c3..b133378d4dc9b1707c749102c345c3c2f7b2d7d4 100644 (file)
@@ -801,6 +801,16 @@ static void closecard(int cardnr)
        ll_unload(csta);
 }
 
+static irqreturn_t card_irq(int intno, void *dev_id)
+{
+       struct IsdnCardState *cs = dev_id;
+       irqreturn_t ret = cs->irq_func(intno, cs);
+
+       if (ret == IRQ_HANDLED)
+               cs->irq_cnt++;
+       return ret;
+}
+
 static int init_card(struct IsdnCardState *cs)
 {
        int     irq_cnt, cnt = 3, ret;
@@ -809,10 +819,10 @@ static int init_card(struct IsdnCardState *cs)
                ret = cs->cardmsg(cs, CARD_INIT, NULL);
                return(ret);
        }
-       irq_cnt = kstat_irqs(cs->irq);
+       irq_cnt = cs->irq_cnt = 0;
        printk(KERN_INFO "%s: IRQ %d count %d\n", CardType[cs->typ],
               cs->irq, irq_cnt);
-       if (request_irq(cs->irq, cs->irq_func, cs->irq_flags, "HiSax", cs)) {
+       if (request_irq(cs->irq, card_irq, cs->irq_flags, "HiSax", cs)) {
                printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
                       cs->irq);
                return 1;
@@ -822,8 +832,8 @@ static int init_card(struct IsdnCardState *cs)
                /* Timeout 10ms */
                msleep(10);
                printk(KERN_INFO "%s: IRQ %d count %d\n",
-                      CardType[cs->typ], cs->irq, kstat_irqs(cs->irq));
-               if (kstat_irqs(cs->irq) == irq_cnt) {
+                      CardType[cs->typ], cs->irq, cs->irq_cnt);
+               if (cs->irq_cnt == irq_cnt) {
                        printk(KERN_WARNING
                               "%s: IRQ(%d) getting no interrupts during init %d\n",
                               CardType[cs->typ], cs->irq, 4 - cnt);
index b3c08aaf41c410e57c91aaa82fefddc4af6212a8..496d477af0f82fe428798c208e858d407e93d9a8 100644 (file)
@@ -46,7 +46,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -64,26 +63,8 @@ MODULE_LICENSE("Dual MPL/GPL");
 static int protocol = 2;        /* EURO-ISDN Default */
 module_param(protocol, int, 0);
 
-/*====================================================================*/
-
-/*
-   The event() function is this driver's Card Services event handler.
-   It will be called by Card Services when an appropriate card status
-   event is received.  The config() and release() entry points are
-   used to configure or release a socket, in response to card insertion
-   and ejection events.  They are invoked from the elsa_cs event
-   handler.
-*/
-
 static int elsa_cs_config(struct pcmcia_device *link) __devinit ;
 static void elsa_cs_release(struct pcmcia_device *link);
-
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static void elsa_cs_detach(struct pcmcia_device *p_dev) __devexit;
 
 typedef struct local_info_t {
@@ -92,18 +73,6 @@ typedef struct local_info_t {
     int                        cardnr;
 } local_info_t;
 
-/*======================================================================
-
-    elsa_cs_attach() creates an "instance" of the driver, allocatingx
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-
-======================================================================*/
-
 static int __devinit elsa_cs_probe(struct pcmcia_device *link)
 {
     local_info_t *local;
@@ -119,31 +88,9 @@ static int __devinit elsa_cs_probe(struct pcmcia_device *link)
 
     local->cardnr = -1;
 
-    /*
-      General socket configuration defaults can go here.  In this
-      client, we assume very little, and rely on the CIS for almost
-      everything.  In most clients, many details (i.e., number, sizes,
-      and attributes of IO windows) are fixed by the nature of the
-      device, and can be hard-wired here.
-    */
-    link->resource[0]->end = 8;
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-
     return elsa_cs_config(link);
 } /* elsa_cs_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void __devexit elsa_cs_detach(struct pcmcia_device *link)
 {
        local_info_t *info = link->priv;
@@ -156,27 +103,17 @@ static void __devexit elsa_cs_detach(struct pcmcia_device *link)
        kfree(info);
 } /* elsa_cs_detach */
 
-/*======================================================================
-
-    elsa_cs_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    device available to the system.
-
-======================================================================*/
-
-static int elsa_cs_configcheck(struct pcmcia_device *p_dev,
-                              cistpl_cftable_entry_t *cf,
-                              cistpl_cftable_entry_t *dflt,
-                              unsigned int vcc,
-                              void *priv_data)
+static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
 {
        int j;
 
        p_dev->io_lines = 3;
+       p_dev->resource[0]->end = 8;
+       p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
 
-       if ((cf->io.nwin > 0) && cf->io.win[0].base) {
+       if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
                printk(KERN_INFO "(elsa_cs: looks like the 96 model)\n");
-               p_dev->resource[0]->start = cf->io.win[0].base;
                if (!pcmcia_request_io(p_dev))
                        return 0;
        } else {
@@ -199,6 +136,8 @@ static int __devinit elsa_cs_config(struct pcmcia_device *link)
     dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
     dev = link->priv;
 
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+
     i = pcmcia_loop_config(link, elsa_cs_configcheck, NULL);
     if (i != 0)
        goto failed;
@@ -206,21 +145,10 @@ static int __devinit elsa_cs_config(struct pcmcia_device *link)
     if (!link->irq)
        goto failed;
 
-    i = pcmcia_request_configuration(link, &link->conf);
+    i = pcmcia_enable_device(link);
     if (i != 0)
        goto failed;
 
-    /* Finally, report what we've done */
-    dev_info(&link->dev, "index 0x%02x: ",
-           link->conf.ConfigIndex);
-    if (link->conf.Attributes & CONF_ENABLE_IRQ)
-       printk(", irq %d", link->irq);
-    if (link->resource[0])
-       printk(" & %pR", link->resource[0]);
-    if (link->resource[1])
-       printk(" & %pR", link->resource[1]);
-    printk("\n");
-
     icard.para[0] = link->irq;
     icard.para[1] = link->resource[0]->start;
     icard.protocol = protocol;
@@ -240,14 +168,6 @@ failed:
     return -ENODEV;
 } /* elsa_cs_config */
 
-/*======================================================================
-
-    After a card is removed, elsa_cs_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void elsa_cs_release(struct pcmcia_device *link)
 {
     local_info_t *local = link->priv;
@@ -291,9 +211,7 @@ MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
 
 static struct pcmcia_driver elsa_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "elsa_cs",
-       },
+       .name           = "elsa_cs",
        .probe          = elsa_cs_probe,
        .remove         = __devexit_p(elsa_cs_detach),
        .id_table       = elsa_ids,
index 832a87855ffb5900fa22ded56b5586ed907ed886..32ab3924aa7341f5f390623faee36d9a308abc67 100644 (file)
@@ -959,6 +959,7 @@ struct IsdnCardState {
        u_long          event;
        struct work_struct tqueue;
        struct timer_list dbusytimer;
+       unsigned int    irq_cnt;
 #ifdef ERROR_STATISTIC
        int             err_crc;
        int             err_tx;
index a024192b672a3113c0e6663fc1778c5abe4ac6f2..360204bc2777d6f2b941f478ab0a11d2881f07fb 100644 (file)
@@ -46,7 +46,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -64,26 +63,9 @@ MODULE_LICENSE("Dual MPL/GPL");
 static int protocol = 2;        /* EURO-ISDN Default */
 module_param(protocol, int, 0);
 
-/*====================================================================*/
-
-/*
-   The event() function is this driver's Card Services event handler.
-   It will be called by Card Services when an appropriate card status
-   event is received.  The config() and release() entry points are
-   used to configure or release a socket, in response to card
-   insertion and ejection events.  They are invoked from the sedlbauer
-   event handler. 
-*/
-
 static int sedlbauer_config(struct pcmcia_device *link) __devinit ;
 static void sedlbauer_release(struct pcmcia_device *link);
 
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static void sedlbauer_detach(struct pcmcia_device *p_dev) __devexit;
 
 typedef struct local_info_t {
@@ -92,18 +74,6 @@ typedef struct local_info_t {
     int                        cardnr;
 } local_info_t;
 
-/*======================================================================
-
-    sedlbauer_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-    
-======================================================================*/
-
 static int __devinit sedlbauer_probe(struct pcmcia_device *link)
 {
     local_info_t *local;
@@ -118,35 +88,9 @@ static int __devinit sedlbauer_probe(struct pcmcia_device *link)
     local->p_dev = link;
     link->priv = local;
 
-    /*
-      General socket configuration defaults can go here.  In this
-      client, we assume very little, and rely on the CIS for almost
-      everything.  In most clients, many details (i.e., number, sizes,
-      and attributes of IO windows) are fixed by the nature of the
-      device, and can be hard-wired here.
-    */
-
-    /* from old sedl_cs 
-    */
-    /* The io structure describes IO port mapping */
-    link->resource[0]->end = 8;
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-
-    link->conf.Attributes = 0;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-
     return sedlbauer_config(link);
 } /* sedlbauer_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void __devexit sedlbauer_detach(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "sedlbauer_detach(0x%p)\n", link);
@@ -158,70 +102,15 @@ static void __devexit sedlbauer_detach(struct pcmcia_device *link)
        kfree(link->priv);
 } /* sedlbauer_detach */
 
-/*======================================================================
-
-    sedlbauer_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    device available to the system.
-    
-======================================================================*/
-static int sedlbauer_config_check(struct pcmcia_device *p_dev,
-                                 cistpl_cftable_entry_t *cfg,
-                                 cistpl_cftable_entry_t *dflt,
-                                 unsigned int vcc,
-                                 void *priv_data)
+static int sedlbauer_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (cfg->index == 0)
-               return -ENODEV;
-
-       /* Does this card need audio output? */
-       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
-               p_dev->conf.Status = CCSR_AUDIO_ENA;
-       }
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       /* Use power settings for Vcc and Vpp if present */
-       /*  Note that the CIS values need to be rescaled */
-       if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
-                       return -ENODEV;
-       } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
-                       return -ENODEV;
-       }
-
-       if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-       else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
-
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                                       pcmcia_io_cfg_data_width(io->flags);
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-               /* This reserves IO space but doesn't actually enable it */
-               p_dev->io_lines = 3;
-               if (pcmcia_request_io(p_dev) != 0)
-                       return -ENODEV;
-       }
-
-       return 0;
+       p_dev->io_lines = 3;
+       return pcmcia_request_io(p_dev);
 }
 
-
-
 static int __devinit sedlbauer_config(struct pcmcia_device *link)
 {
     int ret;
@@ -229,44 +118,17 @@ static int __devinit sedlbauer_config(struct pcmcia_device *link)
 
     dev_dbg(&link->dev, "sedlbauer_config(0x%p)\n", link);
 
-    /*
-      In this loop, we scan the CIS for configuration table entries,
-      each of which describes a valid card configuration, including
-      voltage, IO window, memory window, and interrupt settings.
-
-      We make no assumptions about the card to be configured: we use
-      just the information available in the CIS.  In an ideal world,
-      this would work for any PCMCIA card, but it requires a complete
-      and accurate CIS.  In practice, a driver usually "knows" most of
-      these things without consulting the CIS, and most client drivers
-      will only use the CIS to fill in implementation-defined details.
-    */
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
+           CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
+
     ret = pcmcia_loop_config(link, sedlbauer_config_check, NULL);
     if (ret)
            goto failed;
 
-    /*
-       This actually configures the PCMCIA socket -- setting up
-       the I/O windows and the interrupt mapping, and putting the
-       card and host interface into "Memory and IO" mode.
-    */
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
 
-    /* Finally, report what we've done */
-    dev_info(&link->dev, "index 0x%02x:",
-          link->conf.ConfigIndex);
-    if (link->conf.Vpp)
-       printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
-    if (link->conf.Attributes & CONF_ENABLE_IRQ)
-       printk(", irq %d", link->irq);
-    if (link->resource[0])
-       printk(" & %pR", link->resource[0]);
-    if (link->resource[1])
-       printk(" & %pR", link->resource[1]);
-    printk("\n");
-
     icard.para[0] = link->irq;
     icard.para[1] = link->resource[0]->start;
     icard.protocol = protocol;
@@ -290,14 +152,6 @@ failed:
 
 } /* sedlbauer_config */
 
-/*======================================================================
-
-    After a card is removed, sedlbauer_release() will unregister the
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-    
-======================================================================*/
-
 static void sedlbauer_release(struct pcmcia_device *link)
 {
     local_info_t *local = link->priv;
@@ -346,9 +200,7 @@ MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids);
 
 static struct pcmcia_driver sedlbauer_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "sedlbauer_cs",
-       },
+       .name           = "sedlbauer_cs",
        .probe          = sedlbauer_probe,
        .remove         = __devexit_p(sedlbauer_detach),
        .id_table       = sedlbauer_ids,
index 7296102ca255d89ef34bee0a1736d695629214d2..282a4467ef19571c803f296aee3b82b2e5883c20 100644 (file)
@@ -27,7 +27,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -45,26 +44,8 @@ MODULE_LICENSE("GPL");
 static int protocol = 2;        /* EURO-ISDN Default */
 module_param(protocol, int, 0);
 
-/*====================================================================*/
-
-/*
-   The event() function is this driver's Card Services event handler.
-   It will be called by Card Services when an appropriate card status
-   event is received.  The config() and release() entry points are
-   used to configure or release a socket, in response to card insertion
-   and ejection events.  They are invoked from the teles_cs event
-   handler.
-*/
-
 static int teles_cs_config(struct pcmcia_device *link) __devinit ;
 static void teles_cs_release(struct pcmcia_device *link);
-
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static void teles_detach(struct pcmcia_device *p_dev) __devexit ;
 
 typedef struct local_info_t {
@@ -73,18 +54,6 @@ typedef struct local_info_t {
     int                        cardnr;
 } local_info_t;
 
-/*======================================================================
-
-    teles_attach() creates an "instance" of the driver, allocatingx
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-
-======================================================================*/
-
 static int __devinit teles_probe(struct pcmcia_device *link)
 {
     local_info_t *local;
@@ -99,31 +68,11 @@ static int __devinit teles_probe(struct pcmcia_device *link)
     local->p_dev = link;
     link->priv = local;
 
-    /*
-      General socket configuration defaults can go here.  In this
-      client, we assume very little, and rely on the CIS for almost
-      everything.  In most clients, many details (i.e., number, sizes,
-      and attributes of IO windows) are fixed by the nature of the
-      device, and can be hard-wired here.
-    */
-    link->resource[0]->end = 96;
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 
     return teles_cs_config(link);
 } /* teles_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void __devexit teles_detach(struct pcmcia_device *link)
 {
        local_info_t *info = link->priv;
@@ -136,27 +85,17 @@ static void __devexit teles_detach(struct pcmcia_device *link)
        kfree(info);
 } /* teles_detach */
 
-/*======================================================================
-
-    teles_cs_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    device available to the system.
-
-======================================================================*/
-
-static int teles_cs_configcheck(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cf,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
-                               void *priv_data)
+static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
 {
        int j;
 
        p_dev->io_lines = 5;
+       p_dev->resource[0]->end = 96;
+       p_dev->resource[0]->flags &= IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
 
-       if ((cf->io.nwin > 0) && cf->io.win[0].base) {
+       if ((p_dev->resource[0]->end) && p_dev->resource[0]->start) {
                printk(KERN_INFO "(teles_cs: looks like the 96 model)\n");
-               p_dev->resource[0]->start = cf->io.win[0].base;
                if (!pcmcia_request_io(p_dev))
                        return 0;
        } else {
@@ -186,21 +125,10 @@ static int __devinit teles_cs_config(struct pcmcia_device *link)
     if (!link->irq)
         goto cs_failed;
 
-    i = pcmcia_request_configuration(link, &link->conf);
+    i = pcmcia_enable_device(link);
     if (i != 0)
       goto cs_failed;
 
-    /* Finally, report what we've done */
-    dev_info(&link->dev, "index 0x%02x:",
-           link->conf.ConfigIndex);
-    if (link->conf.Attributes & CONF_ENABLE_IRQ)
-           printk(", irq %d", link->irq);
-    if (link->resource[0])
-       printk(" & %pR", link->resource[0]);
-    if (link->resource[1])
-       printk(" & %pR", link->resource[1]);
-    printk("\n");
-
     icard.para[0] = link->irq;
     icard.para[1] = link->resource[0]->start;
     icard.protocol = protocol;
@@ -222,14 +150,6 @@ cs_failed:
     return -ENODEV;
 } /* teles_cs_config */
 
-/*======================================================================
-
-    After a card is removed, teles_cs_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void teles_cs_release(struct pcmcia_device *link)
 {
     local_info_t *local = link->priv;
@@ -273,9 +193,7 @@ MODULE_DEVICE_TABLE(pcmcia, teles_ids);
 
 static struct pcmcia_driver teles_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "teles_cs",
-       },
+       .name           = "teles_cs",
        .probe          = teles_probe,
        .remove         = __devexit_p(teles_detach),
        .id_table       = teles_ids,
index e4112622e5a25e7eb90b615bcc93475bcfd054a7..cc2a88d5192fbb359f3027082c0843ad34055d97 100644 (file)
@@ -304,13 +304,22 @@ config LEDS_MC13783
 
 config LEDS_NS2
        tristate "LED support for Network Space v2 GPIO LEDs"
-       depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2
+       depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || MACH_NETSPACE_MAX_V2 || D2NET_V2
        default y
        help
          This option enable support for the dual-GPIO LED found on the
          Network Space v2 board (and parents). This include Internet Space v2,
          Network Space (Max) v2 and d2 Network v2 boards.
 
+config LEDS_NETXBIG
+       tristate "LED support for Big Network series LEDs"
+       depends on MACH_NET2BIG_V2 || MACH_NET5BIG_V2
+       default y
+       help
+         This option enable support for LEDs found on the LaCie 2Big
+         and 5Big Network v2 boards. The LEDs are wired to a CPLD and are
+         controlled through a GPIO extension bus.
+
 config LEDS_TRIGGERS
        bool "LED Trigger support"
        help
index 7d6b95831f8eb5da86fad02ab6eedf680c437e3c..9c96db40ef6d7d3a12f776ab4d764371a71026a5 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_LEDS_ADP5520)            += leds-adp5520.o
 obj-$(CONFIG_LEDS_DELL_NETBOOKS)       += dell-led.o
 obj-$(CONFIG_LEDS_MC13783)             += leds-mc13783.o
 obj-$(CONFIG_LEDS_NS2)                 += leds-ns2.o
+obj-$(CONFIG_LEDS_NETXBIG)             += leds-netxbig.o
 
 # LED SPI Drivers
 obj-$(CONFIG_LEDS_DAC124S085)          += leds-dac124s085.o
diff --git a/drivers/leds/leds-netxbig.c b/drivers/leds/leds-netxbig.c
new file mode 100644 (file)
index 0000000..f2e51c1
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * leds-netxbig.c - Driver for the 2Big and 5Big Network series LEDs
+ *
+ * Copyright (C) 2010 LaCie
+ *
+ * Author: Simon Guinot <sguinot@lacie.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <mach/leds-netxbig.h>
+
+/*
+ * GPIO extension bus.
+ */
+
+static DEFINE_SPINLOCK(gpio_ext_lock);
+
+static void gpio_ext_set_addr(struct netxbig_gpio_ext *gpio_ext, int addr)
+{
+       int pin;
+
+       for (pin = 0; pin < gpio_ext->num_addr; pin++)
+               gpio_set_value(gpio_ext->addr[pin], (addr >> pin) & 1);
+}
+
+static void gpio_ext_set_data(struct netxbig_gpio_ext *gpio_ext, int data)
+{
+       int pin;
+
+       for (pin = 0; pin < gpio_ext->num_data; pin++)
+               gpio_set_value(gpio_ext->data[pin], (data >> pin) & 1);
+}
+
+static void gpio_ext_enable_select(struct netxbig_gpio_ext *gpio_ext)
+{
+       /* Enable select is done on the raising edge. */
+       gpio_set_value(gpio_ext->enable, 0);
+       gpio_set_value(gpio_ext->enable, 1);
+}
+
+static void gpio_ext_set_value(struct netxbig_gpio_ext *gpio_ext,
+                              int addr, int value)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&gpio_ext_lock, flags);
+       gpio_ext_set_addr(gpio_ext, addr);
+       gpio_ext_set_data(gpio_ext, value);
+       gpio_ext_enable_select(gpio_ext);
+       spin_unlock_irqrestore(&gpio_ext_lock, flags);
+}
+
+static int __devinit gpio_ext_init(struct netxbig_gpio_ext *gpio_ext)
+{
+       int err;
+       int i;
+
+       if (unlikely(!gpio_ext))
+               return -EINVAL;
+
+       /* Configure address GPIOs. */
+       for (i = 0; i < gpio_ext->num_addr; i++) {
+               err = gpio_request(gpio_ext->addr[i], "GPIO extension addr");
+               if (err)
+                       goto err_free_addr;
+               err = gpio_direction_output(gpio_ext->addr[i], 0);
+               if (err) {
+                       gpio_free(gpio_ext->addr[i]);
+                       goto err_free_addr;
+               }
+       }
+       /* Configure data GPIOs. */
+       for (i = 0; i < gpio_ext->num_data; i++) {
+               err = gpio_request(gpio_ext->data[i], "GPIO extension data");
+               if (err)
+                       goto err_free_data;
+               err = gpio_direction_output(gpio_ext->data[i], 0);
+               if (err) {
+                       gpio_free(gpio_ext->data[i]);
+                       goto err_free_data;
+               }
+       }
+       /* Configure "enable select" GPIO. */
+       err = gpio_request(gpio_ext->enable, "GPIO extension enable");
+       if (err)
+               goto err_free_data;
+       err = gpio_direction_output(gpio_ext->enable, 0);
+       if (err) {
+               gpio_free(gpio_ext->enable);
+               goto err_free_data;
+       }
+
+       return 0;
+
+err_free_data:
+       for (i = i - 1; i >= 0; i--)
+               gpio_free(gpio_ext->data[i]);
+       i = gpio_ext->num_addr;
+err_free_addr:
+       for (i = i - 1; i >= 0; i--)
+               gpio_free(gpio_ext->addr[i]);
+
+       return err;
+}
+
+static void __devexit gpio_ext_free(struct netxbig_gpio_ext *gpio_ext)
+{
+       int i;
+
+       gpio_free(gpio_ext->enable);
+       for (i = gpio_ext->num_addr - 1; i >= 0; i--)
+               gpio_free(gpio_ext->addr[i]);
+       for (i = gpio_ext->num_data - 1; i >= 0; i--)
+               gpio_free(gpio_ext->data[i]);
+}
+
+/*
+ * Class LED driver.
+ */
+
+struct netxbig_led_data {
+       struct netxbig_gpio_ext *gpio_ext;
+       struct led_classdev     cdev;
+       int                     mode_addr;
+       int                     *mode_val;
+       int                     bright_addr;
+       int                     bright_max;
+       struct                  netxbig_led_timer *timer;
+       int                     num_timer;
+       enum netxbig_led_mode   mode;
+       int                     sata;
+       spinlock_t              lock;
+};
+
+static int netxbig_led_get_timer_mode(enum netxbig_led_mode *mode,
+                                     unsigned long delay_on,
+                                     unsigned long delay_off,
+                                     struct netxbig_led_timer *timer,
+                                     int num_timer)
+{
+       int i;
+
+       for (i = 0; i < num_timer; i++) {
+               if (timer[i].delay_on == delay_on &&
+                   timer[i].delay_off == delay_off) {
+                       *mode = timer[i].mode;
+                       return 0;
+               }
+       }
+       return -EINVAL;
+}
+
+static int netxbig_led_blink_set(struct led_classdev *led_cdev,
+                                unsigned long *delay_on,
+                                unsigned long *delay_off)
+{
+       struct netxbig_led_data *led_dat =
+               container_of(led_cdev, struct netxbig_led_data, cdev);
+       enum netxbig_led_mode mode;
+       int mode_val;
+       int ret;
+
+       /* Look for a LED mode with the requested timer frequency. */
+       ret = netxbig_led_get_timer_mode(&mode, *delay_on, *delay_off,
+                                        led_dat->timer, led_dat->num_timer);
+       if (ret < 0)
+               return ret;
+
+       mode_val = led_dat->mode_val[mode];
+       if (mode_val == NETXBIG_LED_INVALID_MODE)
+               return -EINVAL;
+
+       spin_lock_irq(&led_dat->lock);
+
+       gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
+       led_dat->mode = mode;
+
+       spin_unlock_irq(&led_dat->lock);
+
+       return 0;
+}
+
+static void netxbig_led_set(struct led_classdev *led_cdev,
+                           enum led_brightness value)
+{
+       struct netxbig_led_data *led_dat =
+               container_of(led_cdev, struct netxbig_led_data, cdev);
+       enum netxbig_led_mode mode;
+       int mode_val, bright_val;
+       int set_brightness = 1;
+       unsigned long flags;
+
+       spin_lock_irqsave(&led_dat->lock, flags);
+
+       if (value == LED_OFF) {
+               mode = NETXBIG_LED_OFF;
+               set_brightness = 0;
+       } else {
+               if (led_dat->sata)
+                       mode = NETXBIG_LED_SATA;
+               else if (led_dat->mode == NETXBIG_LED_OFF)
+                       mode = NETXBIG_LED_ON;
+               else /* Keep 'timer' mode. */
+                       mode = led_dat->mode;
+       }
+       mode_val = led_dat->mode_val[mode];
+
+       gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
+       led_dat->mode = mode;
+       /*
+        * Note that the brightness register is shared between all the
+        * SATA LEDs. So, change the brightness setting for a single
+        * SATA LED will affect all the others.
+        */
+       if (set_brightness) {
+               bright_val = DIV_ROUND_UP(value * led_dat->bright_max,
+                                         LED_FULL);
+               gpio_ext_set_value(led_dat->gpio_ext,
+                                  led_dat->bright_addr, bright_val);
+       }
+
+       spin_unlock_irqrestore(&led_dat->lock, flags);
+}
+
+static ssize_t netxbig_led_sata_store(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buff, size_t count)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct netxbig_led_data *led_dat =
+               container_of(led_cdev, struct netxbig_led_data, cdev);
+       unsigned long enable;
+       enum netxbig_led_mode mode;
+       int mode_val;
+       int ret;
+
+       ret = strict_strtoul(buff, 10, &enable);
+       if (ret < 0)
+               return ret;
+
+       enable = !!enable;
+
+       spin_lock_irq(&led_dat->lock);
+
+       if (led_dat->sata == enable) {
+               ret = count;
+               goto exit_unlock;
+       }
+
+       if (led_dat->mode != NETXBIG_LED_ON &&
+           led_dat->mode != NETXBIG_LED_SATA)
+               mode = led_dat->mode; /* Keep modes 'off' and 'timer'. */
+       else if (enable)
+               mode = NETXBIG_LED_SATA;
+       else
+               mode = NETXBIG_LED_ON;
+
+       mode_val = led_dat->mode_val[mode];
+       if (mode_val == NETXBIG_LED_INVALID_MODE) {
+               ret = -EINVAL;
+               goto exit_unlock;
+       }
+
+       gpio_ext_set_value(led_dat->gpio_ext, led_dat->mode_addr, mode_val);
+       led_dat->mode = mode;
+       led_dat->sata = enable;
+
+       ret = count;
+
+exit_unlock:
+       spin_unlock_irq(&led_dat->lock);
+
+       return ret;
+}
+
+static ssize_t netxbig_led_sata_show(struct device *dev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct netxbig_led_data *led_dat =
+               container_of(led_cdev, struct netxbig_led_data, cdev);
+
+       return sprintf(buf, "%d\n", led_dat->sata);
+}
+
+static DEVICE_ATTR(sata, 0644, netxbig_led_sata_show, netxbig_led_sata_store);
+
+static void __devexit delete_netxbig_led(struct netxbig_led_data *led_dat)
+{
+       if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE)
+               device_remove_file(led_dat->cdev.dev, &dev_attr_sata);
+       led_classdev_unregister(&led_dat->cdev);
+}
+
+static int __devinit
+create_netxbig_led(struct platform_device *pdev,
+                  struct netxbig_led_data *led_dat,
+                  const struct netxbig_led *template)
+{
+       struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+       int ret;
+
+       spin_lock_init(&led_dat->lock);
+       led_dat->gpio_ext = pdata->gpio_ext;
+       led_dat->cdev.name = template->name;
+       led_dat->cdev.default_trigger = template->default_trigger;
+       led_dat->cdev.blink_set = netxbig_led_blink_set;
+       led_dat->cdev.brightness_set = netxbig_led_set;
+       /*
+        * Because the GPIO extension bus don't allow to read registers
+        * value, there is no way to probe the LED initial state.
+        * So, the initial sysfs LED value for the "brightness" and "sata"
+        * attributes are inconsistent.
+        *
+        * Note that the initial LED state can't be reconfigured.
+        * The reason is that the LED behaviour must stay uniform during
+        * the whole boot process (bootloader+linux).
+        */
+       led_dat->sata = 0;
+       led_dat->cdev.brightness = LED_OFF;
+       led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
+       led_dat->mode_addr = template->mode_addr;
+       led_dat->mode_val = template->mode_val;
+       led_dat->bright_addr = template->bright_addr;
+       led_dat->bright_max = (1 << pdata->gpio_ext->num_data) - 1;
+       led_dat->timer = pdata->timer;
+       led_dat->num_timer = pdata->num_timer;
+
+       ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * If available, expose the SATA activity blink capability through
+        * a "sata" sysfs attribute.
+        */
+       if (led_dat->mode_val[NETXBIG_LED_SATA] != NETXBIG_LED_INVALID_MODE) {
+               ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata);
+               if (ret)
+                       led_classdev_unregister(&led_dat->cdev);
+       }
+
+       return ret;
+}
+
+static int __devinit netxbig_led_probe(struct platform_device *pdev)
+{
+       struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+       struct netxbig_led_data *leds_data;
+       int i;
+       int ret;
+
+       if (!pdata)
+               return -EINVAL;
+
+       leds_data = kzalloc(sizeof(struct netxbig_led_data) * pdata->num_leds,
+                           GFP_KERNEL);
+       if (!leds_data)
+               return -ENOMEM;
+
+       ret = gpio_ext_init(pdata->gpio_ext);
+       if (ret < 0)
+               goto err_free_data;
+
+       for (i = 0; i < pdata->num_leds; i++) {
+               ret = create_netxbig_led(pdev, &leds_data[i], &pdata->leds[i]);
+               if (ret < 0)
+                       goto err_free_leds;
+       }
+
+       platform_set_drvdata(pdev, leds_data);
+
+       return 0;
+
+err_free_leds:
+       for (i = i - 1; i >= 0; i--)
+               delete_netxbig_led(&leds_data[i]);
+
+       gpio_ext_free(pdata->gpio_ext);
+err_free_data:
+       kfree(leds_data);
+
+       return ret;
+}
+
+static int __devexit netxbig_led_remove(struct platform_device *pdev)
+{
+       struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+       struct netxbig_led_data *leds_data;
+       int i;
+
+       leds_data = platform_get_drvdata(pdev);
+
+       for (i = 0; i < pdata->num_leds; i++)
+               delete_netxbig_led(&leds_data[i]);
+
+       gpio_ext_free(pdata->gpio_ext);
+       kfree(leds_data);
+
+       return 0;
+}
+
+static struct platform_driver netxbig_led_driver = {
+       .probe          = netxbig_led_probe,
+       .remove         = __devexit_p(netxbig_led_remove),
+       .driver         = {
+               .name   = "leds-netxbig",
+               .owner  = THIS_MODULE,
+       },
+};
+MODULE_ALIAS("platform:leds-netxbig");
+
+static int __init netxbig_led_init(void)
+{
+       return platform_driver_register(&netxbig_led_driver);
+}
+
+static void __exit netxbig_led_exit(void)
+{
+       platform_driver_unregister(&netxbig_led_driver);
+}
+
+module_init(netxbig_led_init);
+module_exit(netxbig_led_exit);
+
+MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>");
+MODULE_DESCRIPTION("LED driver for LaCie xBig Network boards");
+MODULE_LICENSE("GPL");
index 350eb34f049c97520bb183d97f9f84f8864663b5..f77d48d0b3e484bea2d48fd76568f4aa42cce445 100644 (file)
@@ -141,10 +141,12 @@ static ssize_t ns2_led_sata_store(struct device *dev,
                                  struct device_attribute *attr,
                                  const char *buff, size_t count)
 {
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct ns2_led_data *led_dat =
+               container_of(led_cdev, struct ns2_led_data, cdev);
        int ret;
        unsigned long enable;
        enum ns2_led_modes mode;
-       struct ns2_led_data *led_dat = dev_get_drvdata(dev);
 
        ret = strict_strtoul(buff, 10, &enable);
        if (ret < 0)
@@ -172,7 +174,9 @@ static ssize_t ns2_led_sata_store(struct device *dev,
 static ssize_t ns2_led_sata_show(struct device *dev,
                                 struct device_attribute *attr, char *buf)
 {
-       struct ns2_led_data *led_dat = dev_get_drvdata(dev);
+       struct led_classdev *led_cdev = dev_get_drvdata(dev);
+       struct ns2_led_data *led_dat =
+               container_of(led_cdev, struct ns2_led_data, cdev);
 
        return sprintf(buf, "%d\n", led_dat->sata);
 }
@@ -234,7 +238,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
        if (ret < 0)
                goto err_free_slow;
 
-       dev_set_drvdata(led_dat->cdev.dev, led_dat);
        ret = device_create_file(led_dat->cdev.dev, &dev_attr_sata);
        if (ret < 0)
                goto err_free_cdev;
index 1c4ee6e77937f596378f88587787052106cd3c58..bf64e49d996acd121a215c7d0bdc3c1bc1fd86b6 100644 (file)
@@ -83,7 +83,7 @@ static struct adb_driver *adb_controller;
 BLOCKING_NOTIFIER_HEAD(adb_client_list);
 static int adb_got_sleep;
 static int adb_inited;
-static DECLARE_MUTEX(adb_probe_mutex);
+static DEFINE_SEMAPHORE(adb_probe_mutex);
 static int sleepy_trackpad;
 static int autopoll_devs;
 int __adb_probe_sync;
index d242976bcfe71455b966d3a8cdfa69a7f40dbdbc..19c371809d7776f19aa2adaff75fae9b3bd7904c 100644 (file)
@@ -92,8 +92,10 @@ static int __init via_pmu_led_init(void)
        if (dt == NULL)
                return -ENODEV;
        model = of_get_property(dt, "model", NULL);
-       if (model == NULL)
+       if (model == NULL) {
+               of_node_put(dt);
                return -ENODEV;
+       }
        if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
            strncmp(model, "iBook", strlen("iBook")) != 0 &&
            strcmp(model, "PowerMac7,2") != 0 &&
index e1c8b62b086d506ef46d8a52ccb6d5c4d73e0a18..01b6d584442cdcf686c8c4f643193b9c51360e4a 100644 (file)
@@ -83,6 +83,11 @@ static int __devinit ab8500_spi_probe(struct spi_device *spi)
        struct ab8500 *ab8500;
        int ret;
 
+       spi->bits_per_word = 24;
+       ret = spi_setup(spi);
+       if (ret < 0)
+               return ret;
+
        ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL);
        if (!ab8500)
                return -ENOMEM;
index 097f24d8bceb9ec2ad0d1440430c302d7f0a4a35..b9fda7018cef9a4b07cdeec3c71c3e29c5f63775 100644 (file)
@@ -78,7 +78,7 @@ struct sih {
        u8      irq_lines;              /* number of supported irq lines */
 
        /* SIR ignored -- set interrupt, for testing only */
-       struct irq_data {
+       struct sih_irq_data {
                u8      isr_offset;
                u8      imr_offset;
        } mask[2];
@@ -810,7 +810,7 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
        twl4030_irq_chip = dummy_irq_chip;
        twl4030_irq_chip.name = "twl4030";
 
-       twl4030_sih_irq_chip.ack = dummy_irq_chip.ack;
+       twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack;
 
        for (i = irq_base; i < irq_end; i++) {
                set_irq_chip_and_handler(i, &twl4030_irq_chip,
index 840b301b567142b4e264924a14feb91c5cb54003..f2e02d7d9f3d45555356a54aecb5e5ec3228472d 100644 (file)
@@ -41,23 +41,35 @@ static unsigned int fmax = 515633;
  * @clkreg: default value for MCICLOCK register
  * @clkreg_enable: enable value for MMCICLOCK register
  * @datalength_bits: number of bits in the MMCIDATALENGTH register
+ * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
+ *           is asserted (likewise for RX)
+ * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
+ *               is asserted (likewise for RX)
  */
 struct variant_data {
        unsigned int            clkreg;
        unsigned int            clkreg_enable;
        unsigned int            datalength_bits;
+       unsigned int            fifosize;
+       unsigned int            fifohalfsize;
 };
 
 static struct variant_data variant_arm = {
+       .fifosize               = 16 * 4,
+       .fifohalfsize           = 8 * 4,
        .datalength_bits        = 16,
 };
 
 static struct variant_data variant_u300 = {
+       .fifosize               = 16 * 4,
+       .fifohalfsize           = 8 * 4,
        .clkreg_enable          = 1 << 13, /* HWFCEN */
        .datalength_bits        = 16,
 };
 
 static struct variant_data variant_ux500 = {
+       .fifosize               = 30 * 4,
+       .fifohalfsize           = 8 * 4,
        .clkreg                 = MCI_CLK_ENABLE,
        .clkreg_enable          = 1 << 14, /* HWFCEN */
        .datalength_bits        = 24,
@@ -138,6 +150,7 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
 
 static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
 {
+       struct variant_data *variant = host->variant;
        unsigned int datactrl, timeout, irqmask;
        unsigned long long clks;
        void __iomem *base;
@@ -173,7 +186,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
                 * If we have less than a FIFOSIZE of bytes to transfer,
                 * trigger a PIO interrupt as soon as any data is available.
                 */
-               if (host->size < MCI_FIFOSIZE)
+               if (host->size < variant->fifosize)
                        irqmask |= MCI_RXDATAAVLBLMASK;
        } else {
                /*
@@ -332,13 +345,15 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema
 
 static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
 {
+       struct variant_data *variant = host->variant;
        void __iomem *base = host->base;
        char *ptr = buffer;
 
        do {
                unsigned int count, maxcnt;
 
-               maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : MCI_FIFOHALFSIZE;
+               maxcnt = status & MCI_TXFIFOEMPTY ?
+                        variant->fifosize : variant->fifohalfsize;
                count = min(remain, maxcnt);
 
                writesl(base + MMCIFIFO, ptr, count >> 2);
@@ -362,6 +377,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
 {
        struct mmci_host *host = dev_id;
        struct sg_mapping_iter *sg_miter = &host->sg_miter;
+       struct variant_data *variant = host->variant;
        void __iomem *base = host->base;
        unsigned long flags;
        u32 status;
@@ -420,7 +436,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
         * If we're nearing the end of the read, switch to
         * "any data available" mode.
         */
-       if (status & MCI_RXACTIVE && host->size < MCI_FIFOSIZE)
+       if (status & MCI_RXACTIVE && host->size < variant->fifosize)
                writel(MCI_RXDATAAVLBLMASK, base + MMCIMASK1);
 
        /*
@@ -564,18 +580,23 @@ static int mmci_get_ro(struct mmc_host *mmc)
        if (host->gpio_wp == -ENOSYS)
                return -ENOSYS;
 
-       return gpio_get_value(host->gpio_wp);
+       return gpio_get_value_cansleep(host->gpio_wp);
 }
 
 static int mmci_get_cd(struct mmc_host *mmc)
 {
        struct mmci_host *host = mmc_priv(mmc);
+       struct mmci_platform_data *plat = host->plat;
        unsigned int status;
 
-       if (host->gpio_cd == -ENOSYS)
-               status = host->plat->status(mmc_dev(host->mmc));
-       else
-               status = !gpio_get_value(host->gpio_cd);
+       if (host->gpio_cd == -ENOSYS) {
+               if (!plat->status)
+                       return 1; /* Assume always present */
+
+               status = plat->status(mmc_dev(host->mmc));
+       } else
+               status = !!gpio_get_value_cansleep(host->gpio_cd)
+                       ^ plat->cd_invert;
 
        /*
         * Use positive logic throughout - status is zero for no card,
@@ -584,6 +605,15 @@ static int mmci_get_cd(struct mmc_host *mmc)
        return status;
 }
 
+static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
+{
+       struct mmci_host *host = dev_id;
+
+       mmc_detect_change(host->mmc, msecs_to_jiffies(500));
+
+       return IRQ_HANDLED;
+}
+
 static const struct mmc_host_ops mmci_ops = {
        .request        = mmci_request,
        .set_ios        = mmci_set_ios,
@@ -620,6 +650,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
 
        host->gpio_wp = -ENOSYS;
        host->gpio_cd = -ENOSYS;
+       host->gpio_cd_irq = -1;
 
        host->hw_designer = amba_manf(dev);
        host->hw_revision = amba_rev(dev);
@@ -699,7 +730,6 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        if (host->vcc == NULL)
                mmc->ocr_avail = plat->ocr_mask;
        mmc->caps = plat->capabilities;
-       mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        /*
         * We can do SGIO
@@ -744,6 +774,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                        host->gpio_cd = plat->gpio_cd;
                else if (ret != -ENOSYS)
                        goto err_gpio_cd;
+
+               ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd),
+                                             mmci_cd_irq, 0,
+                                             DRIVER_NAME " (cd)", host);
+               if (ret >= 0)
+                       host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd);
        }
        if (gpio_is_valid(plat->gpio_wp)) {
                ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)");
@@ -755,6 +791,10 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
                        goto err_gpio_wp;
        }
 
+       if ((host->plat->status || host->gpio_cd != -ENOSYS)
+           && host->gpio_cd_irq < 0)
+               mmc->caps |= MMC_CAP_NEEDS_POLL;
+
        ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
        if (ret)
                goto unmap;
@@ -781,6 +821,8 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        if (host->gpio_wp != -ENOSYS)
                gpio_free(host->gpio_wp);
  err_gpio_wp:
+       if (host->gpio_cd_irq >= 0)
+               free_irq(host->gpio_cd_irq, host);
        if (host->gpio_cd != -ENOSYS)
                gpio_free(host->gpio_cd);
  err_gpio_cd:
@@ -819,6 +861,8 @@ static int __devexit mmci_remove(struct amba_device *dev)
 
                if (host->gpio_wp != -ENOSYS)
                        gpio_free(host->gpio_wp);
+               if (host->gpio_cd_irq >= 0)
+                       free_irq(host->gpio_cd_irq, host);
                if (host->gpio_cd != -ENOSYS)
                        gpio_free(host->gpio_cd);
 
index 68970cfb81e1396ca9f5a3f817e4c7ede777d6ea..4ae887fc01892e3a844b064ce6dd72c3a8773aa9 100644 (file)
 #define MCI_DPSM_MODE          (1 << 2)
 #define MCI_DPSM_DMAENABLE     (1 << 3)
 #define MCI_DPSM_BLOCKSIZE     (1 << 4)
-#define MCI_DPSM_RWSTART       (1 << 8)
-#define MCI_DPSM_RWSTOP                (1 << 9)
-#define MCI_DPSM_RWMOD         (1 << 10)
-#define MCI_DPSM_SDIOEN                (1 << 11)
+/* Control register extensions in the ST Micro U300 and Ux500 versions */
+#define MCI_ST_DPSM_RWSTART    (1 << 8)
+#define MCI_ST_DPSM_RWSTOP     (1 << 9)
+#define MCI_ST_DPSM_RWMOD      (1 << 10)
+#define MCI_ST_DPSM_SDIOEN     (1 << 11)
+/* Control register extensions in the ST Micro Ux500 versions */
+#define MCI_ST_DPSM_DMAREQCTL  (1 << 12)
+#define MCI_ST_DPSM_DBOOTMODEEN        (1 << 13)
+#define MCI_ST_DPSM_BUSYMODE   (1 << 14)
+#define MCI_ST_DPSM_DDRMODE    (1 << 15)
 
 #define MMCIDATACNT            0x030
 #define MMCISTATUS             0x034
        MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|       \
        MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATABLOCKENDMASK)
 
-/*
- * The size of the FIFO in bytes.
- */
-#define MCI_FIFOSIZE   (16*4)
-       
-#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
-
 #define NR_SG          16
 
 struct clk;
@@ -154,6 +153,7 @@ struct mmci_host {
        struct clk              *clk;
        int                     gpio_cd;
        int                     gpio_wp;
+       int                     gpio_cd_irq;
 
        unsigned int            data_xfered;
 
index 7aa65bb2af4a29cc03231589de9083e48589b66f..f472c2714eb88a4289598ed9e454e7aefceaac45 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/ioport.h>
 #include <linux/scatterlist.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <linux/io.h>
@@ -536,9 +535,7 @@ static int sdricoh_pcmcia_resume(struct pcmcia_device *link)
 #endif
 
 static struct pcmcia_driver sdricoh_driver = {
-       .drv = {
-               .name = DRIVER_NAME,
-               },
+       .name = DRIVER_NAME,
        .probe = sdricoh_pcmcia_probe,
        .remove = sdricoh_pcmcia_detach,
        .id_table = pcmcia_ids,
index e9ca5ba7d9d2cfa1fe1671205f0a9db584d00e49..57a1acfe22c4a2df13903e42918b14ac47f875a4 100644 (file)
@@ -16,7 +16,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -101,7 +100,7 @@ MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)")
 static caddr_t remap_window(struct map_info *map, unsigned long to)
 {
        struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
-       window_handle_t win = (window_handle_t)map->map_priv_2;
+       struct resource *win = (struct resource *) map->map_priv_2;
        unsigned int offset;
        int ret;
 
@@ -316,30 +315,19 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on)
 {
        struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
        struct pcmcia_device *link = dev->p_dev;
-       modconf_t mod;
-       int ret;
-
-       mod.Attributes = CONF_VPP1_CHANGE_VALID | CONF_VPP2_CHANGE_VALID;
-       mod.Vcc = 0;
-       mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0;
 
        DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp);
-       ret = pcmcia_modify_configuration(link, &mod);
+       pcmcia_fixup_vpp(link, on ? dev->vpp : 0);
 }
 
 
-/* After a card is removed, pcmciamtd_release() will unregister the
- * device, and release the PCMCIA configuration.  If the device is
- * still open, this will be postponed until it is closed.
- */
-
 static void pcmciamtd_release(struct pcmcia_device *link)
 {
        struct pcmciamtd_dev *dev = link->priv;
 
        DEBUG(3, "link = 0x%p", link);
 
-       if (link->win) {
+       if (link->resource[2]->end) {
                if(dev->win_base) {
                        iounmap(dev->win_base);
                        dev->win_base = NULL;
@@ -482,18 +470,12 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev
 }
 
 
-/* pcmciamtd_config() is scheduled to run after a CARD_INSERTION event
- * is received, to configure the PCMCIA socket, and to make the
- * MTD device available to the system.
- */
-
 static int pcmciamtd_config(struct pcmcia_device *link)
 {
        struct pcmciamtd_dev *dev = link->priv;
        struct mtd_info *mtd = NULL;
-       win_req_t req;
        int ret;
-       int i;
+       int i, j = 0;
        static char *probes[] = { "jedec_probe", "cfi_probe" };
        int new_name = 0;
 
@@ -520,28 +502,34 @@ static int pcmciamtd_config(struct pcmcia_device *link)
         * smaller windows until we succeed
         */
 
-       req.Attributes =  WIN_MEMORY_TYPE_CM | WIN_ENABLE;
-       req.Attributes |= (dev->pcmcia_map.bankwidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
-       req.Base = 0;
-       req.AccessSpeed = mem_speed;
-       link->win = (window_handle_t)link;
-       req.Size = (force_size) ? force_size << 20 : MAX_PCMCIA_ADDR;
+       link->resource[2]->flags |=  WIN_MEMORY_TYPE_CM | WIN_ENABLE;
+       link->resource[2]->flags |= (dev->pcmcia_map.bankwidth == 1) ?
+                                       WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
+       link->resource[2]->start = 0;
+       link->resource[2]->end = (force_size) ? force_size << 20 :
+                                       MAX_PCMCIA_ADDR;
        dev->win_size = 0;
 
        do {
                int ret;
-               DEBUG(2, "requesting window with size = %dKiB memspeed = %d",
-                     req.Size >> 10, req.AccessSpeed);
-               ret = pcmcia_request_window(link, &req, &link->win);
+               DEBUG(2, "requesting window with size = %luKiB memspeed = %d",
+                       (unsigned long) resource_size(link->resource[2]) >> 10,
+                       mem_speed);
+               ret = pcmcia_request_window(link, link->resource[2], mem_speed);
                DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size);
                if(ret) {
-                       req.Size >>= 1;
+                       j++;
+                       link->resource[2]->start = 0;
+                       link->resource[2]->end = (force_size) ?
+                                       force_size << 20 : MAX_PCMCIA_ADDR;
+                       link->resource[2]->end >>= j;
                } else {
-                       DEBUG(2, "Got window of size %dKiB", req.Size >> 10);
-                       dev->win_size = req.Size;
+                       DEBUG(2, "Got window of size %luKiB", (unsigned long)
+                               resource_size(link->resource[2]) >> 10);
+                       dev->win_size = resource_size(link->resource[2]);
                        break;
                }
-       } while(req.Size >= 0x1000);
+       } while (link->resource[2]->end >= 0x1000);
 
        DEBUG(2, "dev->win_size = %d", dev->win_size);
 
@@ -553,33 +541,31 @@ static int pcmciamtd_config(struct pcmcia_device *link)
        DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10);
 
        /* Get write protect status */
-       DEBUG(2, "window handle = 0x%8.8lx", (unsigned long)link->win);
-       dev->win_base = ioremap(req.Base, req.Size);
+       dev->win_base = ioremap(link->resource[2]->start,
+                               resource_size(link->resource[2]));
        if(!dev->win_base) {
-               dev_err(&dev->p_dev->dev, "ioremap(%lu, %u) failed\n",
-                       req.Base, req.Size);
+               dev_err(&dev->p_dev->dev, "ioremap(%pR) failed\n",
+                       link->resource[2]);
                pcmciamtd_release(link);
                return -ENODEV;
        }
-       DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x",
-             dev, req.Base, dev->win_base, req.Size);
+       DEBUG(1, "mapped window dev = %p @ %pR, base = %p",
+             dev, link->resource[2], dev->win_base);
 
        dev->offset = 0;
        dev->pcmcia_map.map_priv_1 = (unsigned long)dev;
-       dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
+       dev->pcmcia_map.map_priv_2 = (unsigned long)link->resource[2];
 
        dev->vpp = (vpp) ? vpp : link->socket->socket.Vpp;
-       link->conf.Attributes = 0;
        if(setvpp == 2) {
-               link->conf.Vpp = dev->vpp;
+               link->vpp = dev->vpp;
        } else {
-               link->conf.Vpp = 0;
+               link->vpp = 0;
        }
 
-       link->conf.IntType = INT_MEMORY;
-       link->conf.ConfigIndex = 0;
+       link->config_index = 0;
        DEBUG(2, "Setting Configuration");
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret != 0) {
                if (dev->win_base) {
                        iounmap(dev->win_base);
@@ -680,12 +666,6 @@ static int pcmciamtd_resume(struct pcmcia_device *dev)
 }
 
 
-/* This deletes a driver "instance".  The device is de-registered
- * with Card Services.  If it has been released, all local data
- * structures are freed.  Otherwise, the structures will be freed
- * when the device is released.
- */
-
 static void pcmciamtd_detach(struct pcmcia_device *link)
 {
        struct pcmciamtd_dev *dev = link->priv;
@@ -703,11 +683,6 @@ static void pcmciamtd_detach(struct pcmcia_device *link)
 }
 
 
-/* pcmciamtd_attach() creates an "instance" of the driver, allocating
- * local data structures for one device.  The device is registered
- * with Card Services.
- */
-
 static int pcmciamtd_probe(struct pcmcia_device *link)
 {
        struct pcmciamtd_dev *dev;
@@ -720,9 +695,6 @@ static int pcmciamtd_probe(struct pcmcia_device *link)
        dev->p_dev = link;
        link->priv = dev;
 
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY;
-
        return pcmciamtd_config(link);
 }
 
@@ -757,9 +729,7 @@ static struct pcmcia_device_id pcmciamtd_ids[] = {
 MODULE_DEVICE_TABLE(pcmcia, pcmciamtd_ids);
 
 static struct pcmcia_driver pcmciamtd_driver = {
-       .drv            = {
-               .name   = "pcmciamtd"
-       },
+       .name           = "pcmciamtd",
        .probe          = pcmciamtd_probe,
        .remove         = pcmciamtd_detach,
        .owner          = THIS_MODULE,
@@ -771,8 +741,6 @@ static struct pcmcia_driver pcmciamtd_driver = {
 
 static int __init init_pcmciamtd(void)
 {
-       info(DRIVER_DESC);
-
        if(bankwidth && bankwidth != 1 && bankwidth != 2) {
                info("bad bankwidth (%d), using default", bankwidth);
                bankwidth = 2;
index 70705d1306b93e161260852d39f6adf6fe308226..eca55c52bdfdf2ae8c8445bfac2901cfd9d99bd3 100644 (file)
@@ -522,7 +522,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
        lp->tx_len              = lp->exec_box->data[9];   /* Transmit list count */
        lp->rx_len              = lp->exec_box->data[11];  /* Receive list count */
 
-       init_MUTEX_LOCKED(&lp->cmd_mutex);
+       sema_init(&lp->cmd_mutex, 0);
        init_completion(&lp->execution_cmd);
        init_completion(&lp->xceiver_cmd);
 
index 5db667c0b3711f235dfc49c52a4d165b12e6b3fd..77efe462b9215914dd1071c8875635ebabff6d09 100644 (file)
@@ -2,6 +2,9 @@
 # Network device configuration
 #
 
+config HAVE_NET_MACB
+       bool
+
 menuconfig NETDEVICES
        default y if UML
        depends on NET
@@ -221,7 +224,7 @@ config MII
 
 config MACB
        tristate "Atmel MACB support"
-       depends on AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263 || ARCH_AT91SAM9G20 || ARCH_AT91SAM9G45 || ARCH_AT91CAP9
+       depends on HAVE_NET_MACB
        select PHYLIB
        help
          The Atmel MACB ethernet interface is found on many AT32 and AT91
index 012613fde3f4d61f1217603a3bd811673f43d324..03d063554b7f46103cd4c9d20a7dacab215cafeb 100644 (file)
@@ -38,6 +38,7 @@
 #include <asm/blackfin.h>
 #include <asm/cacheflush.h>
 #include <asm/portmux.h>
+#include <mach/pll.h>
 
 #include "bfin_mac.h"
 
index 4b52c767ad056ced9aafcafea8299384b807c169..3e5d0b6b6516133039192fa5dfd1fdf88660d81b 100644 (file)
@@ -608,7 +608,7 @@ static int sixpack_open(struct tty_struct *tty)
 
        spin_lock_init(&sp->lock);
        atomic_set(&sp->refcnt, 1);
-       init_MUTEX_LOCKED(&sp->dead_sem);
+       sema_init(&sp->dead_sem, 0);
 
        /* !!! length of the buffers. MTU is IP MTU, not PACLEN!  */
 
index 66e88bd59caada26f9cdaa4b6dbb7c1a78026e1f..4c628393c8b157cbc09de52d902b5fa8c3d370a3 100644 (file)
@@ -747,7 +747,7 @@ static int mkiss_open(struct tty_struct *tty)
 
        spin_lock_init(&ax->buflock);
        atomic_set(&ax->refcnt, 1);
-       init_MUTEX_LOCKED(&ax->dead_sem);
+       sema_init(&ax->dead_sem, 0);
 
        ax->tty = tty;
        tty->disc_data = ax;
index 1b051dab7b298a761a5d9e4f2ff38af16f062238..51d74447f8f8cb7d428c7bbdf22b14f71cdfc4aa 100644 (file)
@@ -909,7 +909,7 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n
        dev->tx_skb = NULL;
 
        spin_lock_init(&dev->tx_lock);
-       init_MUTEX(&dev->fsm.sem);
+       sema_init(&dev->fsm.sem, 1);
 
        dev->drv = drv;
        dev->netdev = ndev;
index c683f77c6f424ebbc873d76f0e07cb386484ea70..ff824e11f0b6865a74a0f55de50f7a02d659e75c 100644 (file)
@@ -87,7 +87,6 @@ earlier 3Com products.
 #include <linux/bitops.h>
 #include <linux/mii.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
@@ -280,25 +279,15 @@ static int tc574_probe(struct pcmcia_device *link)
        spin_lock_init(&lp->window_lock);
        link->resource[0]->end = 32;
        link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-       link->conf.ConfigIndex = 1;
+       link->config_flags |= CONF_ENABLE_IRQ;
+       link->config_index = 1;
 
        dev->netdev_ops = &el3_netdev_ops;
        SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
        dev->watchdog_timeo = TX_TIMEOUT;
 
        return tc574_config(link);
-} /* tc574_attach */
-
-/*
-
-       This deletes a driver "instance".  The device is de-registered
-       with Card Services.  If it has been released, all local data
-       structures are freed.  Otherwise, the structures will be freed
-       when the device is released.
-
-*/
+}
 
 static void tc574_detach(struct pcmcia_device *link)
 {
@@ -313,12 +302,6 @@ static void tc574_detach(struct pcmcia_device *link)
        free_netdev(dev);
 } /* tc574_detach */
 
-/*
-       tc574_config() is scheduled to run after a CARD_INSERTION event
-       is received, to configure the PCMCIA socket, and to make the
-       ethernet device available to the system.
-*/
-
 static const char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
 
 static int tc574_config(struct pcmcia_device *link)
@@ -352,7 +335,7 @@ static int tc574_config(struct pcmcia_device *link)
        if (ret)
                goto failed;
 
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
@@ -465,12 +448,6 @@ failed:
 
 } /* tc574_config */
 
-/*
-       After a card is removed, tc574_release() will unregister the net
-       device, and release the PCMCIA configuration.  If the device is
-       still open, this will be postponed until it is closed.
-*/
-
 static void tc574_release(struct pcmcia_device *link)
 {
        pcmcia_disable_device(link);
@@ -1198,9 +1175,7 @@ MODULE_DEVICE_TABLE(pcmcia, tc574_ids);
 
 static struct pcmcia_driver tc574_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "3c574_cs",
-       },
+       .name           = "3c574_cs",
        .probe          = tc574_probe,
        .remove         = tc574_detach,
        .id_table       = tc574_ids,
index 61f9cf2100ffd8bfdff824ccfa2c3f3013a8eb1f..a07e22295330dadf2407f558e8500231e8990035 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
@@ -176,14 +175,6 @@ static const struct ethtool_ops netdev_ethtool_ops;
 
 static void tc589_detach(struct pcmcia_device *p_dev);
 
-/*======================================================================
-
-    tc589_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
 static const struct net_device_ops el3_netdev_ops = {
        .ndo_open               = el3_open,
        .ndo_stop               = el3_close,
@@ -216,9 +207,8 @@ static int tc589_probe(struct pcmcia_device *link)
     link->resource[0]->end = 16;
     link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
 
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.ConfigIndex = 1;
+    link->config_flags |= CONF_ENABLE_IRQ;
+    link->config_index = 1;
 
     dev->netdev_ops = &el3_netdev_ops;
     dev->watchdog_timeo = TX_TIMEOUT;
@@ -226,16 +216,7 @@ static int tc589_probe(struct pcmcia_device *link)
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
     return tc589_config(link);
-} /* tc589_attach */
-
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
+}
 
 static void tc589_detach(struct pcmcia_device *link)
 {
@@ -250,14 +231,6 @@ static void tc589_detach(struct pcmcia_device *link)
     free_netdev(dev);
 } /* tc589_detach */
 
-/*======================================================================
-
-    tc589_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ethernet device available to the system.
-
-======================================================================*/
-
 static int tc589_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
@@ -294,7 +267,7 @@ static int tc589_config(struct pcmcia_device *link)
     if (ret)
            goto failed;
 
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
 
@@ -352,14 +325,6 @@ failed:
     return -ENODEV;
 } /* tc589_config */
 
-/*======================================================================
-
-    After a card is removed, tc589_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void tc589_release(struct pcmcia_device *link)
 {
        pcmcia_disable_device(link);
@@ -955,9 +920,7 @@ MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
 
 static struct pcmcia_driver tc589_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "3c589_cs",
-       },
+       .name           = "3c589_cs",
        .probe          = tc589_probe,
        .remove         = tc589_detach,
        .id_table       = tc589_ids,
index 5f05ffb240cc899eb79537ffe8074ceb97d3da11..9e8b28b271ae9e48e4a798a4806a4a8c7853299a 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/mii.h>
 #include "../8390.h"
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -140,14 +139,6 @@ static const struct net_device_ops axnet_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-/*======================================================================
-
-    axnet_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
 static int axnet_probe(struct pcmcia_device *link)
 {
     axnet_dev_t *info;
@@ -166,8 +157,7 @@ static int axnet_probe(struct pcmcia_device *link)
     info = PRIV(dev);
     info->p_dev = link;
     link->priv = dev;
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->config_flags |= CONF_ENABLE_IRQ;
 
     dev->netdev_ops = &axnet_netdev_ops;
 
@@ -177,15 +167,6 @@ static int axnet_probe(struct pcmcia_device *link)
     return axnet_config(link);
 } /* axnet_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void axnet_detach(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
@@ -231,7 +212,7 @@ static int get_prom(struct pcmcia_device *link)
     };
 
     /* Not much of a test, but the alternatives are messy */
-    if (link->conf.ConfigBase != 0x03c0)
+    if (link->config_base != 0x03c0)
        return 0;
 
     axnet_reset_8390(dev);
@@ -248,14 +229,6 @@ static int get_prom(struct pcmcia_device *link)
     return 1;
 } /* get_prom */
 
-/*======================================================================
-
-    axnet_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ethernet device available to the system.
-
-======================================================================*/
-
 static int try_io_port(struct pcmcia_device *link)
 {
     int j, ret;
@@ -286,35 +259,16 @@ static int try_io_port(struct pcmcia_device *link)
     }
 }
 
-static int axnet_configcheck(struct pcmcia_device *p_dev,
-                            cistpl_cftable_entry_t *cfg,
-                            cistpl_cftable_entry_t *dflt,
-                            unsigned int vcc,
-                            void *priv_data)
+static int axnet_configcheck(struct pcmcia_device *p_dev, void *priv_data)
 {
-       int i;
-       cistpl_io_t *io = &cfg->io;
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       if (cfg->index == 0 || cfg->io.nwin == 0)
+       p_dev->config_index = 0x05;
+       if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32)
                return -ENODEV;
 
-       p_dev->conf.ConfigIndex = 0x05;
-       /* For multifunction cards, by convention, we configure the
-          network function with window 0, and serial with window 1 */
-       if (io->nwin > 1) {
-               i = (io->win[1].len > io->win[0].len);
-               p_dev->resource[1]->start = io->win[1-i].base;
-               p_dev->resource[1]->end = io->win[1-i].len;
-       } else {
-               i = p_dev->resource[1]->end = 0;
-       }
-       p_dev->resource[0]->start = io->win[i].base;
-       p_dev->resource[0]->end = io->win[i].len;
-       p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-       if (p_dev->resource[0]->end + p_dev->resource[1]->end >= 32)
-               return try_io_port(p_dev);
-
-       return -ENODEV;
+       return try_io_port(p_dev);
 }
 
 static int axnet_config(struct pcmcia_device *link)
@@ -326,20 +280,19 @@ static int axnet_config(struct pcmcia_device *link)
     dev_dbg(&link->dev, "axnet_config(0x%p)\n", link);
 
     /* don't trust the CIS on this; Linksys got it wrong */
-    link->conf.Present = 0x63;
+    link->config_regs = 0x63;
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
     ret = pcmcia_loop_config(link, axnet_configcheck, NULL);
     if (ret != 0)
        goto failed;
 
     if (!link->irq)
            goto failed;
+
+    if (resource_size(link->resource[1]) == 8)
+       link->config_flags |= CONF_ENABLE_SPKR;
     
-    if (resource_size(link->resource[1]) == 8) {
-       link->conf.Attributes |= CONF_ENABLE_SPKR;
-       link->conf.Status = CCSR_AUDIO_ENA;
-    }
-    
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
 
@@ -414,14 +367,6 @@ failed:
     return -ENODEV;
 } /* axnet_config */
 
-/*======================================================================
-
-    After a card is removed, axnet_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void axnet_release(struct pcmcia_device *link)
 {
        pcmcia_disable_device(link);
@@ -783,9 +728,7 @@ MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
 
 static struct pcmcia_driver axnet_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "axnet_cs",
-       },
+       .name           = "axnet_cs",
        .probe          = axnet_probe,
        .remove         = axnet_detach,
        .id_table       = axnet_ids,
index 3c400cfa82ae2e88c0e67c3f0582f75491be925e..b706a72494774a73dd0514e85f5a37ea52985b05 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/arcdevice.h>
 #include <linux/com20020.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -123,14 +122,6 @@ typedef struct com20020_dev_t {
     struct net_device       *dev;
 } com20020_dev_t;
 
-/*======================================================================
-
-    com20020_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
 static int com20020_probe(struct pcmcia_device *p_dev)
 {
     com20020_dev_t *info;
@@ -160,8 +151,7 @@ static int com20020_probe(struct pcmcia_device *p_dev)
 
     p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
     p_dev->resource[0]->end = 16;
-    p_dev->conf.Attributes = CONF_ENABLE_IRQ;
-    p_dev->conf.IntType = INT_MEMORY_AND_IO;
+    p_dev->config_flags |= CONF_ENABLE_IRQ;
 
     info->dev = dev;
     p_dev->priv = info;
@@ -174,15 +164,6 @@ fail_alloc_info:
     return -ENOMEM;
 } /* com20020_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void com20020_detach(struct pcmcia_device *link)
 {
     struct com20020_dev_t *info = link->priv;
@@ -221,14 +202,6 @@ static void com20020_detach(struct pcmcia_device *link)
 
 } /* com20020_detach */
 
-/*======================================================================
-
-    com20020_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    device available to the system.
-
-======================================================================*/
-
 static int com20020_config(struct pcmcia_device *link)
 {
     struct arcnet_local *lp;
@@ -282,7 +255,7 @@ static int com20020_config(struct pcmcia_device *link)
 
     dev->irq = link->irq;
 
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
 
@@ -316,14 +289,6 @@ failed:
     return -ENODEV;
 } /* com20020_config */
 
-/*======================================================================
-
-    After a card is removed, com20020_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void com20020_release(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "com20020_release\n");
@@ -366,9 +331,7 @@ MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
 
 static struct pcmcia_driver com20020_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "com20020_cs",
-       },
+       .name           = "com20020_cs",
        .probe          = com20020_probe,
        .remove         = com20020_detach,
        .id_table       = com20020_ids,
index 98fffb03ecd7f4714c068d7a47c5acf667423cac..1c327598bbe80efaa346d4f460ce54461f898368 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/ioport.h>
 #include <linux/crc32.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -252,8 +251,7 @@ static int fmvj18x_probe(struct pcmcia_device *link)
     link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
 
     /* General socket configuration */
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->config_flags |= CONF_ENABLE_IRQ;
 
     dev->netdev_ops = &fjn_netdev_ops;
     dev->watchdog_timeo = TX_TIMEOUT;
@@ -313,7 +311,7 @@ static int ungermann_try_io_port(struct pcmcia_device *link)
        ret = pcmcia_request_io(link);
        if (ret == 0) {
            /* calculate ConfigIndex value */
-           link->conf.ConfigIndex = 
+           link->config_index =
                ((link->resource[0]->start & 0x0f0) >> 3) | 0x22;
            return ret;
        }
@@ -321,11 +319,7 @@ static int ungermann_try_io_port(struct pcmcia_device *link)
     return ret;        /* RequestIO failed */
 }
 
-static int fmvj18x_ioprobe(struct pcmcia_device *p_dev,
-                          cistpl_cftable_entry_t *cfg,
-                          cistpl_cftable_entry_t *dflt,
-                          unsigned int vcc,
-                          void *priv_data)
+static int fmvj18x_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
 {
        return 0; /* strange, but that's what the code did already before... */
 }
@@ -362,28 +356,28 @@ static int fmvj18x_config(struct pcmcia_device *link)
                link->card_id == PRODID_TDK_NP9610 ||
                link->card_id == PRODID_TDK_MN3200) {
                /* MultiFunction Card */
-               link->conf.ConfigBase = 0x800;
-               link->conf.ConfigIndex = 0x47;
+               link->config_base = 0x800;
+               link->config_index = 0x47;
                link->resource[1]->end = 8;
            }
            break;
        case MANFID_NEC:
            cardtype = NEC; /* MultiFunction Card */
-           link->conf.ConfigBase = 0x800;
-           link->conf.ConfigIndex = 0x47;
+           link->config_base = 0x800;
+           link->config_index = 0x47;
            link->resource[1]->end = 8;
            break;
        case MANFID_KME:
            cardtype = KME; /* MultiFunction Card */
-           link->conf.ConfigBase = 0x800;
-           link->conf.ConfigIndex = 0x47;
+           link->config_base = 0x800;
+           link->config_index = 0x47;
            link->resource[1]->end = 8;
            break;
        case MANFID_CONTEC:
            cardtype = CONTEC;
            break;
        case MANFID_FUJITSU:
-           if (link->conf.ConfigBase == 0x0fe0)
+           if (link->config_base == 0x0fe0)
                cardtype = MBH10302;
            else if (link->card_id == PRODID_FUJITSU_MBH10302) 
                 /* RATOC REX-5588/9822/4886's PRODID are 0004(=MBH10302),
@@ -403,10 +397,10 @@ static int fmvj18x_config(struct pcmcia_device *link)
        case MANFID_FUJITSU:
            if (link->card_id == PRODID_FUJITSU_MBH10304) {
                cardtype = XXX10304;    /* MBH10304 with buggy CIS */
-               link->conf.ConfigIndex = 0x20;
+               link->config_index = 0x20;
            } else {
                cardtype = MBH10302;    /* NextCom NC5310, etc. */
-               link->conf.ConfigIndex = 1;
+               link->config_index = 1;
            }
            break;
        case MANFID_UNGERMANN:
@@ -414,7 +408,7 @@ static int fmvj18x_config(struct pcmcia_device *link)
            break;
        default:
            cardtype = MBH10302;
-           link->conf.ConfigIndex = 1;
+           link->config_index = 1;
        }
     }
 
@@ -432,7 +426,7 @@ static int fmvj18x_config(struct pcmcia_device *link)
     ret = pcmcia_request_irq(link, fjn_interrupt);
     if (ret)
            goto failed;
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
 
@@ -544,20 +538,18 @@ failed:
 
 static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
 {
-    win_req_t req;
     u_char __iomem *base;
     int i, j;
 
     /* Allocate a small memory window */
-    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    req.Base = 0; req.Size = 0;
-    req.AccessSpeed = 0;
-    i = pcmcia_request_window(link, &req, &link->win);
+    link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    link->resource[2]->start = 0; link->resource[2]->end = 0;
+    i = pcmcia_request_window(link, link->resource[2], 0);
     if (i != 0)
        return -1;
 
-    base = ioremap(req.Base, req.Size);
-    pcmcia_map_mem_page(link, link->win, 0);
+    base = ioremap(link->resource[2]->start, resource_size(link->resource[2]));
+    pcmcia_map_mem_page(link, link->resource[2], 0);
 
     /*
      *  MBH10304 CISTPL_FUNCE_LAN_NODE_ID format
@@ -582,7 +574,7 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
     }
 
     iounmap(base);
-    j = pcmcia_release_window(link, link->win);
+    j = pcmcia_release_window(link, link->resource[2]);
     return (i != 0x200) ? 0 : -1;
 
 } /* fmvj18x_get_hwinfo */
@@ -590,27 +582,26 @@ static int fmvj18x_get_hwinfo(struct pcmcia_device *link, u_char *node_id)
 
 static int fmvj18x_setup_mfc(struct pcmcia_device *link)
 {
-    win_req_t req;
     int i;
     struct net_device *dev = link->priv;
     unsigned int ioaddr;
     local_info_t *lp = netdev_priv(dev);
 
     /* Allocate a small memory window */
-    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    req.Base = 0; req.Size = 0;
-    req.AccessSpeed = 0;
-    i = pcmcia_request_window(link, &req, &link->win);
+    link->resource[3]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    link->resource[3]->start = link->resource[3]->end = 0;
+    i = pcmcia_request_window(link, link->resource[3], 0);
     if (i != 0)
        return -1;
 
-    lp->base = ioremap(req.Base, req.Size);
+    lp->base = ioremap(link->resource[3]->start,
+                      resource_size(link->resource[3]));
     if (lp->base == NULL) {
        printk(KERN_NOTICE "fmvj18x_cs: ioremap failed\n");
        return -1;
     }
 
-    i = pcmcia_map_mem_page(link, link->win, 0);
+    i = pcmcia_map_mem_page(link, link->resource[3], 0);
     if (i != 0) {
        iounmap(lp->base);
        lp->base = NULL;
@@ -638,7 +629,6 @@ static void fmvj18x_release(struct pcmcia_device *link)
     struct net_device *dev = link->priv;
     local_info_t *lp = netdev_priv(dev);
     u_char __iomem *tmp;
-    int j;
 
     dev_dbg(&link->dev, "fmvj18x_release\n");
 
@@ -646,7 +636,6 @@ static void fmvj18x_release(struct pcmcia_device *link)
        tmp = lp->base;
        lp->base = NULL;    /* set NULL before iounmap */
        iounmap(tmp);
-       j = pcmcia_release_window(link, link->win);
     }
 
     pcmcia_disable_device(link);
@@ -708,9 +697,7 @@ MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids);
 
 static struct pcmcia_driver fmvj18x_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "fmvj18x_cs",
-       },
+       .name           = "fmvj18x_cs",
        .probe          = fmvj18x_probe,
        .remove         = fmvj18x_detach,
        .id_table       = fmvj18x_ids,
index b0d06a3d962fc235fdc22c8f5af840272a5574d3..bf7dff96d881d20ade26849c61604882709e4fd2 100644 (file)
@@ -57,7 +57,6 @@
 #include <linux/trdevice.h>
 #include <linux/ibmtr.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -102,9 +101,8 @@ static void ibmtr_detach(struct pcmcia_device *p_dev);
 
 typedef struct ibmtr_dev_t {
        struct pcmcia_device    *p_dev;
-    struct net_device  *dev;
-    window_handle_t     sram_win_handle;
-    struct tok_info    *ti;
+       struct net_device       *dev;
+       struct tok_info         *ti;
 } ibmtr_dev_t;
 
 static void netdev_get_drvinfo(struct net_device *dev,
@@ -123,14 +121,6 @@ static irqreturn_t ibmtr_interrupt(int irq, void *dev_id) {
        return tok_interrupt(irq, dev);
 };
 
-/*======================================================================
-
-    ibmtr_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
 static int __devinit ibmtr_attach(struct pcmcia_device *link)
 {
     ibmtr_dev_t *info;
@@ -153,9 +143,8 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link)
 
     link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
     link->resource[0]->end = 4;
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.Present = PRESENT_OPTION;
+    link->config_flags |= CONF_ENABLE_IRQ;
+    link->config_regs = PRESENT_OPTION;
 
     info->dev = dev;
 
@@ -164,15 +153,6 @@ static int __devinit ibmtr_attach(struct pcmcia_device *link)
     return ibmtr_config(link);
 } /* ibmtr_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void ibmtr_detach(struct pcmcia_device *link)
 {
     struct ibmtr_dev_t *info = link->priv;
@@ -197,26 +177,17 @@ static void ibmtr_detach(struct pcmcia_device *link)
     kfree(info);
 } /* ibmtr_detach */
 
-/*======================================================================
-
-    ibmtr_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    token-ring device available to the system.
-
-======================================================================*/
-
 static int __devinit ibmtr_config(struct pcmcia_device *link)
 {
     ibmtr_dev_t *info = link->priv;
     struct net_device *dev = info->dev;
     struct tok_info *ti = netdev_priv(dev);
-    win_req_t req;
     int i, ret;
 
     dev_dbg(&link->dev, "ibmtr_config\n");
 
-    link->conf.ConfigIndex = 0x61;
     link->io_lines = 16;
+    link->config_index = 0x61;
 
     /* Determine if this is PRIMARY or ALTERNATE. */
 
@@ -240,39 +211,39 @@ static int __devinit ibmtr_config(struct pcmcia_device *link)
     ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
 
     /* Allocate the MMIO memory window */
-    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
-    req.Attributes |= WIN_USE_WAIT;
-    req.Base = 0; 
-    req.Size = 0x2000;
-    req.AccessSpeed = 250;
-    ret = pcmcia_request_window(link, &req, &link->win);
+    link->resource[2]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    link->resource[2]->flags |= WIN_USE_WAIT;
+    link->resource[2]->start = 0;
+    link->resource[2]->end = 0x2000;
+    ret = pcmcia_request_window(link, link->resource[2], 250);
     if (ret)
            goto failed;
 
-    ret = pcmcia_map_mem_page(link, link->win, mmiobase);
+    ret = pcmcia_map_mem_page(link, link->resource[2], mmiobase);
     if (ret)
            goto failed;
-    ti->mmio = ioremap(req.Base, req.Size);
+    ti->mmio = ioremap(link->resource[2]->start,
+                   resource_size(link->resource[2]));
 
     /* Allocate the SRAM memory window */
-    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
-    req.Attributes |= WIN_USE_WAIT;
-    req.Base = 0;
-    req.Size = sramsize * 1024;
-    req.AccessSpeed = 250;
-    ret = pcmcia_request_window(link, &req, &info->sram_win_handle);
+    link->resource[3]->flags = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    link->resource[3]->flags |= WIN_USE_WAIT;
+    link->resource[3]->start = 0;
+    link->resource[3]->end = sramsize * 1024;
+    ret = pcmcia_request_window(link, link->resource[3], 250);
     if (ret)
            goto failed;
 
-    ret = pcmcia_map_mem_page(link, info->sram_win_handle, srambase);
+    ret = pcmcia_map_mem_page(link, link->resource[3], srambase);
     if (ret)
            goto failed;
 
     ti->sram_base = srambase >> 12;
-    ti->sram_virt = ioremap(req.Base, req.Size);
-    ti->sram_phys = req.Base;
+    ti->sram_virt = ioremap(link->resource[3]->start,
+                   resource_size(link->resource[3]));
+    ti->sram_phys = link->resource[3]->start;
 
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
 
@@ -301,14 +272,6 @@ failed:
     return -ENODEV;
 } /* ibmtr_config */
 
-/*======================================================================
-
-    After a card is removed, ibmtr_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void ibmtr_release(struct pcmcia_device *link)
 {
        ibmtr_dev_t *info = link->priv;
@@ -316,7 +279,7 @@ static void ibmtr_release(struct pcmcia_device *link)
 
        dev_dbg(&link->dev, "ibmtr_release\n");
 
-       if (link->win) {
+       if (link->resource[2]->end) {
                struct tok_info *ti = netdev_priv(dev);
                iounmap(ti->mmio);
        }
@@ -398,9 +361,7 @@ MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
 
 static struct pcmcia_driver ibmtr_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "ibmtr_cs",
-       },
+       .name           = "ibmtr_cs",
        .probe          = ibmtr_attach,
        .remove         = ibmtr_detach,
        .id_table       = ibmtr_ids,
index 68f2deeb3ade11722dc5333386f4afd56cc98eb3..1eca4f5a6e78b3824d3129a28a535764c0eefb98 100644 (file)
@@ -146,7 +146,6 @@ Include Files
 #include <linux/ioport.h>
 #include <linux/bitops.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
@@ -435,13 +434,6 @@ static const struct net_device_ops mace_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-/* ----------------------------------------------------------------------------
-nmclan_attach
-       Creates an "instance" of the driver, allocating local data
-       structures for one device.  The device is registered with Card
-       Services.
----------------------------------------------------------------------------- */
-
 static int nmclan_probe(struct pcmcia_device *link)
 {
     mace_private *lp;
@@ -460,10 +452,9 @@ static int nmclan_probe(struct pcmcia_device *link)
     spin_lock_init(&lp->bank_lock);
     link->resource[0]->end = 32;
     link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.ConfigIndex = 1;
-    link->conf.Present = PRESENT_OPTION;
+    link->config_flags |= CONF_ENABLE_IRQ;
+    link->config_index = 1;
+    link->config_regs = PRESENT_OPTION;
 
     lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
 
@@ -474,14 +465,6 @@ static int nmclan_probe(struct pcmcia_device *link)
     return nmclan_config(link);
 } /* nmclan_attach */
 
-/* ----------------------------------------------------------------------------
-nmclan_detach
-       This deletes a driver "instance".  The device is de-registered
-       with Card Services.  If it has been released, all local data
-       structures are freed.  Otherwise, the structures will be freed
-       when the device is released.
----------------------------------------------------------------------------- */
-
 static void nmclan_detach(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
@@ -625,13 +608,6 @@ static int mace_init(mace_private *lp, unsigned int ioaddr, char *enet_addr)
   return 0;
 } /* mace_init */
 
-/* ----------------------------------------------------------------------------
-nmclan_config
-       This routine is scheduled to run after a CARD_INSERTION event
-       is received, to configure the PCMCIA socket, and to make the
-       ethernet device available to the system.
----------------------------------------------------------------------------- */
-
 static int nmclan_config(struct pcmcia_device *link)
 {
   struct net_device *dev = link->priv;
@@ -650,7 +626,7 @@ static int nmclan_config(struct pcmcia_device *link)
   ret = pcmcia_request_exclusive_irq(link, mace_interrupt);
   if (ret)
          goto failed;
-  ret = pcmcia_request_configuration(link, &link->conf);
+  ret = pcmcia_enable_device(link);
   if (ret)
          goto failed;
 
@@ -712,12 +688,6 @@ failed:
        return -ENODEV;
 } /* nmclan_config */
 
-/* ----------------------------------------------------------------------------
-nmclan_release
-       After a card is removed, nmclan_release() will unregister the
-       net device, and release the PCMCIA configuration.  If the device
-       is still open, this will be postponed until it is closed.
----------------------------------------------------------------------------- */
 static void nmclan_release(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "nmclan_release\n");
@@ -1535,9 +1505,7 @@ MODULE_DEVICE_TABLE(pcmcia, nmclan_ids);
 
 static struct pcmcia_driver nmclan_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "nmclan_cs",
-       },
+       .name           = "nmclan_cs",
        .probe          = nmclan_probe,
        .remove         = nmclan_detach,
        .id_table       = nmclan_ids,
index f9b509a6b09a702d214ed2821d3bf6a79a671b49..5d7d1d3088ae148b6491fc07482b0970178b9466 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/mii.h>
 #include "../8390.h"
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -238,14 +237,6 @@ static const struct net_device_ops pcnet_netdev_ops = {
 #endif
 };
 
-/*======================================================================
-
-    pcnet_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
 static int pcnet_probe(struct pcmcia_device *link)
 {
     pcnet_dev_t *info;
@@ -260,23 +251,13 @@ static int pcnet_probe(struct pcmcia_device *link)
     info->p_dev = link;
     link->priv = dev;
 
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 
     dev->netdev_ops = &pcnet_netdev_ops;
 
     return pcnet_config(link);
 } /* pcnet_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void pcnet_detach(struct pcmcia_device *link)
 {
        struct net_device *dev = link->priv;
@@ -300,22 +281,22 @@ static void pcnet_detach(struct pcmcia_device *link)
 static hw_info_t *get_hwinfo(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
-    win_req_t req;
     u_char __iomem *base, *virt;
     int i, j;
 
     /* Allocate a small memory window */
-    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    req.Base = 0; req.Size = 0;
-    req.AccessSpeed = 0;
-    i = pcmcia_request_window(link, &req, &link->win);
+    link->resource[2]->flags |= WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    link->resource[2]->start = 0; link->resource[2]->end = 0;
+    i = pcmcia_request_window(link, link->resource[2], 0);
     if (i != 0)
        return NULL;
 
-    virt = ioremap(req.Base, req.Size);
+    virt = ioremap(link->resource[2]->start,
+           resource_size(link->resource[2]));
     for (i = 0; i < NR_INFO; i++) {
-       pcmcia_map_mem_page(link, link->win, hw_info[i].offset & ~(req.Size-1));
-       base = &virt[hw_info[i].offset & (req.Size-1)];
+       pcmcia_map_mem_page(link, link->resource[2],
+               hw_info[i].offset & ~(resource_size(link->resource[2])-1));
+       base = &virt[hw_info[i].offset & (resource_size(link->resource[2])-1)];
        if ((readb(base+0) == hw_info[i].a0) &&
            (readb(base+2) == hw_info[i].a1) &&
            (readb(base+4) == hw_info[i].a2)) {
@@ -326,7 +307,7 @@ static hw_info_t *get_hwinfo(struct pcmcia_device *link)
     }
 
     iounmap(virt);
-    j = pcmcia_release_window(link, link->win);
+    j = pcmcia_release_window(link, link->resource[2]);
     return (i < NR_INFO) ? hw_info+i : NULL;
 } /* get_hwinfo */
 
@@ -421,7 +402,7 @@ static hw_info_t *get_ax88190(struct pcmcia_device *link)
     int i, j;
 
     /* Not much of a test, but the alternatives are messy */
-    if (link->conf.ConfigBase != 0x03c0)
+    if (link->config_base != 0x03c0)
        return NULL;
 
     outb_p(0x01, ioaddr + EN0_DCFG);   /* Set word-wide access. */
@@ -463,14 +444,6 @@ static hw_info_t *get_hwired(struct pcmcia_device *link)
     return &default_info;
 } /* get_hwired */
 
-/*======================================================================
-
-    pcnet_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ethernet device available to the system.
-
-======================================================================*/
-
 static int try_io_port(struct pcmcia_device *link)
 {
     int j, ret;
@@ -502,43 +475,22 @@ static int try_io_port(struct pcmcia_device *link)
     }
 }
 
-static int pcnet_confcheck(struct pcmcia_device *p_dev,
-                          cistpl_cftable_entry_t *cfg,
-                          cistpl_cftable_entry_t *dflt,
-                          unsigned int vcc,
-                          void *priv_data)
+static int pcnet_confcheck(struct pcmcia_device *p_dev, void *priv_data)
 {
        int *priv = priv_data;
        int try = (*priv & 0x1);
-       int i;
-       cistpl_io_t *io = &cfg->io;
 
-       if (cfg->index == 0 || cfg->io.nwin == 0)
-               return -EINVAL;
+       *priv &= (p_dev->resource[2]->end >= 0x4000) ? 0x10 : ~0x10;
 
-       /* For multifunction cards, by convention, we configure the
-          network function with window 0, and serial with window 1 */
-       if (io->nwin > 1) {
-               i = (io->win[1].len > io->win[0].len);
-               p_dev->resource[1]->start = io->win[1-i].base;
-               p_dev->resource[1]->end = io->win[1-i].len;
-       } else {
-               i = p_dev->resource[1]->end = 0;
-       }
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       *priv &= ((cfg->mem.nwin == 1) &&
-                 (cfg->mem.win[0].len >= 0x4000)) ? 0x10 : ~0x10;
+       if (p_dev->resource[0]->end + p_dev->resource[1]->end < 32)
+               return -EINVAL;
 
-       p_dev->resource[0]->start = io->win[i].base;
-       p_dev->resource[0]->end = io->win[i].len;
-       if (!try)
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-       else
+       if (try)
                p_dev->io_lines = 16;
-       if (p_dev->resource[0]->end + p_dev->resource[1]->end >= 32)
-               return try_io_port(p_dev);
-
-       return -EINVAL;
+       return try_io_port(p_dev);
 }
 
 static hw_info_t *pcnet_try_config(struct pcmcia_device *link,
@@ -560,15 +512,14 @@ static hw_info_t *pcnet_try_config(struct pcmcia_device *link,
        if (!link->irq)
                return NULL;
 
-       if (resource_size(link->resource[1]) == 8) {
-               link->conf.Attributes |= CONF_ENABLE_SPKR;
-               link->conf.Status = CCSR_AUDIO_ENA;
-       }
+       if (resource_size(link->resource[1]) == 8)
+               link->config_flags |= CONF_ENABLE_SPKR;
+
        if ((link->manf_id == MANFID_IBM) &&
            (link->card_id == PRODID_IBM_HOME_AND_AWAY))
-               link->conf.ConfigIndex |= 0x10;
+               link->config_index |= 0x10;
 
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                return NULL;
 
@@ -583,7 +534,7 @@ static hw_info_t *pcnet_try_config(struct pcmcia_device *link,
        } else
                dev->if_port = 0;
 
-       if ((link->conf.ConfigBase == 0x03c0) &&
+       if ((link->config_base == 0x03c0) &&
            (link->manf_id == 0x149) && (link->card_id == 0xc1ab)) {
                dev_info(&link->dev,
                        "this is an AX88190 card - use axnet_cs instead.\n");
@@ -689,14 +640,6 @@ failed:
     return -ENODEV;
 } /* pcnet_config */
 
-/*======================================================================
-
-    After a card is removed, pcnet_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void pcnet_release(struct pcmcia_device *link)
 {
        pcnet_dev_t *info = PRIV(link->priv);
@@ -709,15 +652,6 @@ static void pcnet_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }
 
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.  A CARD_REMOVAL event
-    also sets some flags to discourage the net drivers from trying
-    to talk to the card any more.
-
-======================================================================*/
-
 static int pcnet_suspend(struct pcmcia_device *link)
 {
        struct net_device *dev = link->priv;
@@ -1486,7 +1420,6 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
 {
     struct net_device *dev = link->priv;
     pcnet_dev_t *info = PRIV(dev);
-    win_req_t req;
     int i, window_size, offset, ret;
 
     window_size = (stop_pg - start_pg) << 8;
@@ -1497,22 +1430,22 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
     window_size = roundup_pow_of_two(window_size);
 
     /* Allocate a memory window */
-    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
-    req.Attributes |= WIN_USE_WAIT;
-    req.Base = 0; req.Size = window_size;
-    req.AccessSpeed = mem_speed;
-    ret = pcmcia_request_window(link, &req, &link->win);
+    link->resource[3]->flags |= WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    link->resource[3]->flags |= WIN_USE_WAIT;
+    link->resource[3]->start = 0; link->resource[3]->end = window_size;
+    ret = pcmcia_request_window(link, link->resource[3], mem_speed);
     if (ret)
            goto failed;
 
     offset = (start_pg << 8) + cm_offset;
     offset -= offset % window_size;
-    ret = pcmcia_map_mem_page(link, link->win, offset);
+    ret = pcmcia_map_mem_page(link, link->resource[3], offset);
     if (ret)
            goto failed;
 
     /* Try scribbling on the buffer */
-    info->base = ioremap(req.Base, window_size);
+    info->base = ioremap(link->resource[3]->start,
+                       resource_size(link->resource[3]));
     for (i = 0; i < (TX_PAGES<<8); i += 2)
        __raw_writew((i>>1), info->base+offset+i);
     udelay(100);
@@ -1521,19 +1454,20 @@ static int setup_shmem_window(struct pcmcia_device *link, int start_pg,
     pcnet_reset_8390(dev);
     if (i != (TX_PAGES<<8)) {
        iounmap(info->base);
-       pcmcia_release_window(link, link->win);
-       info->base = NULL; link->win = 0;
+       pcmcia_release_window(link, link->resource[3]);
+       info->base = NULL;
        goto failed;
     }
 
     ei_status.mem = info->base + offset;
-    ei_status.priv = req.Size;
+    ei_status.priv = resource_size(link->resource[3]);
     dev->mem_start = (u_long)ei_status.mem;
-    dev->mem_end = dev->mem_start + req.Size;
+    dev->mem_end = dev->mem_start + resource_size(link->resource[3]);
 
     ei_status.tx_start_page = start_pg;
     ei_status.rx_start_page = start_pg + TX_PAGES;
-    ei_status.stop_page = start_pg + ((req.Size - offset) >> 8);
+    ei_status.stop_page = start_pg + (
+           (resource_size(link->resource[3]) - offset) >> 8);
 
     /* set up block i/o functions */
     ei_status.get_8390_hdr = &shmem_get_8390_hdr;
@@ -1772,9 +1706,7 @@ MODULE_FIRMWARE("cis/PE-200.cis");
 MODULE_FIRMWARE("cis/tamarack.cis");
 
 static struct pcmcia_driver pcnet_driver = {
-       .drv            = {
-               .name   = "pcnet_cs",
-       },
+       .name           = "pcnet_cs",
        .probe          = pcnet_probe,
        .remove         = pcnet_detach,
        .owner          = THIS_MODULE,
index 377367d03b419dd7907262bfaedaf3acc0d60aca..0af2fc8ec164a7b2a200ee0452777538d93d4b4e 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/jiffies.h>
 #include <linux/firmware.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
@@ -300,14 +299,6 @@ static const struct net_device_ops smc_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-/*======================================================================
-
-  smc91c92_attach() creates an "instance" of the driver, allocating
-  local data structures for one device.  The device is registered
-  with Card Services.
-
-======================================================================*/
-
 static int smc91c92_probe(struct pcmcia_device *link)
 {
     struct smc_private *smc;
@@ -324,10 +315,6 @@ static int smc91c92_probe(struct pcmcia_device *link)
     link->priv = dev;
 
     spin_lock_init(&smc->lock);
-    link->resource[0]->end = 16;
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
 
     /* The SMC91c92-specific entries in the device structure. */
     dev->netdev_ops = &smc_netdev_ops;
@@ -343,15 +330,6 @@ static int smc91c92_probe(struct pcmcia_device *link)
     return smc91c92_config(link);
 } /* smc91c92_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void smc91c92_detach(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
@@ -412,26 +390,28 @@ static int mhz_3288_power(struct pcmcia_device *link)
     mdelay(200);
 
     /* Now read and write the COR... */
-    tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR);
+    tmp = readb(smc->base + link->config_base + CISREG_COR);
     udelay(5);
-    writeb(tmp, smc->base + link->conf.ConfigBase + CISREG_COR);
+    writeb(tmp, smc->base + link->config_base + CISREG_COR);
 
     return 0;
 }
 
-static int mhz_mfc_config_check(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cf,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
-                               void *priv_data)
+static int mhz_mfc_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
        int k;
-       p_dev->resource[1]->start = cf->io.win[0].base;
+       p_dev->io_lines = 16;
+       p_dev->resource[1]->start = p_dev->resource[0]->start;
+       p_dev->resource[1]->end = 8;
+       p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[0]->end = 16;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
        for (k = 0; k < 0x400; k += 0x10) {
                if (k & 0x80)
                        continue;
                p_dev->resource[0]->start = k ^ 0x300;
-               p_dev->io_lines = 16;
                if (!pcmcia_request_io(p_dev))
                        return 0;
        }
@@ -442,14 +422,11 @@ static int mhz_mfc_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
     struct smc_private *smc = netdev_priv(dev);
-    win_req_t req;
     unsigned int offset;
     int i;
 
-    link->conf.Attributes |= CONF_ENABLE_SPKR;
-    link->conf.Status = CCSR_AUDIO_ENA;
-    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-    link->resource[1]->end = 8;
+    link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ |
+           CONF_AUTO_SET_IO;
 
     /* The Megahertz combo cards have modem-like CIS entries, so
        we have to explicitly try a bunch of port combinations. */
@@ -459,16 +436,16 @@ static int mhz_mfc_config(struct pcmcia_device *link)
     dev->base_addr = link->resource[0]->start;
 
     /* Allocate a memory window, for accessing the ISR */
-    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-    req.Base = req.Size = 0;
-    req.AccessSpeed = 0;
-    i = pcmcia_request_window(link, &req, &link->win);
+    link->resource[2]->flags = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    link->resource[2]->start = link->resource[2]->end = 0;
+    i = pcmcia_request_window(link, link->resource[2], 0);
     if (i != 0)
            return -ENODEV;
 
-    smc->base = ioremap(req.Base, req.Size);
-    offset = (smc->manfid == MANFID_MOTOROLA) ? link->conf.ConfigBase : 0;
-    i = pcmcia_map_mem_page(link, link->win, offset);
+    smc->base = ioremap(link->resource[2]->start,
+                   resource_size(link->resource[2]));
+    offset = (smc->manfid == MANFID_MOTOROLA) ? link->config_base : 0;
+    i = pcmcia_map_mem_page(link, link->resource[2], offset);
     if ((i == 0) &&
        (smc->manfid == MANFID_MEGAHERTZ) &&
        (smc->cardid == PRODID_MEGAHERTZ_EM3288))
@@ -591,14 +568,12 @@ static int mot_setup(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static int smc_configcheck(struct pcmcia_device *p_dev,
-                          cistpl_cftable_entry_t *cf,
-                          cistpl_cftable_entry_t *dflt,
-                          unsigned int vcc,
-                          void *priv_data)
+static int smc_configcheck(struct pcmcia_device *p_dev, void *priv_data)
 {
-       p_dev->resource[0]->start = cf->io.win[0].base;
-       p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
+       p_dev->resource[0]->end = 16;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+
        return pcmcia_request_io(p_dev);
 }
 
@@ -607,7 +582,8 @@ static int smc_config(struct pcmcia_device *link)
     struct net_device *dev = link->priv;
     int i;
 
-    link->resource[0]->end = 16;
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+
     i = pcmcia_loop_config(link, smc_configcheck, NULL);
     if (!i)
            dev->base_addr = link->resource[0]->start;
@@ -640,15 +616,14 @@ static int osi_config(struct pcmcia_device *link)
     static const unsigned int com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
     int i, j;
 
-    link->conf.Attributes |= CONF_ENABLE_SPKR;
-    link->conf.Status = CCSR_AUDIO_ENA;
+    link->config_flags |= CONF_ENABLE_SPKR | CONF_ENABLE_IRQ;
     link->resource[0]->end = 64;
     link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
     link->resource[1]->end = 8;
 
     /* Enable Hard Decode, LAN, Modem */
-    link->conf.ConfigIndex = 0x23;
     link->io_lines = 16;
+    link->config_index = 0x23;
 
     for (i = j = 0; j < 4; j++) {
        link->resource[1]->start = com[j];
@@ -658,7 +633,7 @@ static int osi_config(struct pcmcia_device *link)
     }
     if (i != 0) {
        /* Fallback: turn off hard decode */
-       link->conf.ConfigIndex = 0x03;
+       link->config_index = 0x03;
        link->resource[1]->end = 0;
        i = pcmcia_request_io(link);
     }
@@ -817,27 +792,16 @@ static int check_sig(struct pcmcia_device *link)
     }
 
     if (width) {
-           modconf_t mod = {
-                   .Attributes = CONF_IO_CHANGE_WIDTH,
-           };
            printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
 
            smc91c92_suspend(link);
-           pcmcia_modify_configuration(link, &mod);
+           pcmcia_fixup_iowidth(link);
            smc91c92_resume(link);
            return check_sig(link);
     }
     return -ENODEV;
 }
 
-/*======================================================================
-
-    smc91c92_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ethernet device available to the system.
-
-======================================================================*/
-
 static int smc91c92_config(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv;
@@ -869,7 +833,7 @@ static int smc91c92_config(struct pcmcia_device *link)
     i = pcmcia_request_irq(link, smc_interrupt);
     if (i)
            goto config_failed;
-    i = pcmcia_request_configuration(link, &link->conf);
+    i = pcmcia_enable_device(link);
     if (i)
            goto config_failed;
 
@@ -988,18 +952,10 @@ config_failed:
     return -ENODEV;
 } /* smc91c92_config */
 
-/*======================================================================
-
-    After a card is removed, smc91c92_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void smc91c92_release(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "smc91c92_release\n");
-       if (link->win) {
+       if (link->resource[2]->end) {
                struct net_device *dev = link->priv;
                struct smc_private *smc = netdev_priv(dev);
                iounmap(smc->base);
@@ -2101,9 +2057,7 @@ MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);
 
 static struct pcmcia_driver smc91c92_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "smc91c92_cs",
-       },
+       .name           = "smc91c92_cs",
        .probe          = smc91c92_probe,
        .remove         = smc91c92_detach,
        .id_table       = smc91c92_ids,
index f5819526b5ee90c25a8630a63fc81f04b64ffb0e..1fece617c069b68ddb6b384741bf43519d52b99c 100644 (file)
@@ -82,7 +82,6 @@
 #include <linux/bitops.h>
 #include <linux/mii.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
@@ -267,33 +266,11 @@ static unsigned mii_rd(unsigned int ioaddr, u_char phyaddr, u_char phyreg);
 static void mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg,
                   unsigned data, int len);
 
-/*
- * The event() function is this driver's Card Services event handler.
- * It will be called by Card Services when an appropriate card status
- * event is received.  The config() and release() entry points are
- * used to configure or release a socket, in response to card insertion
- * and ejection events.  They are invoked from the event handler.
- */
-
 static int has_ce2_string(struct pcmcia_device * link);
 static int xirc2ps_config(struct pcmcia_device * link);
 static void xirc2ps_release(struct pcmcia_device * link);
-
-/****************
- * The attach() and detach() entry points are used to create and destroy
- * "instances" of the driver, where each instance represents everything
- * needed to manage one actual PCMCIA card.
- */
-
 static void xirc2ps_detach(struct pcmcia_device *p_dev);
 
-/****************
- * You'll also need to prototype all the functions that will actually
- * be used to talk to your device.  See 'pcmem_cs' for a good example
- * of a fully self-sufficient driver; the other drivers rely more or
- * less on other parts of the kernel.
- */
-
 static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id);
 
 typedef struct local_info_t {
@@ -501,16 +478,6 @@ static const struct net_device_ops netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-/****************
- * xirc2ps_attach() creates an "instance" of the driver, allocating
- * local data structures for one device.  The device is registered
- * with Card Services.
- *
- * The dev_link structure is initialized, but we don't actually
- * configure the card at this point -- we wait until we receive a
- * card insertion event.
- */
-
 static int
 xirc2ps_probe(struct pcmcia_device *link)
 {
@@ -529,9 +496,7 @@ xirc2ps_probe(struct pcmcia_device *link)
     link->priv = dev;
 
     /* General socket configuration */
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.ConfigIndex = 1;
+    link->config_index = 1;
 
     /* Fill in card specific entries */
     dev->netdev_ops = &netdev_ops;
@@ -542,13 +507,6 @@ xirc2ps_probe(struct pcmcia_device *link)
     return xirc2ps_config(link);
 } /* xirc2ps_attach */
 
-/****************
- *  This deletes a driver "instance".  The device is de-registered
- *  with Card Services.  If it has been released, all local data
- *  structures are freed.  Otherwise, the structures will be freed
- *  when the device is released.
- */
-
 static void
 xirc2ps_detach(struct pcmcia_device *link)
 {
@@ -667,44 +625,53 @@ has_ce2_string(struct pcmcia_device * p_dev)
 }
 
 static int
-xirc2ps_config_modem(struct pcmcia_device *p_dev,
-                    cistpl_cftable_entry_t *cf,
-                    cistpl_cftable_entry_t *dflt,
-                    unsigned int vcc,
-                    void *priv_data)
+xirc2ps_config_modem(struct pcmcia_device *p_dev, void *priv_data)
 {
        unsigned int ioaddr;
 
-       if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8) {
-               for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
-                       p_dev->resource[1]->start = cf->io.win[0].base;
-                       p_dev->resource[0]->start = ioaddr;
-                       if (!pcmcia_request_io(p_dev))
-                               return 0;
-               }
+       if ((p_dev->resource[0]->start & 0xf) == 8)
+               return -ENODEV;
+
+       p_dev->resource[0]->end = 16;
+       p_dev->resource[1]->end = 8;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
+       p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->io_lines = 10;
+
+       p_dev->resource[1]->start = p_dev->resource[0]->start;
+       for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
+               p_dev->resource[0]->start = ioaddr;
+               if (!pcmcia_request_io(p_dev))
+                       return 0;
        }
        return -ENODEV;
 }
 
 static int
-xirc2ps_config_check(struct pcmcia_device *p_dev,
-                    cistpl_cftable_entry_t *cf,
-                    cistpl_cftable_entry_t *dflt,
-                    unsigned int vcc,
-                    void *priv_data)
+xirc2ps_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
        int *pass = priv_data;
+       resource_size_t tmp = p_dev->resource[1]->start;
 
-       if (cf->io.nwin > 0 && (cf->io.win[0].base & 0xf) == 8) {
-               p_dev->resource[1]->start = cf->io.win[0].base;
-               p_dev->resource[0]->start = p_dev->resource[1]->start
-                       + (*pass ? (cf->index & 0x20 ? -24:8)
-                          : (cf->index & 0x20 ?   8:-24));
-               if (!pcmcia_request_io(p_dev))
-                       return 0;
-       }
-       return -ENODEV;
+       tmp += (*pass ? (p_dev->config_index & 0x20 ? -24 : 8)
+               : (p_dev->config_index & 0x20 ?   8 : -24));
+
+       if ((p_dev->resource[0]->start & 0xf) == 8)
+               return -ENODEV;
+
+       p_dev->resource[0]->end = 18;
+       p_dev->resource[1]->end = 8;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
+       p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->io_lines = 10;
 
+       p_dev->resource[1]->start = p_dev->resource[0]->start;
+       p_dev->resource[0]->start = tmp;
+       return pcmcia_request_io(p_dev);
 }
 
 
@@ -727,11 +694,6 @@ static int pcmcia_get_mac_ce(struct pcmcia_device *p_dev,
 };
 
 
-/****************
- * xirc2ps_config() is scheduled to run after a CARD_INSERTION event
- * is received, to configure the PCMCIA socket, and to make the
- * ethernet device available to the system.
- */
 static int
 xirc2ps_config(struct pcmcia_device * link)
 {
@@ -807,32 +769,24 @@ xirc2ps_config(struct pcmcia_device * link)
        goto failure;
     }
 
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-    link->io_lines = 10;
     if (local->modem) {
        int pass;
+       link->config_flags |= CONF_AUTO_SET_IO;
 
-       if (do_sound) {
-           link->conf.Attributes |= CONF_ENABLE_SPKR;
-           link->conf.Status |= CCSR_AUDIO_ENA;
-       }
-       link->resource[1]->end = 8;
-       link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
        if (local->dingo) {
            /* Take the Modem IO port from the CIS and scan for a free
             * Ethernet port */
-           link->resource[0]->end = 16; /* no Mako stuff anymore */
            if (!pcmcia_loop_config(link, xirc2ps_config_modem, NULL))
                    goto port_found;
        } else {
-           link->resource[0]->end = 18;
            /* We do 2 passes here: The first one uses the regular mapping and
             * the second tries again, thereby considering that the 32 ports are
             * mirrored every 32 bytes. Actually we use a mirrored port for
             * the Mako if (on the first pass) the COR bit 5 is set.
             */
            for (pass=0; pass < 2; pass++)
-                   if (!pcmcia_loop_config(link, xirc2ps_config_check, &pass))
+                   if (!pcmcia_loop_config(link, xirc2ps_config_check,
+                                                   &pass))
                            goto port_found;
            /* if special option:
             * try to configure as Ethernet only.
@@ -840,7 +794,9 @@ xirc2ps_config(struct pcmcia_device * link)
        }
        printk(KNOT_XIRC "no ports available\n");
     } else {
+       link->io_lines = 10;
        link->resource[0]->end = 16;
+       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
        for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
            link->resource[0]->start = ioaddr;
            if (!(err = pcmcia_request_io(link)))
@@ -861,16 +817,14 @@ xirc2ps_config(struct pcmcia_device * link)
     if ((err=pcmcia_request_irq(link, xirc2ps_interrupt)))
        goto config_error;
 
-    /****************
-     * This actually configures the PCMCIA socket -- setting up
-     * the I/O windows and the interrupt mapping.
-     */
-    if ((err=pcmcia_request_configuration(link, &link->conf)))
+    link->config_flags |= CONF_ENABLE_IRQ;
+    if (do_sound)
+           link->config_flags |= CONF_ENABLE_SPKR;
+
+    if ((err = pcmcia_enable_device(link)))
        goto config_error;
 
     if (local->dingo) {
-       win_req_t req;
-
        /* Reset the modem's BAR to the correct value
         * This is necessary because in the RequestConfiguration call,
         * the base address of the ethernet port (BasePort1) is written
@@ -890,14 +844,14 @@ xirc2ps_config(struct pcmcia_device * link)
         * is at 0x0800. So we allocate a window into the attribute
         * memory and write direct to the CIS registers
         */
-       req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
-       req.Base = req.Size = 0;
-       req.AccessSpeed = 0;
-       if ((err = pcmcia_request_window(link, &req, &link->win)))
+       link->resource[2]->flags = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM |
+                                       WIN_ENABLE;
+       link->resource[2]->start = link->resource[2]->end = 0;
+       if ((err = pcmcia_request_window(link, link->resource[2], 0)))
            goto config_error;
 
-       local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800;
-       if ((err = pcmcia_map_mem_page(link, link->win, 0)))
+       local->dingo_ccr = ioremap(link->resource[2]->start, 0x1000) + 0x0800;
+       if ((err = pcmcia_map_mem_page(link, link->resource[2], 0)))
            goto config_error;
 
        /* Setup the CCRs; there are no infos in the CIS about the Ethernet
@@ -978,17 +932,12 @@ xirc2ps_config(struct pcmcia_device * link)
     return -ENODEV;
 } /* xirc2ps_config */
 
-/****************
- * After a card is removed, xirc2ps_release() will unregister the net
- * device, and release the PCMCIA configuration.  If the device is
- * still open, this will be postponed until it is closed.
- */
 static void
 xirc2ps_release(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "release\n");
 
-       if (link->win) {
+       if (link->resource[2]->end) {
                struct net_device *dev = link->priv;
                local_info_t *local = netdev_priv(dev);
                if (local->dingo)
@@ -1830,9 +1779,7 @@ MODULE_DEVICE_TABLE(pcmcia, xirc2ps_ids);
 
 static struct pcmcia_driver xirc2ps_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "xirc2ps_cs",
-       },
+       .name           = "xirc2ps_cs",
        .probe          = xirc2ps_probe,
        .remove         = xirc2ps_detach,
        .id_table       = xirc2ps_ids,
index af50a530daee25bf3debf8493690861c2ea2fcc2..78d70a6481bfa7f986e165e427b8c76bd75ae835 100644 (file)
@@ -184,7 +184,7 @@ ppp_asynctty_open(struct tty_struct *tty)
        tasklet_init(&ap->tsk, ppp_async_process, (unsigned long) ap);
 
        atomic_set(&ap->refcnt, 1);
-       init_MUTEX_LOCKED(&ap->dead_sem);
+       sema_init(&ap->dead_sem, 0);
 
        ap->chan.private = ap;
        ap->chan.ops = &async_ops;
index 10cf0cbc218507111b26959f119645672fcd5666..726df611ee17da997b31a8219de2554080fdeed7 100644 (file)
@@ -72,6 +72,7 @@ static const char version[] =
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/crc32.h>
index 04c6cd4333f1ec83d69be506b040b75183cdfb81..10bafd59f9c336e36fbec4c6703530ce54a92a36 100644 (file)
@@ -575,7 +575,7 @@ static int cosa_probe(int base, int irq, int dma)
 
                /* Initialize the chardev data structures */
                mutex_init(&chan->rlock);
-               init_MUTEX(&chan->wsem);
+               sema_init(&chan->wsem, 1);
 
                /* Register the network interface */
                if (!(chan->netdev = alloc_hdlcdev(chan))) {
index 9a121a5b787cb2468005e914e81a15eee55e312f..df2484d4547489c64404c0a8ab3e8579fb7cceba 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/timer.h>
 #include <linux/netdevice.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -54,58 +53,21 @@ MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards");
 
 /*====================================================================*/
 
-/*
-   The event() function is this driver's Card Services event handler.
-   It will be called by Card Services when an appropriate card status
-   event is received.  The config() and release() entry points are
-   used to configure or release a socket, in response to card
-   insertion and ejection events.  They are invoked from the airo_cs
-   event handler.
-*/
-
 static int airo_config(struct pcmcia_device *link);
 static void airo_release(struct pcmcia_device *link);
 
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static void airo_detach(struct pcmcia_device *p_dev);
 
 typedef struct local_info_t {
        struct net_device *eth_dev;
 } local_info_t;
 
-/*======================================================================
-
-  airo_attach() creates an "instance" of the driver, allocating
-  local data structures for one device.  The device is registered
-  with Card Services.
-
-  The dev_link structure is initialized, but we don't actually
-  configure the card at this point -- we wait until we receive a
-  card insertion event.
-
-  ======================================================================*/
-
 static int airo_probe(struct pcmcia_device *p_dev)
 {
        local_info_t *local;
 
        dev_dbg(&p_dev->dev, "airo_attach()\n");
 
-       /*
-         General socket configuration defaults can go here.  In this
-         client, we assume very little, and rely on the CIS for almost
-         everything.  In most clients, many details (i.e., number, sizes,
-         and attributes of IO windows) are fixed by the nature of the
-         device, and can be hard-wired here.
-       */
-       p_dev->conf.Attributes = 0;
-       p_dev->conf.IntType = INT_MEMORY_AND_IO;
-
        /* Allocate space for private device-specific data */
        local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
        if (!local) {
@@ -117,15 +79,6 @@ static int airo_probe(struct pcmcia_device *p_dev)
        return airo_config(p_dev);
 } /* airo_attach */
 
-/*======================================================================
-
-  This deletes a driver "instance".  The device is de-registered
-  with Card Services.  If it has been released, all local data
-  structures are freed.  Otherwise, the structures will be freed
-  when the device is released.
-
-  ======================================================================*/
-
 static void airo_detach(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "airo_detach\n");
@@ -140,60 +93,12 @@ static void airo_detach(struct pcmcia_device *link)
        kfree(link->priv);
 } /* airo_detach */
 
-/*======================================================================
-
-  airo_config() is scheduled to run after a CARD_INSERTION event
-  is received, to configure the PCMCIA socket, and to make the
-  device available to the system.
-
-  ======================================================================*/
-
-static int airo_cs_config_check(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
-                               void *priv_data)
+static int airo_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (cfg->index == 0)
-               return -ENODEV;
-
-       /* Does this card need audio output? */
-       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
-               p_dev->conf.Status = CCSR_AUDIO_ENA;
-       }
-
-       /* Use power settings for Vcc and Vpp if present */
-       /*  Note that the CIS values need to be rescaled */
-       if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-       else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
-
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-       }
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       /* This reserves IO space but doesn't actually enable it */
-       if (pcmcia_request_io(p_dev) != 0)
-               return -ENODEV;
-
-       /* If we got this far, we're cool! */
-       return 0;
+       return pcmcia_request_io(p_dev);
 }
 
 
@@ -206,20 +111,9 @@ static int airo_config(struct pcmcia_device *link)
 
        dev_dbg(&link->dev, "airo_config\n");
 
-       /*
-        * In this loop, we scan the CIS for configuration table
-        * entries, each of which describes a valid card
-        * configuration, including voltage, IO window, memory window,
-        * and interrupt settings.
-        *
-        * We make no assumptions about the card to be configured: we
-        * use just the information available in the CIS.  In an ideal
-        * world, this would work for any PCMCIA card, but it requires
-        * a complete and accurate CIS.  In practice, a driver usually
-        * "knows" most of these things without consulting the CIS,
-        * and most client drivers will only use the CIS to fill in
-        * implementation-defined details.
-        */
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
+               CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
+
        ret = pcmcia_loop_config(link, airo_cs_config_check, NULL);
        if (ret)
                goto failed;
@@ -227,12 +121,7 @@ static int airo_config(struct pcmcia_device *link)
        if (!link->irq)
                goto failed;
 
-       /*
-         This actually configures the PCMCIA socket -- setting up
-         the I/O windows and the interrupt mapping, and putting the
-         card and host interface into "Memory and IO" mode.
-       */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
        ((local_info_t *)link->priv)->eth_dev =
@@ -241,17 +130,6 @@ static int airo_config(struct pcmcia_device *link)
        if (!((local_info_t *)link->priv)->eth_dev)
                goto failed;
 
-       /* Finally, report what we've done */
-       dev_info(&link->dev, "index 0x%02x: ",
-              link->conf.ConfigIndex);
-       if (link->conf.Vpp)
-               printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
-       printk(", irq %d", link->irq);
-       if (link->resource[0])
-               printk(" & %pR", link->resource[0]);
-       if (link->resource[1])
-               printk(" & %pR", link->resource[1]);
-       printk("\n");
        return 0;
 
  failed:
@@ -259,14 +137,6 @@ static int airo_config(struct pcmcia_device *link)
        return -ENODEV;
 } /* airo_config */
 
-/*======================================================================
-
-  After a card is removed, airo_release() will unregister the
-  device, and release the PCMCIA configuration.  If the device is
-  still open, this will be postponed until it is closed.
-
-  ======================================================================*/
-
 static void airo_release(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "airo_release\n");
@@ -305,9 +175,7 @@ MODULE_DEVICE_TABLE(pcmcia, airo_ids);
 
 static struct pcmcia_driver airo_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "airo_cs",
-       },
+       .name           = "airo_cs",
        .probe          = airo_probe,
        .remove         = airo_detach,
        .id_table       = airo_ids,
@@ -315,12 +183,12 @@ static struct pcmcia_driver airo_driver = {
        .resume         = airo_resume,
 };
 
-static int airo_cs_init(void)
+static int __init airo_cs_init(void)
 {
        return pcmcia_register_driver(&airo_driver);
 }
 
-static void airo_cs_cleanup(void)
+static void __exit airo_cs_cleanup(void)
 {
        pcmcia_unregister_driver(&airo_driver);
 }
index 3b632161c10696ee7ae896db24c11d4886395486..c96e19da29496407385ee8e51b19f46b21e230d4 100644 (file)
@@ -42,7 +42,6 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -64,58 +63,21 @@ MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards");
 
 /*====================================================================*/
 
-/*
-   The event() function is this driver's Card Services event handler.
-   It will be called by Card Services when an appropriate card status
-   event is received.  The config() and release() entry points are
-   used to configure or release a socket, in response to card
-   insertion and ejection events.  They are invoked from the atmel_cs
-   event handler.
-*/
-
 static int atmel_config(struct pcmcia_device *link);
 static void atmel_release(struct pcmcia_device *link);
 
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static void atmel_detach(struct pcmcia_device *p_dev);
 
 typedef struct local_info_t {
        struct net_device *eth_dev;
 } local_info_t;
 
-/*======================================================================
-
-  atmel_attach() creates an "instance" of the driver, allocating
-  local data structures for one device.  The device is registered
-  with Card Services.
-
-  The dev_link structure is initialized, but we don't actually
-  configure the card at this point -- we wait until we receive a
-  card insertion event.
-
-  ======================================================================*/
-
 static int atmel_probe(struct pcmcia_device *p_dev)
 {
        local_info_t *local;
 
        dev_dbg(&p_dev->dev, "atmel_attach()\n");
 
-       /*
-         General socket configuration defaults can go here.  In this
-         client, we assume very little, and rely on the CIS for almost
-         everything.  In most clients, many details (i.e., number, sizes,
-         and attributes of IO windows) are fixed by the nature of the
-         device, and can be hard-wired here.
-       */
-       p_dev->conf.Attributes = 0;
-       p_dev->conf.IntType = INT_MEMORY_AND_IO;
-
        /* Allocate space for private device-specific data */
        local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
        if (!local) {
@@ -127,15 +89,6 @@ static int atmel_probe(struct pcmcia_device *p_dev)
        return atmel_config(p_dev);
 } /* atmel_attach */
 
-/*======================================================================
-
-  This deletes a driver "instance".  The device is de-registered
-  with Card Services.  If it has been released, all local data
-  structures are freed.  Otherwise, the structures will be freed
-  when the device is released.
-
-  ======================================================================*/
-
 static void atmel_detach(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "atmel_detach\n");
@@ -145,14 +98,6 @@ static void atmel_detach(struct pcmcia_device *link)
        kfree(link->priv);
 }
 
-/*======================================================================
-
-  atmel_config() is scheduled to run after a CARD_INSERTION event
-  is received, to configure the PCMCIA socket, and to make the
-  device available to the system.
-
-  ======================================================================*/
-
 /* Call-back function to interrogate PCMCIA-specific information
    about the current existance of the card */
 static int card_present(void *arg)
@@ -165,47 +110,11 @@ static int card_present(void *arg)
        return 0;
 }
 
-static int atmel_config_check(struct pcmcia_device *p_dev,
-                             cistpl_cftable_entry_t *cfg,
-                             cistpl_cftable_entry_t *dflt,
-                             unsigned int vcc,
-                             void *priv_data)
+static int atmel_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (cfg->index == 0)
-               return -ENODEV;
-
-       /* Does this card need audio output? */
-       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
-               p_dev->conf.Status = CCSR_AUDIO_ENA;
-       }
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       /* Use power settings for Vcc and Vpp if present */
-       /*  Note that the CIS values need to be rescaled */
-       if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-       else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
-
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-       }
-
-       /* This reserves IO space but doesn't actually enable it */
        return pcmcia_request_io(p_dev);
 }
 
@@ -220,18 +129,9 @@ static int atmel_config(struct pcmcia_device *link)
 
        dev_dbg(&link->dev, "atmel_config\n");
 
-       /*
-         In this loop, we scan the CIS for configuration table entries,
-         each of which describes a valid card configuration, including
-         voltage, IO window, memory window, and interrupt settings.
-
-         We make no assumptions about the card to be configured: we use
-         just the information available in the CIS.  In an ideal world,
-         this would work for any PCMCIA card, but it requires a complete
-         and accurate CIS.  In practice, a driver usually "knows" most of
-         these things without consulting the CIS, and most client drivers
-         will only use the CIS to fill in implementation-defined details.
-       */
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
+               CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
+
        if (pcmcia_loop_config(link, atmel_config_check, NULL))
                goto failed;
 
@@ -240,12 +140,7 @@ static int atmel_config(struct pcmcia_device *link)
                goto failed;
        }
 
-       /*
-         This actually configures the PCMCIA socket -- setting up
-         the I/O windows and the interrupt mapping, and putting the
-         card and host interface into "Memory and IO" mode.
-       */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
@@ -267,14 +162,6 @@ static int atmel_config(struct pcmcia_device *link)
        return -ENODEV;
 }
 
-/*======================================================================
-
-  After a card is removed, atmel_release() will unregister the
-  device, and release the PCMCIA configuration.  If the device is
-  still open, this will be postponed until it is closed.
-
-  ======================================================================*/
-
 static void atmel_release(struct pcmcia_device *link)
 {
        struct net_device *dev = ((local_info_t*)link->priv)->eth_dev;
@@ -353,9 +240,7 @@ MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
 
 static struct pcmcia_driver atmel_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "atmel_cs",
-        },
+       .name           = "atmel_cs",
        .probe          = atmel_probe,
        .remove         = atmel_detach,
        .id_table       = atmel_ids,
@@ -363,12 +248,12 @@ static struct pcmcia_driver atmel_driver = {
        .resume         = atmel_resume,
 };
 
-static int atmel_cs_init(void)
+static int __init atmel_cs_init(void)
 {
         return pcmcia_register_driver(&atmel_driver);
 }
 
-static void atmel_cs_cleanup(void)
+static void __exit atmel_cs_cleanup(void)
 {
         pcmcia_unregister_driver(&atmel_driver);
 }
index dfbc41d431ffae744fca15a2a90506ee5e6abb01..7dcba5fafdc7fe04820bde7a10571f327fd6796d 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/ssb/ssb.h>
 #include <linux/slab.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -63,7 +62,6 @@ static int b43_pcmcia_resume(struct pcmcia_device *dev)
 static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
 {
        struct ssb_bus *ssb;
-       win_req_t win;
        int err = -ENOMEM;
        int res = 0;
 
@@ -73,30 +71,28 @@ static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
 
        err = -ENODEV;
 
-       dev->conf.Attributes = CONF_ENABLE_IRQ;
-       dev->conf.IntType = INT_MEMORY_AND_IO;
+       dev->config_flags |= CONF_ENABLE_IRQ;
 
-       win.Attributes =  WIN_ENABLE | WIN_DATA_WIDTH_16 |
+       dev->resource[2]->flags |=  WIN_ENABLE | WIN_DATA_WIDTH_16 |
                         WIN_USE_WAIT;
-       win.Base = 0;
-       win.Size = SSB_CORE_SIZE;
-       win.AccessSpeed = 250;
-       res = pcmcia_request_window(dev, &win, &dev->win);
+       dev->resource[2]->start = 0;
+       dev->resource[2]->end = SSB_CORE_SIZE;
+       res = pcmcia_request_window(dev, dev->resource[2], 250);
        if (res != 0)
                goto err_kfree_ssb;
 
-       res = pcmcia_map_mem_page(dev, dev->win, 0);
+       res = pcmcia_map_mem_page(dev, dev->resource[2], 0);
        if (res != 0)
                goto err_disable;
 
        if (!dev->irq)
                goto err_disable;
 
-       res = pcmcia_request_configuration(dev, &dev->conf);
+       res = pcmcia_enable_device(dev);
        if (res != 0)
                goto err_disable;
 
-       err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
+       err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start);
        if (err)
                goto err_disable;
        dev->priv = ssb;
@@ -125,9 +121,7 @@ static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev)
 
 static struct pcmcia_driver b43_pcmcia_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-                               .name = "b43-pcmcia",
-                       },
+       .name           = "b43-pcmcia",
        .id_table       = b43_pcmcia_tbl,
        .probe          = b43_pcmcia_probe,
        .remove         = __devexit_p(b43_pcmcia_remove),
index ba54d1b04d22a7e50ae244bb2b905c84d44c1986..bd8a4134edebcae378d89fa9add3c2ae7f4dea9f 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -437,7 +436,6 @@ static int hostap_cs_probe(struct pcmcia_device *p_dev)
        int ret;
 
        PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
-       p_dev->conf.IntType = INT_MEMORY_AND_IO;
 
        ret = prism2_config(p_dev);
        if (ret) {
@@ -468,74 +466,11 @@ static void prism2_detach(struct pcmcia_device *link)
 }
 
 
-/* run after a CARD_INSERTION event is received to configure the PCMCIA
- * socket and make the device available to the system */
-
-static int prism2_config_check(struct pcmcia_device *p_dev,
-                              cistpl_cftable_entry_t *cfg,
-                              cistpl_cftable_entry_t *dflt,
-                              unsigned int vcc,
-                              void *priv_data)
+static int prism2_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (cfg->index == 0)
-               return -ENODEV;
-
-       PDEBUG(DEBUG_EXTRA, "Checking CFTABLE_ENTRY 0x%02X "
-              "(default 0x%02X)\n", cfg->index, dflt->index);
-
-       /* Does this card need audio output? */
-       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
-               p_dev->conf.Status = CCSR_AUDIO_ENA;
-       }
-
-       /* Use power settings for Vcc and Vpp if present */
-       /*  Note that the CIS values need to be rescaled */
-       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] /
-                   10000 && !ignore_cis_vcc) {
-                       PDEBUG(DEBUG_EXTRA, "  Vcc mismatch - skipping"
-                              " this entry\n");
-                       return -ENODEV;
-               }
-       } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] /
-                   10000 && !ignore_cis_vcc) {
-                       PDEBUG(DEBUG_EXTRA, "  Vcc (default) mismatch "
-                              "- skipping this entry\n");
-                       return -ENODEV;
-               }
-       }
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp = dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       PDEBUG(DEBUG_EXTRA, "IO window settings: cfg->io.nwin=%d "
-              "dflt->io.nwin=%d\n",
-              cfg->io.nwin, dflt->io.nwin);
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-       }
-
-       /* This reserves IO space but doesn't actually enable it */
        return pcmcia_request_io(p_dev);
 }
 
@@ -557,6 +492,10 @@ static int prism2_config(struct pcmcia_device *link)
        }
 
        /* Look for an appropriate configuration table entry in the CIS */
+       link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO |
+               CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
+       if (ignore_cis_vcc)
+               link->config_flags &= ~CONF_AUTO_CHECK_VCC;
        ret = pcmcia_loop_config(link, prism2_config_check, NULL);
        if (ret) {
                if (!ignore_cis_vcc)
@@ -588,12 +527,7 @@ static int prism2_config(struct pcmcia_device *link)
        if (ret)
                goto failed_unlock;
 
-       /*
-        * This actually configures the PCMCIA socket -- setting up
-        * the I/O windows and the interrupt mapping, and putting the
-        * card and host interface into "Memory and IO" mode.
-        */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed_unlock;
 
@@ -602,20 +536,6 @@ static int prism2_config(struct pcmcia_device *link)
 
        spin_unlock_irqrestore(&local->irq_init_lock, flags);
 
-       /* Finally, report what we've done */
-       printk(KERN_INFO "%s: index 0x%02x: ",
-              dev_info, link->conf.ConfigIndex);
-       if (link->conf.Vpp)
-               printk(", Vpp %d.%d", link->conf.Vpp / 10,
-                      link->conf.Vpp % 10);
-       if (link->conf.Attributes & CONF_ENABLE_IRQ)
-               printk(", irq %d", link->irq);
-       if (link->resource[0])
-               printk(" & %pR", link->resource[0]);
-       if (link->resource[1])
-               printk(" & %pR", link->resource[1]);
-       printk("\n");
-
        local->shutdown = 0;
 
        sandisk_enable_wireless(dev);
@@ -627,7 +547,7 @@ static int prism2_config(struct pcmcia_device *link)
        return ret;
 
  failed_unlock:
-        spin_unlock_irqrestore(&local->irq_init_lock, flags);
+       spin_unlock_irqrestore(&local->irq_init_lock, flags);
  failed:
        kfree(hw_priv);
        prism2_release((u_long)link);
@@ -779,9 +699,7 @@ MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
 
 
 static struct pcmcia_driver hostap_driver = {
-       .drv            = {
-               .name   = "hostap_cs",
-       },
+       .name           = "hostap_cs",
        .probe          = hostap_cs_probe,
        .remove         = prism2_detach,
        .owner          = THIS_MODULE,
index 9c298396be50b7fe5d0d6f8c6b102ecef441b3f7..ff1280f413362847b364fa8a5cf4f680a21fd354 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/firmware.h>
 #include <linux/netdevice.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -761,15 +760,6 @@ static int if_cs_host_to_card(struct lbs_private *priv,
 }
 
 
-/********************************************************************/
-/* Card Services                                                    */
-/********************************************************************/
-
-/*
- * After a card is removed, if_cs_release() will unregister the
- * device, and release the PCMCIA configuration.  If the device is
- * still open, this will be postponed until it is closed.
- */
 static void if_cs_release(struct pcmcia_device *p_dev)
 {
        struct if_cs_card *card = p_dev->priv;
@@ -785,31 +775,12 @@ static void if_cs_release(struct pcmcia_device *p_dev)
 }
 
 
-/*
- * This creates an "instance" of the driver, allocating local data
- * structures for one device.  The device is registered with Card
- * Services.
- *
- * The dev_link structure is initialized, but we don't actually
- * configure the card at this point -- we wait until we receive a card
- * insertion event.
- */
-
-static int if_cs_ioprobe(struct pcmcia_device *p_dev,
-                        cistpl_cftable_entry_t *cfg,
-                        cistpl_cftable_entry_t *dflt,
-                        unsigned int vcc,
-                        void *priv_data)
+static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
 {
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
        p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-       p_dev->resource[0]->start = cfg->io.win[0].base;
-       p_dev->resource[0]->end = cfg->io.win[0].len;
-
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
 
-       /* IO window settings */
-       if (cfg->io.nwin != 1) {
+       if (p_dev->resource[1]->end) {
                lbs_pr_err("wrong CIS (check number of IO windows)\n");
                return -ENODEV;
        }
@@ -835,15 +806,13 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
        card->p_dev = p_dev;
        p_dev->priv = card;
 
-       p_dev->conf.Attributes = 0;
-       p_dev->conf.IntType = INT_MEMORY_AND_IO;
+       p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 
        if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
                lbs_pr_err("error in pcmcia_loop_config\n");
                goto out1;
        }
 
-
        /*
         * Allocate an interrupt line.  Note that this does not assign
         * a handler to the interrupt, unless the 'Handler' member of
@@ -861,14 +830,9 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
                goto out1;
        }
 
-       /*
-        * This actually configures the PCMCIA socket -- setting up
-        * the I/O windows and the interrupt mapping, and putting the
-        * card and host interface into "Memory and IO" mode.
-        */
-       ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
+       ret = pcmcia_enable_device(p_dev);
        if (ret) {
-               lbs_pr_err("error in pcmcia_request_configuration\n");
+               lbs_pr_err("error in pcmcia_enable_device\n");
                goto out2;
        }
 
@@ -962,12 +926,6 @@ out:
 }
 
 
-/*
- * This deletes a driver "instance".  The device is de-registered with
- * Card Services.  If it has been released, all local data structures
- * are freed.  Otherwise, the structures will be freed when the device
- * is released.
- */
 static void if_cs_detach(struct pcmcia_device *p_dev)
 {
        struct if_cs_card *card = p_dev->priv;
@@ -1000,9 +958,7 @@ MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
 
 static struct pcmcia_driver lbs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = DRV_NAME,
-       },
+       .name           = DRV_NAME,
        .probe          = if_cs_probe,
        .remove         = if_cs_detach,
        .id_table       = if_cs_ids,
index ef46a2d885392f49f1803fbb47bb2f6a6b2f7fdc..71b3d68b9403a8c4c142b776179c1edef9328ebd 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -93,14 +92,6 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
 /* PCMCIA stuff                                                    */
 /********************************************************************/
 
-/*
- * This creates an "instance" of the driver, allocating local data
- * structures for one device.  The device is registered with Card
- * Services.
- *
- * The dev_link structure is initialized, but we don't actually
- * configure the card at this point -- we wait until we receive a card
- * insertion event.  */
 static int
 orinoco_cs_probe(struct pcmcia_device *link)
 {
@@ -117,23 +108,9 @@ orinoco_cs_probe(struct pcmcia_device *link)
        card->p_dev = link;
        link->priv = priv;
 
-       /* General socket configuration defaults can go here.  In this
-        * client, we assume very little, and rely on the CIS for
-        * almost everything.  In most clients, many details (i.e.,
-        * number, sizes, and attributes of IO windows) are fixed by
-        * the nature of the device, and can be hard-wired here. */
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        return orinoco_cs_config(link);
 }                              /* orinoco_cs_attach */
 
-/*
- * This deletes a driver "instance".  The device is de-registered with
- * Card Services.  If it has been released, all local data structures
- * are freed.  Otherwise, the structures will be freed when the device
- * is released.
- */
 static void orinoco_cs_detach(struct pcmcia_device *link)
 {
        struct orinoco_private *priv = link->priv;
@@ -145,76 +122,12 @@ static void orinoco_cs_detach(struct pcmcia_device *link)
        free_orinocodev(priv);
 }                              /* orinoco_cs_detach */
 
-/*
- * orinoco_cs_config() is scheduled to run after a CARD_INSERTION
- * event is received, to configure the PCMCIA socket, and to make the
- * device available to the system.
- */
-
-static int orinoco_cs_config_check(struct pcmcia_device *p_dev,
-                                  cistpl_cftable_entry_t *cfg,
-                                  cistpl_cftable_entry_t *dflt,
-                                  unsigned int vcc,
-                                  void *priv_data)
+static int orinoco_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (cfg->index == 0)
-               goto next_entry;
-
-       /* Use power settings for Vcc and Vpp if present */
-       /* Note that the CIS values need to be rescaled */
-       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                       DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
-                             __func__, vcc,
-                             cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
-                       if (!ignore_cis_vcc)
-                               goto next_entry;
-               }
-       } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                       DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
-                             __func__, vcc,
-                             dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
-                       if (!ignore_cis_vcc)
-                               goto next_entry;
-               }
-       }
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-
-               /* This reserves IO space but doesn't actually enable it */
-               if (pcmcia_request_io(p_dev) != 0)
-                       goto next_entry;
-       }
-       return 0;
-
-next_entry:
-       pcmcia_disable_device(p_dev);
-       return -ENODEV;
+       return pcmcia_request_io(p_dev);
 };
 
 static int
@@ -225,20 +138,10 @@ orinoco_cs_config(struct pcmcia_device *link)
        int ret;
        void __iomem *mem;
 
-       /*
-        * In this loop, we scan the CIS for configuration table
-        * entries, each of which describes a valid card
-        * configuration, including voltage, IO window, memory window,
-        * and interrupt settings.
-        *
-        * We make no assumptions about the card to be configured: we
-        * use just the information available in the CIS.  In an ideal
-        * world, this would work for any PCMCIA card, but it requires
-        * a complete and accurate CIS.  In practice, a driver usually
-        * "knows" most of these things without consulting the CIS,
-        * and most client drivers will only use the CIS to fill in
-        * implementation-defined details.
-        */
+       link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC |
+               CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
+       if (ignore_cis_vcc)
+               link->config_flags &= ~CONF_AUTO_CHECK_VCC;
        ret = pcmcia_loop_config(link, orinoco_cs_config_check, NULL);
        if (ret) {
                if (!ignore_cis_vcc)
@@ -262,12 +165,7 @@ orinoco_cs_config(struct pcmcia_device *link)
 
        hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
 
-       /*
-        * This actually configures the PCMCIA socket -- setting up
-        * the I/O windows and the interrupt mapping, and putting the
-        * card and host interface into "Memory and IO" mode.
-        */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
@@ -291,11 +189,6 @@ orinoco_cs_config(struct pcmcia_device *link)
        return -ENODEV;
 }                              /* orinoco_cs_config */
 
-/*
- * After a card is removed, orinoco_cs_release() will unregister the
- * device, and release the PCMCIA configuration.  If the device is
- * still open, this will be postponed until it is closed.
- */
 static void
 orinoco_cs_release(struct pcmcia_device *link)
 {
@@ -344,12 +237,6 @@ static int orinoco_cs_resume(struct pcmcia_device *link)
 /* Module initialization                                           */
 /********************************************************************/
 
-/* Can't be declared "const" or the whole __initdata section will
- * become const */
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-       " (David Gibson <hermes@gibson.dropbear.id.au>, "
-       "Pavel Roskin <proski@gnu.org>, et al)";
-
 static struct pcmcia_device_id orinoco_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
        PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */
@@ -441,9 +328,7 @@ MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
 
 static struct pcmcia_driver orinoco_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = DRIVER_NAME,
-       },
+       .name           = DRIVER_NAME,
        .probe          = orinoco_cs_probe,
        .remove         = orinoco_cs_detach,
        .id_table       = orinoco_cs_ids,
@@ -454,8 +339,6 @@ static struct pcmcia_driver orinoco_driver = {
 static int __init
 init_orinoco_cs(void)
 {
-       printk(KERN_DEBUG "%s\n", version);
-
        return pcmcia_register_driver(&orinoco_driver);
 }
 
index 873877e17e1bf6bce4debd49b75f359a8d39b1ec..fb859a5ad2eb8a5c2e02f349cf4002caac32fc49 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -154,14 +153,6 @@ spectrum_cs_stop_firmware(struct orinoco_private *priv, int idle)
 /* PCMCIA stuff                                                    */
 /********************************************************************/
 
-/*
- * This creates an "instance" of the driver, allocating local data
- * structures for one device.  The device is registered with Card
- * Services.
- *
- * The dev_link structure is initialized, but we don't actually
- * configure the card at this point -- we wait until we receive a card
- * insertion event.  */
 static int
 spectrum_cs_probe(struct pcmcia_device *link)
 {
@@ -179,23 +170,9 @@ spectrum_cs_probe(struct pcmcia_device *link)
        card->p_dev = link;
        link->priv = priv;
 
-       /* General socket configuration defaults can go here.  In this
-        * client, we assume very little, and rely on the CIS for
-        * almost everything.  In most clients, many details (i.e.,
-        * number, sizes, and attributes of IO windows) are fixed by
-        * the nature of the device, and can be hard-wired here. */
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        return spectrum_cs_config(link);
 }                              /* spectrum_cs_attach */
 
-/*
- * This deletes a driver "instance".  The device is de-registered with
- * Card Services.  If it has been released, all local data structures
- * are freed.  Otherwise, the structures will be freed when the device
- * is released.
- */
 static void spectrum_cs_detach(struct pcmcia_device *link)
 {
        struct orinoco_private *priv = link->priv;
@@ -207,76 +184,13 @@ static void spectrum_cs_detach(struct pcmcia_device *link)
        free_orinocodev(priv);
 }                              /* spectrum_cs_detach */
 
-/*
- * spectrum_cs_config() is scheduled to run after a CARD_INSERTION
- * event is received, to configure the PCMCIA socket, and to make the
- * device available to the system.
- */
-
 static int spectrum_cs_config_check(struct pcmcia_device *p_dev,
-                                   cistpl_cftable_entry_t *cfg,
-                                   cistpl_cftable_entry_t *dflt,
-                                   unsigned int vcc,
                                    void *priv_data)
 {
-       if (cfg->index == 0)
-               goto next_entry;
-
-       /* Use power settings for Vcc and Vpp if present */
-       /* Note that the CIS values need to be rescaled */
-       if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                       DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
-                             __func__, vcc,
-                             cfg->vcc.param[CISTPL_POWER_VNOM] / 10000);
-                       if (!ignore_cis_vcc)
-                               goto next_entry;
-               }
-       } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
-               if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) {
-                       DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n",
-                             __func__, vcc,
-                             dflt->vcc.param[CISTPL_POWER_VNOM] / 10000);
-                       if (!ignore_cis_vcc)
-                               goto next_entry;
-               }
-       }
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-       else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-
-               /* This reserves IO space but doesn't actually enable it */
-               if (pcmcia_request_io(p_dev) != 0)
-                       goto next_entry;
-       }
-       return 0;
-
-next_entry:
-       pcmcia_disable_device(p_dev);
-       return -ENODEV;
+       return pcmcia_request_io(p_dev);
 };
 
 static int
@@ -287,20 +201,10 @@ spectrum_cs_config(struct pcmcia_device *link)
        int ret;
        void __iomem *mem;
 
-       /*
-        * In this loop, we scan the CIS for configuration table
-        * entries, each of which describes a valid card
-        * configuration, including voltage, IO window, memory window,
-        * and interrupt settings.
-        *
-        * We make no assumptions about the card to be configured: we
-        * use just the information available in the CIS.  In an ideal
-        * world, this would work for any PCMCIA card, but it requires
-        * a complete and accurate CIS.  In practice, a driver usually
-        * "knows" most of these things without consulting the CIS,
-        * and most client drivers will only use the CIS to fill in
-        * implementation-defined details.
-        */
+       link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_CHECK_VCC |
+               CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
+       if (ignore_cis_vcc)
+               link->config_flags &= ~CONF_AUTO_CHECK_VCC;
        ret = pcmcia_loop_config(link, spectrum_cs_config_check, NULL);
        if (ret) {
                if (!ignore_cis_vcc)
@@ -325,12 +229,7 @@ spectrum_cs_config(struct pcmcia_device *link)
        hermes_struct_init(hw, mem, HERMES_16BIT_REGSPACING);
        hw->eeprom_pda = true;
 
-       /*
-        * This actually configures the PCMCIA socket -- setting up
-        * the I/O windows and the interrupt mapping, and putting the
-        * card and host interface into "Memory and IO" mode.
-        */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
@@ -358,11 +257,6 @@ spectrum_cs_config(struct pcmcia_device *link)
        return -ENODEV;
 }                              /* spectrum_cs_config */
 
-/*
- * After a card is removed, spectrum_cs_release() will unregister the
- * device, and release the PCMCIA configuration.  If the device is
- * still open, this will be postponed until it is closed.
- */
 static void
 spectrum_cs_release(struct pcmcia_device *link)
 {
@@ -407,12 +301,6 @@ spectrum_cs_resume(struct pcmcia_device *link)
 /* Module initialization                                           */
 /********************************************************************/
 
-/* Can't be declared "const" or the whole __initdata section will
- * become const */
-static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
-       " (Pavel Roskin <proski@gnu.org>,"
-       " David Gibson <hermes@gibson.dropbear.id.au>, et al)";
-
 static struct pcmcia_device_id spectrum_cs_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
        PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
@@ -423,9 +311,7 @@ MODULE_DEVICE_TABLE(pcmcia, spectrum_cs_ids);
 
 static struct pcmcia_driver orinoco_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = DRIVER_NAME,
-       },
+       .name           = DRIVER_NAME,
        .probe          = spectrum_cs_probe,
        .remove         = spectrum_cs_detach,
        .suspend        = spectrum_cs_suspend,
@@ -436,8 +322,6 @@ static struct pcmcia_driver orinoco_driver = {
 static int __init
 init_spectrum_cs(void)
 {
-       printk(KERN_DEBUG "%s\n", version);
-
        return pcmcia_register_driver(&orinoco_driver);
 }
 
index 88560d0ae50a2457d1373103db85b98ebb61211e..af5b17ce5a15132385de6bf472bc4a36002bfb8b 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/ethtool.h>
 #include <linux/ieee80211.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -169,13 +168,6 @@ static int bc;
  */
 static char *phy_addr = NULL;
 
-
-/* A struct pcmcia_device structure has fields for most things that are needed
-   to keep track of a socket, but there will usually be some device
-   specific information that also needs to be kept track of.  The
-   'priv' pointer in a struct pcmcia_device structure can be used to point to
-   a device-specific private data structure, like this.
-*/
 static unsigned int ray_mem_speed = 500;
 
 /* WARNING: THIS DRIVER IS NOT CAPABLE OF HANDLING MULTIPLE DEVICES! */
@@ -290,14 +282,6 @@ static const struct net_device_ops ray_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-/*=============================================================================
-    ray_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-=============================================================================*/
 static int ray_probe(struct pcmcia_device *p_dev)
 {
        ray_dev_t *local;
@@ -318,9 +302,8 @@ static int ray_probe(struct pcmcia_device *p_dev)
        p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
 
        /* General socket configuration */
-       p_dev->conf.Attributes = CONF_ENABLE_IRQ;
-       p_dev->conf.IntType = INT_MEMORY_AND_IO;
-       p_dev->conf.ConfigIndex = 1;
+       p_dev->config_flags |= CONF_ENABLE_IRQ;
+       p_dev->config_index = 1;
 
        p_dev->priv = dev;
 
@@ -353,12 +336,6 @@ fail_alloc_dev:
        return -ENOMEM;
 } /* ray_attach */
 
-/*=============================================================================
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-=============================================================================*/
 static void ray_detach(struct pcmcia_device *link)
 {
        struct net_device *dev;
@@ -381,17 +358,11 @@ static void ray_detach(struct pcmcia_device *link)
        dev_dbg(&link->dev, "ray_cs ray_detach ending\n");
 } /* ray_detach */
 
-/*=============================================================================
-    ray_config() is run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ethernet device available to the system.
-=============================================================================*/
 #define MAX_TUPLE_SIZE 128
 static int ray_config(struct pcmcia_device *link)
 {
        int ret = 0;
        int i;
-       win_req_t req;
        struct net_device *dev = (struct net_device *)link->priv;
        ray_dev_t *local = netdev_priv(dev);
 
@@ -412,54 +383,50 @@ static int ray_config(struct pcmcia_device *link)
                goto failed;
        dev->irq = link->irq;
 
-       /* This actually configures the PCMCIA socket -- setting up
-          the I/O windows and the interrupt mapping.
-        */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
 /*** Set up 32k window for shared memory (transmit and control) ************/
-       req.Attributes =
-           WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
-       req.Base = 0;
-       req.Size = 0x8000;
-       req.AccessSpeed = ray_mem_speed;
-       ret = pcmcia_request_window(link, &req, &link->win);
+       link->resource[2]->flags |= WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+       link->resource[2]->start = 0;
+       link->resource[2]->end = 0x8000;
+       ret = pcmcia_request_window(link, link->resource[2], ray_mem_speed);
        if (ret)
                goto failed;
-       ret = pcmcia_map_mem_page(link, link->win, 0);
+       ret = pcmcia_map_mem_page(link, link->resource[2], 0);
        if (ret)
                goto failed;
-       local->sram = ioremap(req.Base, req.Size);
+       local->sram = ioremap(link->resource[2]->start,
+                       resource_size(link->resource[2]));
 
 /*** Set up 16k window for shared memory (receive buffer) ***************/
-       req.Attributes =
+       link->resource[3]->flags |=
            WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
-       req.Base = 0;
-       req.Size = 0x4000;
-       req.AccessSpeed = ray_mem_speed;
-       ret = pcmcia_request_window(link, &req, &local->rmem_handle);
+       link->resource[3]->start = 0;
+       link->resource[3]->end = 0x4000;
+       ret = pcmcia_request_window(link, link->resource[3], ray_mem_speed);
        if (ret)
                goto failed;
-       ret = pcmcia_map_mem_page(link, local->rmem_handle, 0x8000);
+       ret = pcmcia_map_mem_page(link, link->resource[3], 0x8000);
        if (ret)
                goto failed;
-       local->rmem = ioremap(req.Base, req.Size);
+       local->rmem = ioremap(link->resource[3]->start,
+                       resource_size(link->resource[3]));
 
 /*** Set up window for attribute memory ***********************************/
-       req.Attributes =
+       link->resource[4]->flags |=
            WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT;
-       req.Base = 0;
-       req.Size = 0x1000;
-       req.AccessSpeed = ray_mem_speed;
-       ret = pcmcia_request_window(link, &req, &local->amem_handle);
+       link->resource[4]->start = 0;
+       link->resource[4]->end = 0x1000;
+       ret = pcmcia_request_window(link, link->resource[4], ray_mem_speed);
        if (ret)
                goto failed;
-       ret = pcmcia_map_mem_page(link, local->amem_handle, 0);
+       ret = pcmcia_map_mem_page(link, link->resource[4], 0);
        if (ret)
                goto failed;
-       local->amem = ioremap(req.Base, req.Size);
+       local->amem = ioremap(link->resource[4]->start,
+                       resource_size(link->resource[4]));
 
        dev_dbg(&link->dev, "ray_config sram=%p\n", local->sram);
        dev_dbg(&link->dev, "ray_config rmem=%p\n", local->rmem);
@@ -775,11 +742,7 @@ static void join_net(u_long data)
        local->card_status = CARD_DOING_ACQ;
 }
 
-/*============================================================================
-    After a card is removed, ray_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-=============================================================================*/
+
 static void ray_release(struct pcmcia_device *link)
 {
        struct net_device *dev = link->priv;
@@ -2847,9 +2810,7 @@ MODULE_DEVICE_TABLE(pcmcia, ray_ids);
 
 static struct pcmcia_driver ray_driver = {
        .owner = THIS_MODULE,
-       .drv = {
-               .name = "ray_cs",
-               },
+       .name = "ray_cs",
        .probe = ray_probe,
        .remove = ray_detach,
        .id_table = ray_ids,
index 9f01ddb197485b801e183743999ca822b7a53c7b..e79848fbcca1e1e5397410745589703e3cad903a 100644 (file)
@@ -25,8 +25,6 @@ struct beacon_rx {
 typedef struct ray_dev_t {
     int card_status;
     int authentication_state;
-    window_handle_t amem_handle;   /* handle to window for attribute memory  */
-    window_handle_t rmem_handle;   /* handle to window for rx buffer on card */
     void __iomem *sram;            /* pointer to beginning of shared RAM     */
     void __iomem *amem;            /* pointer to attribute mem window        */
     void __iomem *rmem;            /* pointer to receive buffer window       */
index a1cc2d498a1c01bd19b0174d1497d8bd0c0c8a8b..ca3f8961fa27fd07a6d31f44740b77467fe5df93 100644 (file)
@@ -48,7 +48,6 @@
 
 #include <net/iw_handler.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
 #define WL3501_RESUME  0
 #define WL3501_SUSPEND 1
 
-/*
- * The event() function is this driver's Card Services event handler.  It will
- * be called by Card Services when an appropriate card status event is
- * received. The config() and release() entry points are used to configure or
- * release a socket, in response to card insertion and ejection events.  They
- * are invoked from the wl24 event handler.
- */
 static int wl3501_config(struct pcmcia_device *link);
 static void wl3501_release(struct pcmcia_device *link);
 
@@ -1869,15 +1861,6 @@ static const struct net_device_ops wl3501_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-/**
- * wl3501_attach - creates an "instance" of the driver
- *
- * Creates an "instance" of the driver, allocating local data structures for
- * one device.  The device is registered with Card Services.
- *
- * The dev_link structure is initialized, but we don't actually configure the
- * card at this point -- we wait until we receive a card insertion event.
- */
 static int wl3501_probe(struct pcmcia_device *p_dev)
 {
        struct net_device *dev;
@@ -1888,9 +1871,8 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
        p_dev->resource[0]->flags       = IO_DATA_PATH_WIDTH_8;
 
        /* General socket configuration */
-       p_dev->conf.Attributes  = CONF_ENABLE_IRQ;
-       p_dev->conf.IntType     = INT_MEMORY_AND_IO;
-       p_dev->conf.ConfigIndex = 1;
+       p_dev->config_flags     = CONF_ENABLE_IRQ;
+       p_dev->config_index     = 1;
 
        dev = alloc_etherdev(sizeof(struct wl3501_card));
        if (!dev)
@@ -1914,14 +1896,6 @@ out_link:
        return -ENOMEM;
 }
 
-/**
- * wl3501_config - configure the PCMCIA socket and make eth device available
- * @link - FILL_IN
- *
- * wl3501_config() is scheduled to run after a CARD_INSERTION event is
- * received, to configure the PCMCIA socket, and to make the ethernet device
- * available to the system.
- */
 static int wl3501_config(struct pcmcia_device *link)
 {
        struct net_device *dev = link->priv;
@@ -1952,10 +1926,7 @@ static int wl3501_config(struct pcmcia_device *link)
        if (ret)
                goto failed;
 
-       /* This actually configures the PCMCIA socket -- setting up the I/O
-        * windows and the interrupt mapping.  */
-
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
@@ -2010,14 +1981,6 @@ failed:
        return -ENODEV;
 }
 
-/**
- * wl3501_release - unregister the net, release PCMCIA configuration
- * @arg - link
- *
- * After a card is removed, wl3501_release() will unregister the net device,
- * and release the PCMCIA configuration.  If the device is still open, this
- * will be postponed until it is closed.
- */
 static void wl3501_release(struct pcmcia_device *link)
 {
        pcmcia_disable_device(link);
@@ -2056,9 +2019,7 @@ MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);
 
 static struct pcmcia_driver wl3501_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "wl3501_cs",
-       },
+       .name           = "wl3501_cs",
        .probe          = wl3501_probe,
        .remove         = wl3501_detach,
        .id_table       = wl3501_ids,
index b336cd9ee7a114c54d6b7b85d48cacc6f3ed1a6d..f9bda64fcd1b62771880d5d823b53f797cb9c7f0 100644 (file)
@@ -225,26 +225,17 @@ post_sync:
        mutex_unlock(&start_mutex);
 }
 
-int oprofile_set_backtrace(unsigned long val)
+int oprofile_set_ulong(unsigned long *addr, unsigned long val)
 {
-       int err = 0;
+       int err = -EBUSY;
 
        mutex_lock(&start_mutex);
-
-       if (oprofile_started) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       if (!oprofile_ops.backtrace) {
-               err = -EINVAL;
-               goto out;
+       if (!oprofile_started) {
+               *addr = val;
+               err = 0;
        }
-
-       oprofile_backtrace_depth = val;
-
-out:
        mutex_unlock(&start_mutex);
+
        return err;
 }
 
@@ -257,16 +248,9 @@ static int __init oprofile_init(void)
                printk(KERN_INFO "oprofile: using timer interrupt.\n");
                err = oprofile_timer_init(&oprofile_ops);
                if (err)
-                       goto out_arch;
+                       return err;
        }
-       err = oprofilefs_register();
-       if (err)
-               goto out_arch;
-       return 0;
-
-out_arch:
-       oprofile_arch_exit();
-       return err;
+       return oprofilefs_register();
 }
 
 
index 47e12cb4ee8ba7464e4b0c7ef955be71b1caa201..177b73de5e5f158cbb31fe27f8e31b9363c3a255 100644 (file)
@@ -37,7 +37,7 @@ void oprofile_create_files(struct super_block *sb, struct dentry *root);
 int oprofile_timer_init(struct oprofile_operations *ops);
 void oprofile_timer_exit(void);
 
-int oprofile_set_backtrace(unsigned long depth);
+int oprofile_set_ulong(unsigned long *addr, unsigned long val);
 int oprofile_set_timeout(unsigned long time);
 
 #endif /* OPROF_H */
index bbd7516e0869461c141659004580d509ec5e97a5..ccf099e684a46e90e53bcb17ad72536cdc42a4de 100644 (file)
@@ -79,14 +79,17 @@ static ssize_t depth_write(struct file *file, char const __user *buf, size_t cou
        if (*offset)
                return -EINVAL;
 
+       if (!oprofile_ops.backtrace)
+               return -EINVAL;
+
        retval = oprofilefs_ulong_from_user(&val, buf, count);
        if (retval)
                return retval;
 
-       retval = oprofile_set_backtrace(val);
-
+       retval = oprofile_set_ulong(&oprofile_backtrace_depth, val);
        if (retval)
                return retval;
+
        return count;
 }
 
diff --git a/drivers/oprofile/oprofile_perf.c b/drivers/oprofile/oprofile_perf.c
new file mode 100644 (file)
index 0000000..9046f7b
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2010 ARM Ltd.
+ *
+ * Perf-events backend for OProfile.
+ */
+#include <linux/perf_event.h>
+#include <linux/platform_device.h>
+#include <linux/oprofile.h>
+#include <linux/slab.h>
+
+/*
+ * Per performance monitor configuration as set via oprofilefs.
+ */
+struct op_counter_config {
+       unsigned long count;
+       unsigned long enabled;
+       unsigned long event;
+       unsigned long unit_mask;
+       unsigned long kernel;
+       unsigned long user;
+       struct perf_event_attr attr;
+};
+
+static int oprofile_perf_enabled;
+static DEFINE_MUTEX(oprofile_perf_mutex);
+
+static struct op_counter_config *counter_config;
+static struct perf_event **perf_events[nr_cpumask_bits];
+static int num_counters;
+
+/*
+ * Overflow callback for oprofile.
+ */
+static void op_overflow_handler(struct perf_event *event, int unused,
+                       struct perf_sample_data *data, struct pt_regs *regs)
+{
+       int id;
+       u32 cpu = smp_processor_id();
+
+       for (id = 0; id < num_counters; ++id)
+               if (perf_events[cpu][id] == event)
+                       break;
+
+       if (id != num_counters)
+               oprofile_add_sample(regs, id);
+       else
+               pr_warning("oprofile: ignoring spurious overflow "
+                               "on cpu %u\n", cpu);
+}
+
+/*
+ * Called by oprofile_perf_setup to create perf attributes to mirror the oprofile
+ * settings in counter_config. Attributes are created as `pinned' events and
+ * so are permanently scheduled on the PMU.
+ */
+static void op_perf_setup(void)
+{
+       int i;
+       u32 size = sizeof(struct perf_event_attr);
+       struct perf_event_attr *attr;
+
+       for (i = 0; i < num_counters; ++i) {
+               attr = &counter_config[i].attr;
+               memset(attr, 0, size);
+               attr->type              = PERF_TYPE_RAW;
+               attr->size              = size;
+               attr->config            = counter_config[i].event;
+               attr->sample_period     = counter_config[i].count;
+               attr->pinned            = 1;
+       }
+}
+
+static int op_create_counter(int cpu, int event)
+{
+       struct perf_event *pevent;
+
+       if (!counter_config[event].enabled || perf_events[cpu][event])
+               return 0;
+
+       pevent = perf_event_create_kernel_counter(&counter_config[event].attr,
+                                                 cpu, NULL,
+                                                 op_overflow_handler);
+
+       if (IS_ERR(pevent))
+               return PTR_ERR(pevent);
+
+       if (pevent->state != PERF_EVENT_STATE_ACTIVE) {
+               perf_event_release_kernel(pevent);
+               pr_warning("oprofile: failed to enable event %d "
+                               "on CPU %d\n", event, cpu);
+               return -EBUSY;
+       }
+
+       perf_events[cpu][event] = pevent;
+
+       return 0;
+}
+
+static void op_destroy_counter(int cpu, int event)
+{
+       struct perf_event *pevent = perf_events[cpu][event];
+
+       if (pevent) {
+               perf_event_release_kernel(pevent);
+               perf_events[cpu][event] = NULL;
+       }
+}
+
+/*
+ * Called by oprofile_perf_start to create active perf events based on the
+ * perviously configured attributes.
+ */
+static int op_perf_start(void)
+{
+       int cpu, event, ret = 0;
+
+       for_each_online_cpu(cpu) {
+               for (event = 0; event < num_counters; ++event) {
+                       ret = op_create_counter(cpu, event);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return ret;
+}
+
+/*
+ * Called by oprofile_perf_stop at the end of a profiling run.
+ */
+static void op_perf_stop(void)
+{
+       int cpu, event;
+
+       for_each_online_cpu(cpu)
+               for (event = 0; event < num_counters; ++event)
+                       op_destroy_counter(cpu, event);
+}
+
+static int oprofile_perf_create_files(struct super_block *sb, struct dentry *root)
+{
+       unsigned int i;
+
+       for (i = 0; i < num_counters; i++) {
+               struct dentry *dir;
+               char buf[4];
+
+               snprintf(buf, sizeof buf, "%d", i);
+               dir = oprofilefs_mkdir(sb, root, buf);
+               oprofilefs_create_ulong(sb, dir, "enabled", &counter_config[i].enabled);
+               oprofilefs_create_ulong(sb, dir, "event", &counter_config[i].event);
+               oprofilefs_create_ulong(sb, dir, "count", &counter_config[i].count);
+               oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask);
+               oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel);
+               oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user);
+       }
+
+       return 0;
+}
+
+static int oprofile_perf_setup(void)
+{
+       spin_lock(&oprofilefs_lock);
+       op_perf_setup();
+       spin_unlock(&oprofilefs_lock);
+       return 0;
+}
+
+static int oprofile_perf_start(void)
+{
+       int ret = -EBUSY;
+
+       mutex_lock(&oprofile_perf_mutex);
+       if (!oprofile_perf_enabled) {
+               ret = 0;
+               op_perf_start();
+               oprofile_perf_enabled = 1;
+       }
+       mutex_unlock(&oprofile_perf_mutex);
+       return ret;
+}
+
+static void oprofile_perf_stop(void)
+{
+       mutex_lock(&oprofile_perf_mutex);
+       if (oprofile_perf_enabled)
+               op_perf_stop();
+       oprofile_perf_enabled = 0;
+       mutex_unlock(&oprofile_perf_mutex);
+}
+
+#ifdef CONFIG_PM
+
+static int oprofile_perf_suspend(struct platform_device *dev, pm_message_t state)
+{
+       mutex_lock(&oprofile_perf_mutex);
+       if (oprofile_perf_enabled)
+               op_perf_stop();
+       mutex_unlock(&oprofile_perf_mutex);
+       return 0;
+}
+
+static int oprofile_perf_resume(struct platform_device *dev)
+{
+       mutex_lock(&oprofile_perf_mutex);
+       if (oprofile_perf_enabled && op_perf_start())
+               oprofile_perf_enabled = 0;
+       mutex_unlock(&oprofile_perf_mutex);
+       return 0;
+}
+
+static struct platform_driver oprofile_driver = {
+       .driver         = {
+               .name           = "oprofile-perf",
+       },
+       .resume         = oprofile_perf_resume,
+       .suspend        = oprofile_perf_suspend,
+};
+
+static struct platform_device *oprofile_pdev;
+
+static int __init init_driverfs(void)
+{
+       int ret;
+
+       ret = platform_driver_register(&oprofile_driver);
+       if (ret)
+               return ret;
+
+       oprofile_pdev = platform_device_register_simple(
+                               oprofile_driver.driver.name, 0, NULL, 0);
+       if (IS_ERR(oprofile_pdev)) {
+               ret = PTR_ERR(oprofile_pdev);
+               platform_driver_unregister(&oprofile_driver);
+       }
+
+       return ret;
+}
+
+static void exit_driverfs(void)
+{
+       platform_device_unregister(oprofile_pdev);
+       platform_driver_unregister(&oprofile_driver);
+}
+
+#else
+
+static inline int  init_driverfs(void) { return 0; }
+static inline void exit_driverfs(void) { }
+
+#endif /* CONFIG_PM */
+
+void oprofile_perf_exit(void)
+{
+       int cpu, id;
+       struct perf_event *event;
+
+       for_each_possible_cpu(cpu) {
+               for (id = 0; id < num_counters; ++id) {
+                       event = perf_events[cpu][id];
+                       if (event)
+                               perf_event_release_kernel(event);
+               }
+
+               kfree(perf_events[cpu]);
+       }
+
+       kfree(counter_config);
+       exit_driverfs();
+}
+
+int __init oprofile_perf_init(struct oprofile_operations *ops)
+{
+       int cpu, ret = 0;
+
+       ret = init_driverfs();
+       if (ret)
+               return ret;
+
+       memset(&perf_events, 0, sizeof(perf_events));
+
+       num_counters = perf_num_counters();
+       if (num_counters <= 0) {
+               pr_info("oprofile: no performance counters\n");
+               ret = -ENODEV;
+               goto out;
+       }
+
+       counter_config = kcalloc(num_counters,
+                       sizeof(struct op_counter_config), GFP_KERNEL);
+
+       if (!counter_config) {
+               pr_info("oprofile: failed to allocate %d "
+                               "counters\n", num_counters);
+               ret = -ENOMEM;
+               num_counters = 0;
+               goto out;
+       }
+
+       for_each_possible_cpu(cpu) {
+               perf_events[cpu] = kcalloc(num_counters,
+                               sizeof(struct perf_event *), GFP_KERNEL);
+               if (!perf_events[cpu]) {
+                       pr_info("oprofile: failed to allocate %d perf events "
+                                       "for cpu %d\n", num_counters, cpu);
+                       ret = -ENOMEM;
+                       goto out;
+               }
+       }
+
+       ops->create_files       = oprofile_perf_create_files;
+       ops->setup              = oprofile_perf_setup;
+       ops->start              = oprofile_perf_start;
+       ops->stop               = oprofile_perf_stop;
+       ops->shutdown           = oprofile_perf_stop;
+       ops->cpu_type           = op_name_from_perf_id();
+
+       if (!ops->cpu_type)
+               ret = -ENODEV;
+       else
+               pr_info("oprofile: using %s\n", ops->cpu_type);
+
+out:
+       if (ret)
+               oprofile_perf_exit();
+
+       return ret;
+}
index 2766a6d3c2e9c8fe2f7ab2a2d1f3457275693f80..1944621930d96fc51a8f0497037b4dac74e0329b 100644 (file)
@@ -91,16 +91,20 @@ static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count
 
 static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
 {
-       unsigned long *value = file->private_data;
+       unsigned long value;
        int retval;
 
        if (*offset)
                return -EINVAL;
 
-       retval = oprofilefs_ulong_from_user(value, buf, count);
+       retval = oprofilefs_ulong_from_user(&value, buf, count);
+       if (retval)
+               return retval;
 
+       retval = oprofile_set_ulong(file->private_data, value);
        if (retval)
                return retval;
+
        return count;
 }
 
@@ -126,50 +130,41 @@ static const struct file_operations ulong_ro_fops = {
 };
 
 
-static struct dentry *__oprofilefs_create_file(struct super_block *sb,
+static int __oprofilefs_create_file(struct super_block *sb,
        struct dentry *root, char const *name, const struct file_operations *fops,
-       int perm)
+       int perm, void *priv)
 {
        struct dentry *dentry;
        struct inode *inode;
 
        dentry = d_alloc_name(root, name);
        if (!dentry)
-               return NULL;
+               return -ENOMEM;
        inode = oprofilefs_get_inode(sb, S_IFREG | perm);
        if (!inode) {
                dput(dentry);
-               return NULL;
+               return -ENOMEM;
        }
        inode->i_fop = fops;
        d_add(dentry, inode);
-       return dentry;
+       dentry->d_inode->i_private = priv;
+       return 0;
 }
 
 
 int oprofilefs_create_ulong(struct super_block *sb, struct dentry *root,
        char const *name, unsigned long *val)
 {
-       struct dentry *d = __oprofilefs_create_file(sb, root, name,
-                                                    &ulong_fops, 0644);
-       if (!d)
-               return -EFAULT;
-
-       d->d_inode->i_private = val;
-       return 0;
+       return __oprofilefs_create_file(sb, root, name,
+                                       &ulong_fops, 0644, val);
 }
 
 
 int oprofilefs_create_ro_ulong(struct super_block *sb, struct dentry *root,
        char const *name, unsigned long *val)
 {
-       struct dentry *d = __oprofilefs_create_file(sb, root, name,
-                                                    &ulong_ro_fops, 0444);
-       if (!d)
-               return -EFAULT;
-
-       d->d_inode->i_private = val;
-       return 0;
+       return __oprofilefs_create_file(sb, root, name,
+                                       &ulong_ro_fops, 0444, val);
 }
 
 
@@ -189,31 +184,22 @@ static const struct file_operations atomic_ro_fops = {
 int oprofilefs_create_ro_atomic(struct super_block *sb, struct dentry *root,
        char const *name, atomic_t *val)
 {
-       struct dentry *d = __oprofilefs_create_file(sb, root, name,
-                                                    &atomic_ro_fops, 0444);
-       if (!d)
-               return -EFAULT;
-
-       d->d_inode->i_private = val;
-       return 0;
+       return __oprofilefs_create_file(sb, root, name,
+                                       &atomic_ro_fops, 0444, val);
 }
 
 
 int oprofilefs_create_file(struct super_block *sb, struct dentry *root,
        char const *name, const struct file_operations *fops)
 {
-       if (!__oprofilefs_create_file(sb, root, name, fops, 0644))
-               return -EFAULT;
-       return 0;
+       return __oprofilefs_create_file(sb, root, name, fops, 0644, NULL);
 }
 
 
 int oprofilefs_create_file_perm(struct super_block *sb, struct dentry *root,
        char const *name, const struct file_operations *fops, int perm)
 {
-       if (!__oprofilefs_create_file(sb, root, name, fops, perm))
-               return -EFAULT;
-       return 0;
+       return __oprofilefs_create_file(sb, root, name, fops, perm, NULL);
 }
 
 
index 23e50f4a27c5b8719ac745223b2455d39bea0ad6..787ebdeae31032b853e6e2fce73750f4bf5e4e91 100644 (file)
@@ -48,7 +48,6 @@
 #include <linux/parport.h>
 #include <linux/parport_pc.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/cisreg.h>
@@ -81,14 +80,6 @@ static void parport_detach(struct pcmcia_device *p_dev);
 static int parport_config(struct pcmcia_device *link);
 static void parport_cs_release(struct pcmcia_device *);
 
-/*======================================================================
-
-    parport_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
 static int parport_probe(struct pcmcia_device *link)
 {
     parport_info_t *info;
@@ -101,23 +92,11 @@ static int parport_probe(struct pcmcia_device *link)
     link->priv = info;
     info->p_dev = link;
 
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-    link->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 
     return parport_config(link);
 } /* parport_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void parport_detach(struct pcmcia_device *link)
 {
     dev_dbg(&link->dev, "parport_detach\n");
@@ -127,36 +106,14 @@ static void parport_detach(struct pcmcia_device *link)
     kfree(link->priv);
 } /* parport_detach */
 
-/*======================================================================
-
-    parport_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    parport device available to the system.
-
-======================================================================*/
-
-static int parport_config_check(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
-                               void *priv_data)
+static int parport_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               if (epp_mode)
-                       p_dev->conf.ConfigIndex |= FORCE_EPP_MODE;
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin == 2) {
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-               if (pcmcia_request_io(p_dev) != 0)
-                       return -ENODEV;
-               return 0;
-       }
-       return -ENODEV;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+
+       return pcmcia_request_io(p_dev);
 }
 
 static int parport_config(struct pcmcia_device *link)
@@ -167,13 +124,16 @@ static int parport_config(struct pcmcia_device *link)
 
     dev_dbg(&link->dev, "parport_config\n");
 
+    if (epp_mode)
+           link->config_index |= FORCE_EPP_MODE;
+
     ret = pcmcia_loop_config(link, parport_config_check, NULL);
     if (ret)
            goto failed;
 
     if (!link->irq)
            goto failed;
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
 
@@ -202,14 +162,6 @@ failed:
     return -ENODEV;
 } /* parport_config */
 
-/*======================================================================
-
-    After a card is removed, parport_cs_release() will unregister the
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-    
-======================================================================*/
-
 static void parport_cs_release(struct pcmcia_device *link)
 {
        parport_info_t *info = link->priv;
@@ -236,9 +188,7 @@ MODULE_DEVICE_TABLE(pcmcia, parport_ids);
 
 static struct pcmcia_driver parport_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "parport_cs",
-       },
+       .name           = "parport_cs",
        .probe          = parport_probe,
        .remove         = parport_detach,
        .id_table       = parport_ids,
index dffa5d4fb2986f89b6ab26882bd9de63df81e2e1..a2d9d1e59260eab17097e0a12f16908eed26c552 100644 (file)
@@ -306,7 +306,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
        spin_lock_init(&tmp->pardevice_lock);
        tmp->ieee1284.mode = IEEE1284_MODE_COMPAT;
        tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
-       init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */
+       sema_init(&tmp->ieee1284.irq, 0);
        tmp->spintime = parport_default_spintime;
        atomic_set (&tmp->ref_count, 1);
        INIT_LIST_HEAD(&tmp->full_list);
index 0a19708074c2b5265379ec816e777771823ab861..0157708d474da57ad0532a3bb8bbbd90f0204aeb 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/tboot.h>
 #include <linux/dmi.h>
 #include <linux/slab.h>
+#include <asm/iommu_table.h>
 
 #define PREFIX "DMAR: "
 
@@ -687,7 +688,7 @@ failed:
        return 0;
 }
 
-void __init detect_intel_iommu(void)
+int __init detect_intel_iommu(void)
 {
        int ret;
 
@@ -723,6 +724,8 @@ void __init detect_intel_iommu(void)
        }
        early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size);
        dmar_tbl = NULL;
+
+       return ret ? 1 : -ENODEV;
 }
 
 
@@ -1221,9 +1224,9 @@ const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
        }
 }
 
-void dmar_msi_unmask(unsigned int irq)
+void dmar_msi_unmask(struct irq_data *data)
 {
-       struct intel_iommu *iommu = get_irq_data(irq);
+       struct intel_iommu *iommu = irq_data_get_irq_data(data);
        unsigned long flag;
 
        /* unmask it */
@@ -1234,10 +1237,10 @@ void dmar_msi_unmask(unsigned int irq)
        spin_unlock_irqrestore(&iommu->register_lock, flag);
 }
 
-void dmar_msi_mask(unsigned int irq)
+void dmar_msi_mask(struct irq_data *data)
 {
        unsigned long flag;
-       struct intel_iommu *iommu = get_irq_data(irq);
+       struct intel_iommu *iommu = irq_data_get_irq_data(data);
 
        /* mask it */
        spin_lock_irqsave(&iommu->register_lock, flag);
@@ -1455,3 +1458,4 @@ int __init dmar_ir_support(void)
                return 0;
        return dmar->flags & 0x1;
 }
+IOMMU_INIT_POST(detect_intel_iommu);
index 98abf8b912943f12b6cbcdfe90e4779f3650294e..834842aa5bbf7926b61810cce47c47cb158b1f83 100644 (file)
@@ -57,28 +57,22 @@ void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg)
        *msg = cfg->msg;
 }
 
-void mask_ht_irq(unsigned int irq)
+void mask_ht_irq(struct irq_data *data)
 {
-       struct ht_irq_cfg *cfg;
-       struct ht_irq_msg msg;
-
-       cfg = get_irq_data(irq);
+       struct ht_irq_cfg *cfg = irq_data_get_irq_data(data);
+       struct ht_irq_msg msg = cfg->msg;
 
-       msg = cfg->msg;
        msg.address_lo |= 1;
-       write_ht_irq_msg(irq, &msg);
+       write_ht_irq_msg(data->irq, &msg);
 }
 
-void unmask_ht_irq(unsigned int irq)
+void unmask_ht_irq(struct irq_data *data)
 {
-       struct ht_irq_cfg *cfg;
-       struct ht_irq_msg msg;
-
-       cfg = get_irq_data(irq);
+       struct ht_irq_cfg *cfg = irq_data_get_irq_data(data);
+       struct ht_irq_msg msg = cfg->msg;
 
-       msg = cfg->msg;
        msg.address_lo &= ~1;
-       write_ht_irq_msg(irq, &msg);
+       write_ht_irq_msg(data->irq, &msg);
 }
 
 /**
index fd1d2867cdcc518431032c4562681d53a79de5fe..ec87cd66f3eb21b792381b52c6d8f1656beadede 100644 (file)
@@ -46,109 +46,24 @@ static __init int setup_intremap(char *str)
 }
 early_param("intremap", setup_intremap);
 
-struct irq_2_iommu {
-       struct intel_iommu *iommu;
-       u16 irte_index;
-       u16 sub_handle;
-       u8  irte_mask;
-};
-
-#ifdef CONFIG_GENERIC_HARDIRQS
-static struct irq_2_iommu *get_one_free_irq_2_iommu(int node)
-{
-       struct irq_2_iommu *iommu;
-
-       iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node);
-       printk(KERN_DEBUG "alloc irq_2_iommu on node %d\n", node);
-
-       return iommu;
-}
-
-static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
-{
-       struct irq_desc *desc;
-
-       desc = irq_to_desc(irq);
-
-       if (WARN_ON_ONCE(!desc))
-               return NULL;
-
-       return desc->irq_2_iommu;
-}
-
-static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
-{
-       struct irq_desc *desc;
-       struct irq_2_iommu *irq_iommu;
-
-       desc = irq_to_desc(irq);
-       if (!desc) {
-               printk(KERN_INFO "can not get irq_desc for %d\n", irq);
-               return NULL;
-       }
-
-       irq_iommu = desc->irq_2_iommu;
-
-       if (!irq_iommu)
-               desc->irq_2_iommu = get_one_free_irq_2_iommu(irq_node(irq));
-
-       return desc->irq_2_iommu;
-}
-
-#else /* !CONFIG_SPARSE_IRQ */
-
-static struct irq_2_iommu irq_2_iommuX[NR_IRQS];
-
-static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
-{
-       if (irq < nr_irqs)
-               return &irq_2_iommuX[irq];
-
-       return NULL;
-}
-static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
-{
-       return irq_2_iommu(irq);
-}
-#endif
-
 static DEFINE_SPINLOCK(irq_2_ir_lock);
 
-static struct irq_2_iommu *valid_irq_2_iommu(unsigned int irq)
-{
-       struct irq_2_iommu *irq_iommu;
-
-       irq_iommu = irq_2_iommu(irq);
-
-       if (!irq_iommu)
-               return NULL;
-
-       if (!irq_iommu->iommu)
-               return NULL;
-
-       return irq_iommu;
-}
-
-int irq_remapped(int irq)
+static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
 {
-       return valid_irq_2_iommu(irq) != NULL;
+       struct irq_cfg *cfg = get_irq_chip_data(irq);
+       return cfg ? &cfg->irq_2_iommu : NULL;
 }
 
 int get_irte(int irq, struct irte *entry)
 {
-       int index;
-       struct irq_2_iommu *irq_iommu;
+       struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
        unsigned long flags;
+       int index;
 
-       if (!entry)
+       if (!entry || !irq_iommu)
                return -1;
 
        spin_lock_irqsave(&irq_2_ir_lock, flags);
-       irq_iommu = valid_irq_2_iommu(irq);
-       if (!irq_iommu) {
-               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-               return -1;
-       }
 
        index = irq_iommu->irte_index + irq_iommu->sub_handle;
        *entry = *(irq_iommu->iommu->ir_table->base + index);
@@ -160,20 +75,14 @@ int get_irte(int irq, struct irte *entry)
 int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
 {
        struct ir_table *table = iommu->ir_table;
-       struct irq_2_iommu *irq_iommu;
+       struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
        u16 index, start_index;
        unsigned int mask = 0;
        unsigned long flags;
        int i;
 
-       if (!count)
-               return -1;
-
-#ifndef CONFIG_SPARSE_IRQ
-       /* protect irq_2_iommu_alloc later */
-       if (irq >= nr_irqs)
+       if (!count || !irq_iommu)
                return -1;
-#endif
 
        /*
         * start the IRTE search from index 0.
@@ -214,13 +123,6 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
        for (i = index; i < index + count; i++)
                table->base[i].present = 1;
 
-       irq_iommu = irq_2_iommu_alloc(irq);
-       if (!irq_iommu) {
-               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-               printk(KERN_ERR "can't allocate irq_2_iommu\n");
-               return -1;
-       }
-
        irq_iommu->iommu = iommu;
        irq_iommu->irte_index =  index;
        irq_iommu->sub_handle = 0;
@@ -244,17 +146,14 @@ static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
 
 int map_irq_to_irte_handle(int irq, u16 *sub_handle)
 {
-       int index;
-       struct irq_2_iommu *irq_iommu;
+       struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
        unsigned long flags;
+       int index;
 
-       spin_lock_irqsave(&irq_2_ir_lock, flags);
-       irq_iommu = valid_irq_2_iommu(irq);
-       if (!irq_iommu) {
-               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
+       if (!irq_iommu)
                return -1;
-       }
 
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
        *sub_handle = irq_iommu->sub_handle;
        index = irq_iommu->irte_index;
        spin_unlock_irqrestore(&irq_2_ir_lock, flags);
@@ -263,18 +162,13 @@ int map_irq_to_irte_handle(int irq, u16 *sub_handle)
 
 int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
 {
-       struct irq_2_iommu *irq_iommu;
+       struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
        unsigned long flags;
 
-       spin_lock_irqsave(&irq_2_ir_lock, flags);
-
-       irq_iommu = irq_2_iommu_alloc(irq);
-
-       if (!irq_iommu) {
-               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-               printk(KERN_ERR "can't allocate irq_2_iommu\n");
+       if (!irq_iommu)
                return -1;
-       }
+
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
 
        irq_iommu->iommu = iommu;
        irq_iommu->irte_index = index;
@@ -286,43 +180,18 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
        return 0;
 }
 
-int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index)
-{
-       struct irq_2_iommu *irq_iommu;
-       unsigned long flags;
-
-       spin_lock_irqsave(&irq_2_ir_lock, flags);
-       irq_iommu = valid_irq_2_iommu(irq);
-       if (!irq_iommu) {
-               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-               return -1;
-       }
-
-       irq_iommu->iommu = NULL;
-       irq_iommu->irte_index = 0;
-       irq_iommu->sub_handle = 0;
-       irq_2_iommu(irq)->irte_mask = 0;
-
-       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-
-       return 0;
-}
-
 int modify_irte(int irq, struct irte *irte_modified)
 {
-       int rc;
-       int index;
-       struct irte *irte;
+       struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
        struct intel_iommu *iommu;
-       struct irq_2_iommu *irq_iommu;
        unsigned long flags;
+       struct irte *irte;
+       int rc, index;
 
-       spin_lock_irqsave(&irq_2_ir_lock, flags);
-       irq_iommu = valid_irq_2_iommu(irq);
-       if (!irq_iommu) {
-               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
+       if (!irq_iommu)
                return -1;
-       }
+
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
 
        iommu = irq_iommu->iommu;
 
@@ -339,31 +208,6 @@ int modify_irte(int irq, struct irte *irte_modified)
        return rc;
 }
 
-int flush_irte(int irq)
-{
-       int rc;
-       int index;
-       struct intel_iommu *iommu;
-       struct irq_2_iommu *irq_iommu;
-       unsigned long flags;
-
-       spin_lock_irqsave(&irq_2_ir_lock, flags);
-       irq_iommu = valid_irq_2_iommu(irq);
-       if (!irq_iommu) {
-               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-               return -1;
-       }
-
-       iommu = irq_iommu->iommu;
-
-       index = irq_iommu->irte_index + irq_iommu->sub_handle;
-
-       rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask);
-       spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-
-       return rc;
-}
-
 struct intel_iommu *map_hpet_to_ir(u8 hpet_id)
 {
        int i;
@@ -420,16 +264,14 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
 
 int free_irte(int irq)
 {
-       int rc = 0;
-       struct irq_2_iommu *irq_iommu;
+       struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
        unsigned long flags;
+       int rc;
 
-       spin_lock_irqsave(&irq_2_ir_lock, flags);
-       irq_iommu = valid_irq_2_iommu(irq);
-       if (!irq_iommu) {
-               spin_unlock_irqrestore(&irq_2_ir_lock, flags);
+       if (!irq_iommu)
                return -1;
-       }
+
+       spin_lock_irqsave(&irq_2_ir_lock, flags);
 
        rc = clear_entries(irq_iommu);
 
index 69b7be33b3a24768a460843a13c17a88c96a8024..5fcf5aec680fc36a345dd08d0c6a54287a2dfb34 100644 (file)
@@ -170,33 +170,31 @@ static void msix_mask_irq(struct msi_desc *desc, u32 flag)
        desc->masked = __msix_mask_irq(desc, flag);
 }
 
-static void msi_set_mask_bit(unsigned irq, u32 flag)
+static void msi_set_mask_bit(struct irq_data *data, u32 flag)
 {
-       struct msi_desc *desc = get_irq_msi(irq);
+       struct msi_desc *desc = irq_data_get_msi(data);
 
        if (desc->msi_attrib.is_msix) {
                msix_mask_irq(desc, flag);
                readl(desc->mask_base);         /* Flush write to device */
        } else {
-               unsigned offset = irq - desc->dev->irq;
+               unsigned offset = data->irq - desc->dev->irq;
                msi_mask_irq(desc, 1 << offset, flag << offset);
        }
 }
 
-void mask_msi_irq(unsigned int irq)
+void mask_msi_irq(struct irq_data *data)
 {
-       msi_set_mask_bit(irq, 1);
+       msi_set_mask_bit(data, 1);
 }
 
-void unmask_msi_irq(unsigned int irq)
+void unmask_msi_irq(struct irq_data *data)
 {
-       msi_set_mask_bit(irq, 0);
+       msi_set_mask_bit(data, 0);
 }
 
-void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
+void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
 {
-       struct msi_desc *entry = get_irq_desc_msi(desc);
-
        BUG_ON(entry->dev->current_state != PCI_D0);
 
        if (entry->msi_attrib.is_msix) {
@@ -227,15 +225,13 @@ void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
 
 void read_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct msi_desc *entry = get_irq_msi(irq);
 
-       read_msi_msg_desc(desc, msg);
+       __read_msi_msg(entry, msg);
 }
 
-void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
+void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
 {
-       struct msi_desc *entry = get_irq_desc_msi(desc);
-
        /* Assert that the cache is valid, assuming that
         * valid messages are not all-zeroes. */
        BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo |
@@ -246,15 +242,13 @@ void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
 
 void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct msi_desc *entry = get_irq_msi(irq);
 
-       get_cached_msi_msg_desc(desc, msg);
+       __get_cached_msi_msg(entry, msg);
 }
 
-void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
+void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
 {
-       struct msi_desc *entry = get_irq_desc_msi(desc);
-
        if (entry->dev->current_state != PCI_D0) {
                /* Don't touch the hardware now */
        } else if (entry->msi_attrib.is_msix) {
@@ -292,9 +286,9 @@ void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
 
 void write_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct msi_desc *entry = get_irq_msi(irq);
 
-       write_msi_msg_desc(desc, msg);
+       __write_msi_msg(entry, msg);
 }
 
 static void free_msi_irqs(struct pci_dev *dev)
index 88c4c4098789e1e3e3b08dc3847412c570ebfc35..95dd7c62741ffb7a8014ade9885b072e1c15a4b9 100644 (file)
@@ -441,14 +441,12 @@ int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops,
 
 
 out_err:
-       flush_scheduled_work();
        ops->hw_shutdown(skt);
        while (i-- > 0) {
                skt = PCMCIA_SOCKET(i);
 
                del_timer_sync(&skt->poll_timer);
                pcmcia_unregister_socket(&skt->socket);
-               flush_scheduled_work();
                if (i == 0) {
                        iounmap(skt->virt_io + (u32)mips_io_port_base);
                        skt->virt_io = NULL;
@@ -480,7 +478,6 @@ int au1x00_drv_pcmcia_remove(struct platform_device *dev)
 
                del_timer_sync(&skt->poll_timer);
                pcmcia_unregister_socket(&skt->socket);
-               flush_scheduled_work();
                skt->ops->hw_shutdown(skt);
                au1x00_pcmcia_config_skt(skt, &dead_socket);
                iounmap(skt->virt_io + (u32)mips_io_port_base);
index 67530cefcf3c1bfd5d36ea1f93068a841e2d5642..5c36bda2963b3981a7e91fe2bb4ceb033fa9a2e9 100644 (file)
@@ -23,7 +23,6 @@
 
 /* include the world */
 
-#include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
index 807f2d75dad3a84f7b98142af3e52e812cc601bd..b2396647a1656774a50b484031a7e41eede60de7 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/proc_fs.h>
 #include <linux/types.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
 
index 91414a0ddc442823faebfb1db8b5420ba407630a..884a984216febe247dee1bdcad69d47d1cd1adf2 100644 (file)
@@ -28,7 +28,6 @@
 #include <asm/unaligned.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
index 2ec8ac97445c1491d73102808de25dcf8e2c26bc..d9ea192c4001ed9e315d21bac96b2ab37361376f 100644 (file)
@@ -33,7 +33,6 @@
 #include <asm/irq.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -845,7 +844,7 @@ static int pcmcia_socket_dev_resume_noirq(struct device *dev)
        return __pcmcia_pm_op(dev, socket_early_resume);
 }
 
-static int pcmcia_socket_dev_resume(struct device *dev)
+static int __used pcmcia_socket_dev_resume(struct device *dev)
 {
        return __pcmcia_pm_op(dev, socket_late_resume);
 }
index da055dc14d98a2933953e206d9544d33cc74cb17..7f1953f78b12b906421a4c8f130d4094e49c6d74 100644 (file)
 typedef struct config_t {
        struct kref     ref;
        unsigned int    state;
-       unsigned int    Attributes;
-       unsigned int    IntType;
-       unsigned int    ConfigBase;
-       unsigned char   Status, Pin, Copy, Option, ExtStatus;
-       unsigned int    CardValues;
 
        struct resource io[MAX_IO_WIN]; /* io ports */
        struct resource mem[MAX_WIN];   /* mem areas */
-
-       struct {
-               u_int   Attributes;
-       } irq;
 } config_t;
 
 
index 55570d9e1e4cc0246fe9c9add4583ccad5e3dae7..100c4412457de1357348c9e9eb5b3c29ae8bbdd8 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ss.h>
@@ -52,7 +51,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
 
        if (!p_drv->probe || !p_drv->remove)
                printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback "
-                      "function\n", p_drv->drv.name);
+                      "function\n", p_drv->name);
 
        while (did && did->match_flags) {
                for (i = 0; i < 4; i++) {
@@ -65,7 +64,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
 
                        printk(KERN_DEBUG "pcmcia: %s: invalid hash for "
                               "product string \"%s\": is 0x%x, should "
-                              "be 0x%x\n", p_drv->drv.name, did->prod_id[i],
+                              "be 0x%x\n", p_drv->name, did->prod_id[i],
                               did->prod_id_hash[i], hash);
                        printk(KERN_DEBUG "pcmcia: see "
                                "Documentation/pcmcia/devicetable.txt for "
@@ -180,10 +179,11 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
        /* initialize common fields */
        driver->drv.bus = &pcmcia_bus_type;
        driver->drv.owner = driver->owner;
+       driver->drv.name = driver->name;
        mutex_init(&driver->dynids.lock);
        INIT_LIST_HEAD(&driver->dynids.list);
 
-       pr_debug("registering driver %s\n", driver->drv.name);
+       pr_debug("registering driver %s\n", driver->name);
 
        error = driver_register(&driver->drv);
        if (error < 0)
@@ -203,7 +203,7 @@ EXPORT_SYMBOL(pcmcia_register_driver);
  */
 void pcmcia_unregister_driver(struct pcmcia_driver *driver)
 {
-       pr_debug("unregistering driver %s\n", driver->drv.name);
+       pr_debug("unregistering driver %s\n", driver->name);
        driver_unregister(&driver->drv);
        pcmcia_free_dynids(driver);
 }
@@ -264,7 +264,7 @@ static int pcmcia_device_probe(struct device *dev)
        p_drv = to_pcmcia_drv(dev->driver);
        s = p_dev->socket;
 
-       dev_dbg(dev, "trying to bind to %s\n", p_drv->drv.name);
+       dev_dbg(dev, "trying to bind to %s\n", p_drv->name);
 
        if ((!p_drv->probe) || (!p_dev->function_config) ||
            (!try_module_get(p_drv->owner))) {
@@ -276,21 +276,28 @@ static int pcmcia_device_probe(struct device *dev)
        ret = pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_CONFIG,
                                &cis_config);
        if (!ret) {
-               p_dev->conf.ConfigBase = cis_config.base;
-               p_dev->conf.Present = cis_config.rmask[0];
+               p_dev->config_base = cis_config.base;
+               p_dev->config_regs = cis_config.rmask[0];
+               dev_dbg(dev, "base %x, regs %x", p_dev->config_base,
+                       p_dev->config_regs);
        } else {
                dev_printk(KERN_INFO, dev,
                           "pcmcia: could not parse base and rmask0 of CIS\n");
-               p_dev->conf.ConfigBase = 0;
-               p_dev->conf.Present = 0;
+               p_dev->config_base = 0;
+               p_dev->config_regs = 0;
        }
 
        ret = p_drv->probe(p_dev);
        if (ret) {
                dev_dbg(dev, "binding to %s failed with %d\n",
-                          p_drv->drv.name, ret);
+                          p_drv->name, ret);
                goto put_module;
        }
+       dev_dbg(dev, "%s bound: Vpp %d.%d, idx %x, IRQ %d", p_drv->name,
+               p_dev->vpp/10, p_dev->vpp%10, p_dev->config_index, p_dev->irq);
+       dev_dbg(dev, "resources: ioport %pR %pR iomem %pR %pR %pR",
+               p_dev->resource[0], p_dev->resource[1], p_dev->resource[2],
+               p_dev->resource[3], p_dev->resource[4]);
 
        mutex_lock(&s->ops_mutex);
        if ((s->pcmcia_pfc) &&
@@ -374,13 +381,13 @@ static int pcmcia_device_remove(struct device *dev)
        if (p_dev->_irq || p_dev->_io || p_dev->_locked)
                dev_printk(KERN_INFO, dev,
                        "pcmcia: driver %s did not release config properly\n",
-                       p_drv->drv.name);
+                       p_drv->name);
 
        for (i = 0; i < MAX_WIN; i++)
                if (p_dev->_win & CLIENT_WIN_REQ(i))
                        dev_printk(KERN_INFO, dev,
                          "pcmcia: driver %s did not release window properly\n",
-                          p_drv->drv.name);
+                          p_drv->name);
 
        /* references from pcmcia_probe_device */
        pcmcia_put_dev(p_dev);
@@ -1136,7 +1143,7 @@ static int pcmcia_dev_suspend(struct device *dev, pm_message_t state)
                        dev_printk(KERN_ERR, dev,
                                   "pcmcia: device %s (driver %s) did "
                                   "not want to go to sleep (%d)\n",
-                                  p_dev->devname, p_drv->drv.name, ret);
+                                  p_dev->devname, p_drv->name, ret);
                        mutex_lock(&p_dev->socket->ops_mutex);
                        p_dev->suspended = 0;
                        mutex_unlock(&p_dev->socket->ops_mutex);
@@ -1178,7 +1185,7 @@ static int pcmcia_dev_resume(struct device *dev)
 
        if (p_dev->device_no == p_dev->func) {
                dev_dbg(dev, "requesting configuration\n");
-               ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
+               ret = pcmcia_enable_device(p_dev);
                if (ret)
                        goto out;
        }
index 05d0879ce93568194f36f393cb951b43f3155bc8..fc7906eaf22877f16e0904219ec2544e6f3ebfa4 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/device.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
index 61746bd598b36a58d1ee5c5c5a87e48b740532cc..72a033a2acdb262684cf02a164efb6ee89cea408 100644 (file)
@@ -51,7 +51,6 @@
 #include <asm/system.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 
 #include <linux/isapnp.h>
 
index 24de499258630e2e6442ac0045134fa647fd0746..2adb0106a0397a3800b9c707493f871490d5636f 100644 (file)
@@ -27,7 +27,6 @@
 #include <asm/system.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 
 #undef MAX_IO_WIN      /* FIXME */
 #define MAX_IO_WIN 1
index 8e4723844ad3a2bb447de65e70ea236e2d22e3ef..1511ff71c87b013914491e2695a97995253a694f 100644 (file)
@@ -28,7 +28,6 @@
 #include <asm/addrspace.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 
 /* XXX: should be moved into asm/irq.h */
 #define PCC0_IRQ 24
index f0ecad99ce819d0af8ac77467e2bce332bdc7bc8..99d4f23cb4353136dc73a7d0b7d6309f6f71f97e 100644 (file)
@@ -59,7 +59,6 @@
 #include <asm/irq.h>
 #include <asm/fs_pd.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 
 #define pcmcia_info(args...) printk(KERN_INFO "m8xx_pcmcia: "args)
index e74bebac26950b2c9d5869c310f835ef99662b64..5096e92c7a4cfb39e1e300f5d8ac8016b5fe54d4 100644 (file)
@@ -153,14 +153,14 @@ static int o2micro_override(struct yenta_socket *socket)
 
                if (use_speedup) {
                        dev_info(&socket->dev->dev,
-                               "O2: enabling read prefetch/write burst\n");
+                               "O2: enabling read prefetch/write burst. If you experience problems or performance issues, use the yenta_socket parameter 'o2_speedup=off'\n");
                        config_writeb(socket, O2_RESERVED1,
                                      a | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
                        config_writeb(socket, O2_RESERVED2,
                                      b | O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST);
                } else {
                        dev_info(&socket->dev->dev,
-                               "O2: disabling read prefetch/write burst\n");
+                               "O2: disabling read prefetch/write burst. If you experience problems or performance issues, use the yenta_socket parameter 'o2_speedup=on'\n");
                        config_writeb(socket, O2_RESERVED1,
                                      a & ~(O2_RES_READ_PREFETCH | O2_RES_WRITE_BURST));
                        config_writeb(socket, O2_RESERVED2,
index 0ac54da158850352c766cebd9c5a502b5b7e65e0..e2c92415b8924a89c27e6759652b4a7e5726139b 100644 (file)
@@ -6,7 +6,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Copyright (C) 1999       David A. Hinds
- * Copyright (C) 2004-2009   Dominik Brodowski
+ * Copyright (C) 2004-2010   Dominik Brodowski
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -22,7 +22,6 @@
 #include <pcmcia/cisreg.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/ds.h>
 #include "cs_internal.h"
 
@@ -126,14 +125,24 @@ next_entry:
        return ret;
 }
 
+
+/**
+ * pcmcia_io_cfg_data_width() - convert cfgtable to data path width parameter
+ */
+static int pcmcia_io_cfg_data_width(unsigned int flags)
+{
+       if (!(flags & CISTPL_IO_8BIT))
+               return IO_DATA_PATH_WIDTH_16;
+       if (!(flags & CISTPL_IO_16BIT))
+               return IO_DATA_PATH_WIDTH_8;
+       return IO_DATA_PATH_WIDTH_AUTO;
+}
+
+
 struct pcmcia_cfg_mem {
        struct pcmcia_device *p_dev;
+       int (*conf_check) (struct pcmcia_device *p_dev, void *priv_data);
        void *priv_data;
-       int (*conf_check) (struct pcmcia_device *p_dev,
-                          cistpl_cftable_entry_t *cfg,
-                          cistpl_cftable_entry_t *dflt,
-                          unsigned int vcc,
-                          void *priv_data);
        cisparse_t parse;
        cistpl_cftable_entry_t dflt;
 };
@@ -147,25 +156,102 @@ struct pcmcia_cfg_mem {
  */
 static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv)
 {
-       cistpl_cftable_entry_t *cfg = &parse->cftable_entry;
        struct pcmcia_cfg_mem *cfg_mem = priv;
+       struct pcmcia_device *p_dev = cfg_mem->p_dev;
+       cistpl_cftable_entry_t *cfg = &parse->cftable_entry;
+       cistpl_cftable_entry_t *dflt = &cfg_mem->dflt;
+       unsigned int flags = p_dev->config_flags;
+       unsigned int vcc = p_dev->socket->socket.Vcc;
+
+       dev_dbg(&p_dev->dev, "testing configuration %x, autoconf %x\n",
+               cfg->index, flags);
 
        /* default values */
-       cfg_mem->p_dev->conf.ConfigIndex = cfg->index;
+       cfg_mem->p_dev->config_index = cfg->index;
        if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
                cfg_mem->dflt = *cfg;
 
-       return cfg_mem->conf_check(cfg_mem->p_dev, cfg, &cfg_mem->dflt,
-                                  cfg_mem->p_dev->socket->socket.Vcc,
-                                  cfg_mem->priv_data);
+       /* check for matching Vcc? */
+       if (flags & CONF_AUTO_CHECK_VCC) {
+               if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+                       if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+                               return -ENODEV;
+               } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+                       if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000)
+                               return -ENODEV;
+               }
+       }
+
+       /* set Vpp? */
+       if (flags & CONF_AUTO_SET_VPP) {
+               if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+                       p_dev->vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+               else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM))
+                       p_dev->vpp =
+                               dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       }
+
+       /* enable audio? */
+       if ((flags & CONF_AUTO_AUDIO) && (cfg->flags & CISTPL_CFTABLE_AUDIO))
+               p_dev->config_flags |= CONF_ENABLE_SPKR;
+
+
+       /* IO window settings? */
+       if (flags & CONF_AUTO_SET_IO) {
+               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
+               int i = 0;
+
+               p_dev->resource[0]->start = p_dev->resource[0]->end = 0;
+               p_dev->resource[1]->start = p_dev->resource[1]->end = 0;
+               if (io->nwin == 0)
+                       return -ENODEV;
+
+               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+               p_dev->resource[0]->flags |=
+                                       pcmcia_io_cfg_data_width(io->flags);
+               if (io->nwin > 1) {
+                       /* For multifunction cards, by convention, we
+                        * configure the network function with window 0,
+                        * and serial with window 1 */
+                       i = (io->win[1].len > io->win[0].len);
+                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
+                       p_dev->resource[1]->start = io->win[1-i].base;
+                       p_dev->resource[1]->end = io->win[1-i].len;
+               }
+               p_dev->resource[0]->start = io->win[i].base;
+               p_dev->resource[0]->end = io->win[i].len;
+               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
+       }
+
+       /* MEM window settings? */
+       if (flags & CONF_AUTO_SET_IOMEM) {
+               /* so far, we only set one memory window */
+               cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
+
+               p_dev->resource[2]->start = p_dev->resource[2]->end = 0;
+               if (mem->nwin == 0)
+                       return -ENODEV;
+
+               p_dev->resource[2]->start = mem->win[0].host_addr;
+               p_dev->resource[2]->end = mem->win[0].len;
+               if (p_dev->resource[2]->end < 0x1000)
+                       p_dev->resource[2]->end = 0x1000;
+               p_dev->card_addr = mem->win[0].card_addr;
+       }
+
+       dev_dbg(&p_dev->dev,
+               "checking configuration %x: %pr %pr %pr (%d lines)\n",
+               p_dev->config_index, p_dev->resource[0], p_dev->resource[1],
+               p_dev->resource[2], p_dev->io_lines);
+
+       return cfg_mem->conf_check(p_dev, cfg_mem->priv_data);
 }
 
 /**
  * pcmcia_loop_config() - loop over configuration options
  * @p_dev:     the struct pcmcia_device which we need to loop for.
  * @conf_check:        function to call for each configuration option.
- *             It gets passed the struct pcmcia_device, the CIS data
- *             describing the configuration option, and private data
+ *             It gets passed the struct pcmcia_device and private data
  *             being passed to pcmcia_loop_config()
  * @priv_data: private data to be passed to the conf_check function.
  *
@@ -175,9 +261,6 @@ static int pcmcia_do_loop_config(tuple_t *tuple, cisparse_t *parse, void *priv)
  */
 int pcmcia_loop_config(struct pcmcia_device *p_dev,
                       int      (*conf_check)   (struct pcmcia_device *p_dev,
-                                                cistpl_cftable_entry_t *cfg,
-                                                cistpl_cftable_entry_t *dflt,
-                                                unsigned int vcc,
                                                 void *priv_data),
                       void *priv_data)
 {
index 9ba4dade69a4d67cd5b0efc1e4c55a70dbf349c1..a9af0d7844266527aaefe3032bc9d6ee9d9d061e 100644 (file)
@@ -6,7 +6,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Copyright (C) 1999       David A. Hinds
- * Copyright (C) 2004-2005   Dominik Brodowski
+ * Copyright (C) 2004-2010   Dominik Brodowski
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -26,7 +26,6 @@
 #include <asm/irq.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -56,6 +55,12 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
 }
 
 
+/**
+ * release_io_space() - release IO ports allocated with alloc_io_space()
+ * @s: pcmcia socket
+ * @res: resource to release
+ *
+ */
 static void release_io_space(struct pcmcia_socket *s, struct resource *res)
 {
        resource_size_t num = resource_size(res);
@@ -81,9 +86,14 @@ static void release_io_space(struct pcmcia_socket *s, struct resource *res)
                        }
                }
        }
-} /* release_io_space */
+}
+
 
-/** alloc_io_space
+/**
+ * alloc_io_space() - allocate IO ports for use by a PCMCIA device
+ * @s: pcmcia socket
+ * @res: resource to allocate (begin: begin, end: size)
+ * @lines: number of IO lines decoded by the PCMCIA card
  *
  * Special stuff for managing IO windows, because they are scarce
  */
@@ -135,7 +145,7 @@ static int alloc_io_space(struct pcmcia_socket *s, struct resource *res,
        }
        dev_dbg(&s->dev, "alloc_io_space request result %d: %pR\n", ret, res);
        return ret;
-} /* alloc_io_space */
+}
 
 
 /**
@@ -168,14 +178,14 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev,
                return -EACCES;
        }
 
-       addr = (c->ConfigBase + where) >> 1;
+       addr = (p_dev->config_base + where) >> 1;
 
        ret = accessf(s, 1, addr, 1, val);
 
        mutex_unlock(&s->ops_mutex);
 
        return ret;
-} /* pcmcia_access_config */
+}
 
 
 /**
@@ -204,11 +214,20 @@ int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val)
 EXPORT_SYMBOL(pcmcia_write_config_byte);
 
 
-int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,
+/**
+ * pcmcia_map_mem_page() - modify iomem window to point to a different offset
+ * @p_dev: pcmcia device
+ * @res: iomem resource already enabled by pcmcia_request_window()
+ * @offset: card_offset to map
+ *
+ * pcmcia_map_mem_page() modifies what can be read and written by accessing
+ * an iomem range previously enabled by pcmcia_request_window(), by setting
+ * the card_offset value to @offset.
+ */
+int pcmcia_map_mem_page(struct pcmcia_device *p_dev, struct resource *res,
                        unsigned int offset)
 {
        struct pcmcia_socket *s = p_dev->socket;
-       struct resource *res = wh;
        unsigned int w;
        int ret;
 
@@ -223,98 +242,111 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,
                dev_warn(&p_dev->dev, "failed to set_mem_map\n");
        mutex_unlock(&s->ops_mutex);
        return ret;
-} /* pcmcia_map_mem_page */
+}
 EXPORT_SYMBOL(pcmcia_map_mem_page);
 
 
-/** pcmcia_modify_configuration
+/**
+ * pcmcia_fixup_iowidth() - reduce io width to 8bit
+ * @p_dev: pcmcia device
  *
- * Modify a locked socket configuration
+ * pcmcia_fixup_iowidth() allows a PCMCIA device driver to reduce the
+ * IO width to 8bit after having called pcmcia_enable_device()
+ * previously.
  */
-int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
-                               modconf_t *mod)
+int pcmcia_fixup_iowidth(struct pcmcia_device *p_dev)
 {
-       struct pcmcia_socket *s;
-       config_t *c;
-       int ret;
-
-       s = p_dev->socket;
+       struct pcmcia_socket *s = p_dev->socket;
+       pccard_io_map io_off = { 0, 0, 0, 0, 1 };
+       pccard_io_map io_on;
+       int i, ret = 0;
 
        mutex_lock(&s->ops_mutex);
-       c = p_dev->function_config;
 
-       if (!(s->state & SOCKET_PRESENT)) {
-               dev_dbg(&p_dev->dev, "No card present\n");
-               ret = -ENODEV;
-               goto unlock;
-       }
-       if (!(c->state & CONFIG_LOCKED)) {
-               dev_dbg(&p_dev->dev, "Configuration isnt't locked\n");
+       dev_dbg(&p_dev->dev, "fixup iowidth to 8bit\n");
+
+       if (!(s->state & SOCKET_PRESENT) ||
+               !(p_dev->function_config->state & CONFIG_LOCKED)) {
+               dev_dbg(&p_dev->dev, "No card? Config not locked?\n");
                ret = -EACCES;
                goto unlock;
        }
 
-       if (mod->Attributes & (CONF_IRQ_CHANGE_VALID | CONF_VCC_CHANGE_VALID)) {
-               dev_dbg(&p_dev->dev,
-                       "changing Vcc or IRQ is not allowed at this time\n");
-               ret = -EINVAL;
-               goto unlock;
-       }
+       io_on.speed = io_speed;
+       for (i = 0; i < MAX_IO_WIN; i++) {
+               if (!s->io[i].res)
+                       continue;
+               io_off.map = i;
+               io_on.map = i;
 
-       /* We only allow changing Vpp1 and Vpp2 to the same value */
-       if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
-           (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
-               if (mod->Vpp1 != mod->Vpp2) {
-                       dev_dbg(&p_dev->dev,
-                               "Vpp1 and Vpp2 must be the same\n");
-                       ret = -EINVAL;
-                       goto unlock;
-               }
-               s->socket.Vpp = mod->Vpp1;
-               if (s->ops->set_socket(s, &s->socket)) {
-                       dev_printk(KERN_WARNING, &p_dev->dev,
-                                  "Unable to set VPP\n");
-                       ret = -EIO;
-                       goto unlock;
-               }
-       } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
-                  (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
-               dev_dbg(&p_dev->dev,
-                       "changing Vcc is not allowed at this time\n");
-               ret = -EINVAL;
-               goto unlock;
+               io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8;
+               io_on.start = s->io[i].res->start;
+               io_on.stop = s->io[i].res->end;
+
+               s->ops->set_io_map(s, &io_off);
+               mdelay(40);
+               s->ops->set_io_map(s, &io_on);
        }
+unlock:
+       mutex_unlock(&s->ops_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(pcmcia_fixup_iowidth);
+
+
+/**
+ * pcmcia_fixup_vpp() - set Vpp to a new voltage level
+ * @p_dev: pcmcia device
+ * @new_vpp: new Vpp voltage
+ *
+ * pcmcia_fixup_vpp() allows a PCMCIA device driver to set Vpp to
+ * a new voltage level between calls to pcmcia_enable_device()
+ * and pcmcia_disable_device().
+ */
+int pcmcia_fixup_vpp(struct pcmcia_device *p_dev, unsigned char new_vpp)
+{
+       struct pcmcia_socket *s = p_dev->socket;
+       int ret = 0;
 
-       if (mod->Attributes & CONF_IO_CHANGE_WIDTH) {
-               pccard_io_map io_off = { 0, 0, 0, 0, 1 };
-               pccard_io_map io_on;
-               int i;
+       mutex_lock(&s->ops_mutex);
 
-               io_on.speed = io_speed;
-               for (i = 0; i < MAX_IO_WIN; i++) {
-                       if (!s->io[i].res)
-                               continue;
-                       io_off.map = i;
-                       io_on.map = i;
+       dev_dbg(&p_dev->dev, "fixup Vpp to %d\n", new_vpp);
 
-                       io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8;
-                       io_on.start = s->io[i].res->start;
-                       io_on.stop = s->io[i].res->end;
+       if (!(s->state & SOCKET_PRESENT) ||
+               !(p_dev->function_config->state & CONFIG_LOCKED)) {
+               dev_dbg(&p_dev->dev, "No card? Config not locked?\n");
+               ret = -EACCES;
+               goto unlock;
+       }
 
-                       s->ops->set_io_map(s, &io_off);
-                       mdelay(40);
-                       s->ops->set_io_map(s, &io_on);
-               }
+       s->socket.Vpp = new_vpp;
+       if (s->ops->set_socket(s, &s->socket)) {
+               dev_warn(&p_dev->dev, "Unable to set VPP\n");
+               ret = -EIO;
+               goto unlock;
        }
-       ret = 0;
+       p_dev->vpp = new_vpp;
+
 unlock:
        mutex_unlock(&s->ops_mutex);
 
        return ret;
-} /* modify_configuration */
-EXPORT_SYMBOL(pcmcia_modify_configuration);
+}
+EXPORT_SYMBOL(pcmcia_fixup_vpp);
 
 
+/**
+ * pcmcia_release_configuration() - physically disable a PCMCIA device
+ * @p_dev: pcmcia device
+ *
+ * pcmcia_release_configuration() is the 1:1 counterpart to
+ * pcmcia_enable_device(): If a PCMCIA device is no longer used by any
+ * driver, the Vpp voltage is set to 0, IRQs will no longer be generated,
+ * and I/O ranges will be disabled. As pcmcia_release_io() and
+ * pcmcia_release_window() still need to be called, device drivers are
+ * expected to call pcmcia_disable_device() instead.
+ */
 int pcmcia_release_configuration(struct pcmcia_device *p_dev)
 {
        pccard_io_map io = { 0, 0, 0, 0, 1 };
@@ -327,7 +359,7 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
        if (p_dev->_locked) {
                p_dev->_locked = 0;
                if (--(s->lock_count) == 0) {
-                       s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */
+                       s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */
                        s->socket.Vpp = 0;
                        s->socket.io_irq = 0;
                        s->ops->set_socket(s, &s->socket);
@@ -349,16 +381,18 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
        mutex_unlock(&s->ops_mutex);
 
        return 0;
-} /* pcmcia_release_configuration */
+}
 
 
-/** pcmcia_release_io
+/**
+ * pcmcia_release_io() - release I/O allocated by a PCMCIA device
+ * @p_dev: pcmcia device
  *
- * Release_io() releases the I/O ranges allocated by a client.  This
- * may be invoked some time after a card ejection has already dumped
- * the actual socket configuration, so if the client is "stale", we
- * don't bother checking the port ranges against the current socket
- * values.
+ * pcmcia_release_io() releases the I/O ranges allocated by a PCMCIA
+ * device.  This may be invoked some time after a card ejection has
+ * already dumped the actual socket configuration, so if the client is
+ * "stale", we don't bother checking the port ranges against the
+ * current socket values.
  */
 static int pcmcia_release_io(struct pcmcia_device *p_dev)
 {
@@ -387,6 +421,14 @@ out:
 } /* pcmcia_release_io */
 
 
+/**
+ * pcmcia_release_window() - release reserved iomem for PCMCIA devices
+ * @p_dev: pcmcia device
+ * @res: iomem resource to release
+ *
+ * pcmcia_release_window() releases &struct resource *res which was
+ * previously reserved by calling pcmcia_request_window().
+ */
 int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res)
 {
        struct pcmcia_socket *s = p_dev->socket;
@@ -420,6 +462,8 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res)
                kfree(win->res);
                win->res = NULL;
        }
+       res->start = res->end = 0;
+       res->flags = IORESOURCE_MEM;
        p_dev->_win &= ~CLIENT_WIN_REQ(w);
        mutex_unlock(&s->ops_mutex);
 
@@ -428,23 +472,30 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res)
 EXPORT_SYMBOL(pcmcia_release_window);
 
 
-int pcmcia_request_configuration(struct pcmcia_device *p_dev,
-                                config_req_t *req)
+/**
+ * pcmcia_enable_device() - set up and activate a PCMCIA device
+ * @p_dev: the associated PCMCIA device
+ *
+ * pcmcia_enable_device() physically enables a PCMCIA device. It parses
+ * the flags passed to in @flags and stored in @p_dev->flags and sets up
+ * the Vpp voltage, enables the speaker line, I/O ports and store proper
+ * values to configuration registers.
+ */
+int pcmcia_enable_device(struct pcmcia_device *p_dev)
 {
        int i;
-       u_int base;
+       unsigned int base;
        struct pcmcia_socket *s = p_dev->socket;
        config_t *c;
        pccard_io_map iomap;
+       unsigned char status = 0;
+       unsigned char ext_status = 0;
+       unsigned char option = 0;
+       unsigned int flags = p_dev->config_flags;
 
        if (!(s->state & SOCKET_PRESENT))
                return -ENODEV;
 
-       if (req->IntType & INT_CARDBUS) {
-               dev_dbg(&p_dev->dev, "IntType may not be INT_CARDBUS\n");
-               return -EINVAL;
-       }
-
        mutex_lock(&s->ops_mutex);
        c = p_dev->function_config;
        if (c->state & CONFIG_LOCKED) {
@@ -454,7 +505,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
        }
 
        /* Do power control.  We don't allow changes in Vcc. */
-       s->socket.Vpp = req->Vpp;
+       s->socket.Vpp = p_dev->vpp;
        if (s->ops->set_socket(s, &s->socket)) {
                mutex_unlock(&s->ops_mutex);
                dev_printk(KERN_WARNING, &p_dev->dev,
@@ -463,64 +514,72 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
        }
 
        /* Pick memory or I/O card, DMA mode, interrupt */
-       c->IntType = req->IntType;
-       c->Attributes = req->Attributes;
-       if (req->IntType & INT_MEMORY_AND_IO)
+       if (p_dev->_io)
                s->socket.flags |= SS_IOCARD;
-       if (req->IntType & INT_ZOOMED_VIDEO)
-               s->socket.flags |= SS_ZVCARD | SS_IOCARD;
-       if (req->Attributes & CONF_ENABLE_DMA)
-               s->socket.flags |= SS_DMA_MODE;
-       if (req->Attributes & CONF_ENABLE_SPKR)
+       if (flags & CONF_ENABLE_SPKR) {
                s->socket.flags |= SS_SPKR_ENA;
-       if (req->Attributes & CONF_ENABLE_IRQ)
+               status = CCSR_AUDIO_ENA;
+               if (!(p_dev->config_regs & PRESENT_STATUS))
+                       dev_warn(&p_dev->dev, "speaker requested, but "
+                                             "PRESENT_STATUS not set!\n");
+       }
+       if (flags & CONF_ENABLE_IRQ)
                s->socket.io_irq = s->pcmcia_irq;
        else
                s->socket.io_irq = 0;
+       if (flags & CONF_ENABLE_ESR) {
+               p_dev->config_regs |= PRESENT_EXT_STATUS;
+               ext_status = ESR_REQ_ATTN_ENA;
+       }
        s->ops->set_socket(s, &s->socket);
        s->lock_count++;
 
+       dev_dbg(&p_dev->dev,
+               "enable_device: V %d, flags %x, base %x, regs %x, idx %x\n",
+               p_dev->vpp, flags, p_dev->config_base, p_dev->config_regs,
+               p_dev->config_index);
+
        /* Set up CIS configuration registers */
-       base = c->ConfigBase = req->ConfigBase;
-       c->CardValues = req->Present;
-       if (req->Present & PRESENT_COPY) {
-               c->Copy = req->Copy;
-               pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
-       }
-       if (req->Present & PRESENT_OPTION) {
+       base = p_dev->config_base;
+       if (p_dev->config_regs & PRESENT_COPY) {
+               u16 tmp = 0;
+               dev_dbg(&p_dev->dev, "clearing CISREG_SCR\n");
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &tmp);
+       }
+       if (p_dev->config_regs & PRESENT_PIN_REPLACE) {
+               u16 tmp = 0;
+               dev_dbg(&p_dev->dev, "clearing CISREG_PRR\n");
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &tmp);
+       }
+       if (p_dev->config_regs & PRESENT_OPTION) {
                if (s->functions == 1) {
-                       c->Option = req->ConfigIndex & COR_CONFIG_MASK;
+                       option = p_dev->config_index & COR_CONFIG_MASK;
                } else {
-                       c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
-                       c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;
-                       if (req->Present & PRESENT_IOBASE_0)
-                               c->Option |= COR_ADDR_DECODE;
+                       option = p_dev->config_index & COR_MFC_CONFIG_MASK;
+                       option |= COR_FUNC_ENA|COR_IREQ_ENA;
+                       if (p_dev->config_regs & PRESENT_IOBASE_0)
+                               option |= COR_ADDR_DECODE;
                }
-               if ((req->Attributes & CONF_ENABLE_IRQ) &&
-                       !(req->Attributes & CONF_ENABLE_PULSE_IRQ))
-                       c->Option |= COR_LEVEL_REQ;
-               pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
+               if ((flags & CONF_ENABLE_IRQ) &&
+                       !(flags & CONF_ENABLE_PULSE_IRQ))
+                       option |= COR_LEVEL_REQ;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &option);
                mdelay(40);
        }
-       if (req->Present & PRESENT_STATUS) {
-               c->Status = req->Status;
-               pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
-       }
-       if (req->Present & PRESENT_PIN_REPLACE) {
-               c->Pin = req->Pin;
-               pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
-       }
-       if (req->Present & PRESENT_EXT_STATUS) {
-               c->ExtStatus = req->ExtStatus;
-               pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
-       }
-       if (req->Present & PRESENT_IOBASE_0) {
+       if (p_dev->config_regs & PRESENT_STATUS)
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &status);
+
+       if (p_dev->config_regs & PRESENT_EXT_STATUS)
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1,
+                                       &ext_status);
+
+       if (p_dev->config_regs & PRESENT_IOBASE_0) {
                u8 b = c->io[0].start & 0xff;
                pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
                b = (c->io[0].start >> 8) & 0xff;
                pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
        }
-       if (req->Present & PRESENT_IOSIZE) {
+       if (p_dev->config_regs & PRESENT_IOSIZE) {
                u8 b = resource_size(&c->io[0]) + resource_size(&c->io[1]) - 1;
                pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
        }
@@ -551,14 +610,15 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
        p_dev->_locked = 1;
        mutex_unlock(&s->ops_mutex);
        return 0;
-} /* pcmcia_request_configuration */
-EXPORT_SYMBOL(pcmcia_request_configuration);
+} /* pcmcia_enable_device */
+EXPORT_SYMBOL(pcmcia_enable_device);
 
 
 /**
  * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices
+ * @p_dev: the associated PCMCIA device
  *
- * pcmcia_request_io() attepts to reserve the IO port ranges specified in
+ * pcmcia_request_io() attempts to reserve the IO port ranges specified in
  * &struct pcmcia_device @p_dev->resource[0] and @p_dev->resource[1]. The
  * "start" value is the requested start of the IO port resource; "end"
  * reflects the number of ports requested. The number of IO lines requested
@@ -622,11 +682,13 @@ EXPORT_SYMBOL(pcmcia_request_io);
 
 /**
  * pcmcia_request_irq() - attempt to request a IRQ for a PCMCIA device
+ * @p_dev: the associated PCMCIA device
+ * @handler: IRQ handler to register
  *
- * pcmcia_request_irq() is a wrapper around request_irq which will allow
+ * pcmcia_request_irq() is a wrapper around request_irq() which allows
  * the PCMCIA core to clean up the registration in pcmcia_disable_device().
  * Drivers are free to use request_irq() directly, but then they need to
- * call free_irq themselfves, too. Also, only IRQF_SHARED capable IRQ
+ * call free_irq() themselfves, too. Also, only %IRQF_SHARED capable IRQ
  * handlers are allowed.
  */
 int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev,
@@ -649,12 +711,14 @@ EXPORT_SYMBOL(pcmcia_request_irq);
 
 /**
  * pcmcia_request_exclusive_irq() - attempt to request an exclusive IRQ first
+ * @p_dev: the associated PCMCIA device
+ * @handler: IRQ handler to register
  *
- * pcmcia_request_exclusive_irq() is a wrapper around request_irq which
+ * pcmcia_request_exclusive_irq() is a wrapper around request_irq() which
  * attempts first to request an exclusive IRQ. If it fails, it also accepts
  * a shared IRQ, but prints out a warning. PCMCIA drivers should allow for
  * IRQ sharing and either use request_irq directly (then they need to call
- * free_irq themselves, too), or the pcmcia_request_irq() function.
+ * free_irq() themselves, too), or the pcmcia_request_irq() function.
  */
 int __must_check
 __pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev,
@@ -795,38 +859,47 @@ int pcmcia_setup_irq(struct pcmcia_device *p_dev)
 }
 
 
-/** pcmcia_request_window
+/**
+ * pcmcia_request_window() - attempt to reserve iomem for PCMCIA devices
+ * @p_dev: the associated PCMCIA device
+ * @res: &struct resource pointing to p_dev->resource[2..5]
+ * @speed: access speed
  *
- * Request_window() establishes a mapping between card memory space
- * and system memory space.
+ * pcmcia_request_window() attepts to reserve an iomem ranges specified in
+ * &struct resource @res pointing to one of the entries in
+ * &struct pcmcia_device @p_dev->resource[2..5]. The "start" value is the
+ * requested start of the IO mem resource; "end" reflects the size
+ * requested.
  */
-int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_handle_t *wh)
+int pcmcia_request_window(struct pcmcia_device *p_dev, struct resource *res,
+                       unsigned int speed)
 {
        struct pcmcia_socket *s = p_dev->socket;
        pccard_mem_map *win;
        u_long align;
-       struct resource *res;
        int w;
 
+       dev_dbg(&p_dev->dev, "request_window %pR %d\n", res, speed);
+
        if (!(s->state & SOCKET_PRESENT)) {
                dev_dbg(&p_dev->dev, "No card present\n");
                return -ENODEV;
        }
 
        /* Window size defaults to smallest available */
-       if (req->Size == 0)
-               req->Size = s->map_size;
-       align = (s->features & SS_CAP_MEM_ALIGN) ? req->Size : s->map_size;
-       if (req->Size & (s->map_size-1)) {
+       if (res->end == 0)
+               res->end = s->map_size;
+       align = (s->features & SS_CAP_MEM_ALIGN) ? res->end : s->map_size;
+       if (res->end & (s->map_size-1)) {
                dev_dbg(&p_dev->dev, "invalid map size\n");
                return -EINVAL;
        }
-       if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
-           (req->Base & (align-1))) {
+       if ((res->start && (s->features & SS_CAP_STATIC_MAP)) ||
+           (res->start & (align-1))) {
                dev_dbg(&p_dev->dev, "invalid base address\n");
                return -EINVAL;
        }
-       if (req->Base)
+       if (res->start)
                align = 0;
 
        /* Allocate system memory window */
@@ -843,7 +916,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
        win = &s->win[w];
 
        if (!(s->features & SS_CAP_STATIC_MAP)) {
-               win->res = pcmcia_find_mem_region(req->Base, req->Size, align,
+               win->res = pcmcia_find_mem_region(res->start, res->end, align,
                                                0, s);
                if (!win->res) {
                        dev_dbg(&p_dev->dev, "allocating mem region failed\n");
@@ -855,8 +928,8 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
 
        /* Configure the socket controller */
        win->map = w+1;
-       win->flags = req->Attributes;
-       win->speed = req->AccessSpeed;
+       win->flags = res->flags & WIN_FLAGS_MAP;
+       win->speed = speed;
        win->card_start = 0;
 
        if (s->ops->set_mem_map(s, win) != 0) {
@@ -868,17 +941,14 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
 
        /* Return window handle */
        if (s->features & SS_CAP_STATIC_MAP)
-               req->Base = win->static_start;
+               res->start = win->static_start;
        else
-               req->Base = win->res->start;
+               res->start = win->res->start;
 
        /* convert to new-style resources */
-       res = p_dev->resource[w + MAX_IO_WIN];
-       res->start = req->Base;
-       res->end = req->Base + req->Size - 1;
-       res->flags &= ~IORESOURCE_BITS;
-       res->flags |= (req->Attributes & WIN_FLAGS_MAP) | (win->map << 2);
-       res->flags |= IORESOURCE_MEM;
+       res->end += res->start - 1;
+       res->flags &= ~WIN_FLAGS_REQ;
+       res->flags |= (win->map << 2) | IORESOURCE_MEM;
        res->parent = win->res;
        if (win->res)
                request_resource(&iomem_resource, res);
@@ -886,15 +956,30 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
        dev_dbg(&p_dev->dev, "request_window results in %pR\n", res);
 
        mutex_unlock(&s->ops_mutex);
-       *wh = res;
 
        return 0;
 } /* pcmcia_request_window */
 EXPORT_SYMBOL(pcmcia_request_window);
 
+
+/**
+ * pcmcia_disable_device() - disable and clean up a PCMCIA device
+ * @p_dev: the associated PCMCIA device
+ *
+ * pcmcia_disable_device() is the driver-callable counterpart to
+ * pcmcia_enable_device(): If a PCMCIA device is no longer used,
+ * drivers are expected to clean up and disable the device by calling
+ * this function. Any I/O ranges (iomem and ioports) will be released,
+ * the Vpp voltage will be set to 0, and IRQs will no longer be
+ * generated -- at least if there is no other card function (of
+ * multifunction devices) being used.
+ */
 void pcmcia_disable_device(struct pcmcia_device *p_dev)
 {
        int i;
+
+       dev_dbg(&p_dev->dev, "disabling device\n");
+
        for (i = 0; i < MAX_WIN; i++) {
                struct resource *res = p_dev->resource[MAX_IO_WIN + i];
                if (res->flags & WIN_FLAGS_REQ)
index deef6656ab7b8e2015e382ed48b85e067c7503a5..8cbfa067171f8a1264dbc95b195928bd24833982 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/io.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 
 #include <asm/system.h>
 
index 8510c35d2952e5a264877632f22954c0de85c77f..523eb691c30b954e3a14d05f4b4e91fc3d27675c 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
 
index 4e80421fd9084d02433aea7f1c0561edcd2c6192..aa628ed0e9f48178ca3ac9b1fbba39a370877228 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/kernel.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
 
index 96f348b35fdea356daabb8b1836d438b163ca117..b187555d4388d394345f06997ffaa39361ed1de3 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/irq.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include "cs_internal.h"
 
index e09851480295dd22260cea8c7609acc9bf6d0b56..945857f8c2843d6d258769f54629562395fc088a 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 
 #include <asm/hardware/scoop.h>
index 6f1a86b43c606ac5e21b9353363da911cc53c314..689e3c02edb819e7c41190787d30d55e06de1131 100644 (file)
@@ -627,8 +627,6 @@ void soc_pcmcia_remove_one(struct soc_pcmcia_socket *skt)
 
        pcmcia_unregister_socket(&skt->socket);
 
-       flush_scheduled_work();
-
        skt->ops->hw_shutdown(skt);
 
        soc_common_pcmcia_config_skt(skt, &dead_socket);
@@ -720,8 +718,6 @@ int soc_pcmcia_add_one(struct soc_pcmcia_socket *skt)
        pcmcia_unregister_socket(&skt->socket);
 
  out_err_7:
-       flush_scheduled_work();
-
        skt->ops->hw_shutdown(skt);
  out_err_6:
        list_del(&skt->node);
index 3fba3a679128b10547714cd672461c0ba9e563b0..bbcd5385a221ae40d5dc0ffb0d21cbf1a09de602 100644 (file)
@@ -11,7 +11,6 @@
 
 /* include the world */
 #include <linux/cpufreq.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
 
index cb0d3ace18bd5b6113512e12a9c42c1142393468..71aeed93037c57485b330ee703efdc9b5bae4198 100644 (file)
@@ -27,7 +27,6 @@
 #include <asm/irq.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
index be0d841c7ebd9d9e2bb1407a4165ee92623105ec..310160bffe382c46ac6cda7a3c848bbcb2646d0a 100644 (file)
@@ -49,7 +49,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 #include "tcic.h"
 
index 9b3c15827e5c763208a82b212eb7ab6cc2e9919f..c6d36b3a6ce89b04fb84540be5a32203fb5405b2 100644 (file)
@@ -461,7 +461,7 @@ static int __devinit vrc4173_cardu_probe(struct pci_dev *dev,
 {
        vrc4173_socket_t *socket;
        unsigned long start, len, flags;
-       int slot, err;
+       int slot, err, ret;
 
        slot = vrc4173_cardu_slots++;
        socket = &cardu_sockets[slot];
@@ -474,43 +474,63 @@ static int __devinit vrc4173_cardu_probe(struct pci_dev *dev,
                return err;
 
        start = pci_resource_start(dev, 0);
-       if (start == 0)
-               return -ENODEV;
+       if (start == 0) {
+               ret = -ENODEV;
+               goto disable;
+       }
 
        len = pci_resource_len(dev, 0);
-       if (len == 0)
-               return -ENODEV;
+       if (len == 0) {
+               ret = -ENODEV;
+               goto disable;
+       }
 
-       if (((flags = pci_resource_flags(dev, 0)) & IORESOURCE_MEM) == 0)
-               return -EBUSY;
+       flags = pci_resource_flags(dev, 0);
+       if ((flags & IORESOURCE_MEM) == 0) {
+               ret = -EBUSY;
+               goto disable;
+       }
 
-       if ((err = pci_request_regions(dev, socket->name)) < 0)
-               return err;
+       err = pci_request_regions(dev, socket->name);
+       if (err < 0) {
+               ret = err;
+               goto disable;
+       }
 
        socket->base = ioremap(start, len);
-       if (socket->base == NULL)
-               return -ENODEV;
+       if (socket->base == NULL) {
+               ret = -ENODEV;
+               goto release;
+       }
 
        socket->dev = dev;
 
        socket->pcmcia_socket = pcmcia_register_socket(slot, &cardu_operations, 1);
        if (socket->pcmcia_socket == NULL) {
-               iounmap(socket->base);
-               socket->base = NULL;
-               return -ENOMEM;
+               ret =  -ENOMEM;
+               goto unmap;
        }
 
        if (request_irq(dev->irq, cardu_interrupt, IRQF_SHARED, socket->name, socket) < 0) {
-               pcmcia_unregister_socket(socket->pcmcia_socket);
-               socket->pcmcia_socket = NULL;
-               iounmap(socket->base);
-               socket->base = NULL;
-               return -EBUSY;
+               ret = -EBUSY;
+               goto unregister;
        }
 
        printk(KERN_INFO "%s at %#08lx, IRQ %d\n", socket->name, start, dev->irq);
 
        return 0;
+
+unregister:
+       pcmcia_unregister_socket(socket->pcmcia_socket);
+       socket->pcmcia_socket = NULL;
+unmap:
+       iounmap(socket->base);
+       socket->base = NULL;
+release:
+       pci_release_regions(dev);
+disable:
+       pci_disable_device(dev);
+       return ret;
 }
 
 static int __devinit vrc4173_cardu_setup(char *options)
index fa88c360c37a21f1875ba05e3fea58c3194d95ab..3b67a1b6a1972670c5c305c94b64c8677a720fb8 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/ss.h>
 #include <pcmcia/cistpl.h>
 
index 414d9a6f9a32c04f3908373d93c6e361b34b4ed2..408dbaa080a17863e3e926cc2d6beba42ae05c2d 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/slab.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 
 #include "yenta_socket.h"
 #include "i82365.h"
index f6d72e1f2a3897a324398f70767324bafb7056e0..5707a80b96b669d055ed26572051de637ccd7ae2 100644 (file)
@@ -468,7 +468,7 @@ sclp_sync_wait(void)
        cr0_sync &= 0xffff00a0;
        cr0_sync |= 0x00000200;
        __ctl_load(cr0_sync, 0, 0);
-       __raw_local_irq_stosm(0x01);
+       __arch_local_irq_stosm(0x01);
        /* Loop until driver state indicates finished request */
        while (sclp_running_state != sclp_running_state_idle) {
                /* Check for expired request timer */
index 61f49bdcc0c2815cc3b28f805c711cc3e4163ff8..e77dd02eccddcba823d2f7faec9f13a97237689d 100644 (file)
@@ -49,7 +49,6 @@
 #include <scsi/scsi_host.h>
 #include "aha152x.h"
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -86,8 +85,6 @@ static void aha152x_release_cs(struct pcmcia_device *link);
 static void aha152x_detach(struct pcmcia_device *p_dev);
 static int aha152x_config_cs(struct pcmcia_device *link);
 
-static struct pcmcia_device *dev_list;
-
 static int aha152x_probe(struct pcmcia_device *link)
 {
     scsi_info_t *info;
@@ -100,11 +97,8 @@ static int aha152x_probe(struct pcmcia_device *link)
     info->p_dev = link;
     link->priv = info;
 
-    link->resource[0]->end = 0x20;
-    link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-    link->conf.Attributes = CONF_ENABLE_IRQ;
-    link->conf.IntType = INT_MEMORY_AND_IO;
-    link->conf.Present = PRESENT_OPTION;
+    link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+    link->config_regs = PRESENT_OPTION;
 
     return aha152x_config_cs(link);
 } /* aha152x_attach */
@@ -123,25 +117,24 @@ static void aha152x_detach(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static int aha152x_config_check(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
-                               void *priv_data)
+static int aha152x_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
        p_dev->io_lines = 10;
+
        /* For New Media T&J, look for a SCSI window */
-       if (cfg->io.win[0].len >= 0x20)
-               p_dev->resource[0]->start = cfg->io.win[0].base;
-       else if ((cfg->io.nwin > 1) &&
-                (cfg->io.win[1].len >= 0x20))
-               p_dev->resource[0]->start = cfg->io.win[1].base;
-       if ((cfg->io.nwin > 0) &&
-           (p_dev->resource[0]->start < 0xffff)) {
-               if (!pcmcia_request_io(p_dev))
-                       return 0;
-       }
-       return -EINVAL;
+       if ((p_dev->resource[0]->end < 0x20) &&
+               (p_dev->resource[1]->end >= 0x20))
+               p_dev->resource[0]->start = p_dev->resource[1]->start;
+
+       if (p_dev->resource[0]->start >= 0xffff)
+               return -EINVAL;
+
+       p_dev->resource[1]->start = p_dev->resource[1]->end = 0;
+       p_dev->resource[0]->end = 0x20;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
+
+       return pcmcia_request_io(p_dev);
 }
 
 static int aha152x_config_cs(struct pcmcia_device *link)
@@ -160,7 +153,7 @@ static int aha152x_config_cs(struct pcmcia_device *link)
     if (!link->irq)
            goto failed;
 
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
     
@@ -221,9 +214,7 @@ MODULE_DEVICE_TABLE(pcmcia, aha152x_ids);
 
 static struct pcmcia_driver aha152x_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "aha152x_cs",
-       },
+       .name           = "aha152x_cs",
        .probe          = aha152x_probe,
        .remove         = aha152x_detach,
        .id_table       = aha152x_ids,
@@ -238,7 +229,6 @@ static int __init init_aha152x_cs(void)
 static void __exit exit_aha152x_cs(void)
 {
        pcmcia_unregister_driver(&aha152x_cs_driver);
-       BUG_ON(dev_list != NULL);
 }
 
 module_init(init_aha152x_cs);
index 13dbe5c48492e720c2691e24ad17930d3ee41f36..cd69c2670f810dd7ca7a738a5a75ef0ba4b28a52 100644 (file)
@@ -46,7 +46,6 @@
 #include <scsi/scsi_host.h>
 #include "fdomain.h"
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -83,11 +82,8 @@ static int fdomain_probe(struct pcmcia_device *link)
 
        info->p_dev = link;
        link->priv = info;
-       link->resource[0]->end = 0x10;
-       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-       link->conf.Present = PRESENT_OPTION;
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+       link->config_regs = PRESENT_OPTION;
 
        return fdomain_config(link);
 } /* fdomain_attach */
@@ -105,14 +101,12 @@ static void fdomain_detach(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static int fdomain_config_check(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
-                               void *priv_data)
+static int fdomain_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
        p_dev->io_lines = 10;
-       p_dev->resource[0]->start = cfg->io.win[0].base;
+       p_dev->resource[0]->end = 0x10;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
        return pcmcia_request_io(p_dev);
 }
 
@@ -132,7 +126,7 @@ static int fdomain_config(struct pcmcia_device *link)
 
     if (!link->irq)
            goto failed;
-    ret = pcmcia_request_configuration(link, &link->conf);
+    ret = pcmcia_enable_device(link);
     if (ret)
            goto failed;
 
@@ -194,9 +188,7 @@ MODULE_DEVICE_TABLE(pcmcia, fdomain_ids);
 
 static struct pcmcia_driver fdomain_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "fdomain_cs",
-       },
+       .name           = "fdomain_cs",
        .probe          = fdomain_probe,
        .remove         = fdomain_detach,
        .id_table       = fdomain_ids,
index dd9b40306f3d28f0d355a2ed72903b5fa148530f..9326c2c148803a6d1933faa0d183b6fad26be460 100644 (file)
@@ -47,7 +47,6 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_ioctl.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -1531,15 +1530,6 @@ static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt)
   PCMCIA functions
 **********************************************************************/
 
-/*======================================================================
-    nsp_cs_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-======================================================================*/
 static int nsp_cs_probe(struct pcmcia_device *link)
 {
        scsi_info_t  *info;
@@ -1557,14 +1547,6 @@ static int nsp_cs_probe(struct pcmcia_device *link)
 
        nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
 
-       /* The io structure describes IO port mapping */
-       link->resource[0]->end   = 0x10;
-       link->resource[0]->flags = IO_DATA_PATH_WIDTH_AUTO;
-
-       /* General socket configuration */
-       link->conf.Attributes    = CONF_ENABLE_IRQ;
-       link->conf.IntType       = INT_MEMORY_AND_IO;
-
        ret = nsp_cs_config(link);
 
        nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
@@ -1572,12 +1554,6 @@ static int nsp_cs_probe(struct pcmcia_device *link)
 } /* nsp_cs_attach */
 
 
-/*======================================================================
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.         If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-======================================================================*/
 static void nsp_cs_detach(struct pcmcia_device *link)
 {
        nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
@@ -1590,98 +1566,36 @@ static void nsp_cs_detach(struct pcmcia_device *link)
 } /* nsp_cs_detach */
 
 
-/*======================================================================
-    nsp_cs_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    ethernet device available to the system.
-======================================================================*/
-
-struct nsp_cs_configdata {
-       nsp_hw_data             *data;
-       win_req_t               req;
-};
-
-static int nsp_cs_config_check(struct pcmcia_device *p_dev,
-                              cistpl_cftable_entry_t *cfg,
-                              cistpl_cftable_entry_t *dflt,
-                              unsigned int vcc,
-                              void *priv_data)
+static int nsp_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       struct nsp_cs_configdata *cfg_mem = priv_data;
+       nsp_hw_data             *data = priv_data;
 
-       if (cfg->index == 0)
+       if (p_dev->config_index == 0)
                return -ENODEV;
 
-       /* Does this card need audio output? */
-       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
-               p_dev->conf.Status = CCSR_AUDIO_ENA;
-       }
-
-       /* Use power settings for Vcc and Vpp if present */
-       /*  Note that the CIS values need to be rescaled */
-       if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-               if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
-                       return -ENODEV;
-               else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-                       if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM]/10000)
-                               return -ENODEV;
-               }
-
-               if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
-                       p_dev->conf.Vpp =
-                               cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-               } else if (dflt->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
-                       p_dev->conf.Vpp =
-                               dflt->vpp1.param[CISTPL_POWER_VNOM] / 10000;
-               }
-
-               /* Do we need to allocate an interrupt? */
-               p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-               /* IO window settings */
-               p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-               if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-                       cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-                       p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-                       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-                       p_dev->resource[0]->flags |=
-                               pcmcia_io_cfg_data_width(io->flags);
-                       p_dev->resource[0]->start = io->win[0].base;
-                       p_dev->resource[0]->end = io->win[0].len;
-                       if (io->nwin > 1) {
-                               p_dev->resource[1]->flags =
-                                       p_dev->resource[0]->flags;
-                               p_dev->resource[1]->start = io->win[1].base;
-                               p_dev->resource[1]->end = io->win[1].len;
-                       }
-                       /* This reserves IO space but doesn't actually enable it */
-                       if (pcmcia_request_io(p_dev) != 0)
-                               goto next_entry;
-               }
-
-               if ((cfg->mem.nwin > 0) || (dflt->mem.nwin > 0)) {
-                       cistpl_mem_t    *mem =
-                               (cfg->mem.nwin) ? &cfg->mem : &dflt->mem;
-                       cfg_mem->req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
-                       cfg_mem->req.Attributes |= WIN_ENABLE;
-                       cfg_mem->req.Base = mem->win[0].host_addr;
-                       cfg_mem->req.Size = mem->win[0].len;
-                       if (cfg_mem->req.Size < 0x1000)
-                               cfg_mem->req.Size = 0x1000;
-                       cfg_mem->req.AccessSpeed = 0;
-                       if (pcmcia_request_window(p_dev, &cfg_mem->req, &p_dev->win) != 0)
-                               goto next_entry;
-                       if (pcmcia_map_mem_page(p_dev, p_dev->win,
-                                       mem->win[0].card_addr) != 0)
-                               goto next_entry;
-
-                       cfg_mem->data->MmioAddress = (unsigned long) ioremap_nocache(cfg_mem->req.Base, cfg_mem->req.Size);
-                       cfg_mem->data->MmioLength  = cfg_mem->req.Size;
-               }
-               /* If we got this far, we're cool! */
-               return 0;
+       /* This reserves IO space but doesn't actually enable it */
+       if (pcmcia_request_io(p_dev) != 0)
+               goto next_entry;
+
+       if (resource_size(p_dev->resource[2])) {
+               p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 |
+                                       WIN_MEMORY_TYPE_CM |
+                                       WIN_ENABLE);
+               if (p_dev->resource[2]->end < 0x1000)
+                       p_dev->resource[2]->end = 0x1000;
+               if (pcmcia_request_window(p_dev, p_dev->resource[2], 0) != 0)
+                       goto next_entry;
+               if (pcmcia_map_mem_page(p_dev, p_dev->resource[2],
+                                               p_dev->card_addr) != 0)
+                       goto next_entry;
+
+               data->MmioAddress = (unsigned long)
+                       ioremap_nocache(p_dev->resource[2]->start,
+                                       resource_size(p_dev->resource[2]));
+               data->MmioLength  = resource_size(p_dev->resource[2]);
        }
+       /* If we got this far, we're cool! */
+       return 0;
 
 next_entry:
        nsp_dbg(NSP_DEBUG_INIT, "next");
@@ -1693,25 +1607,23 @@ static int nsp_cs_config(struct pcmcia_device *link)
 {
        int               ret;
        scsi_info_t      *info   = link->priv;
-       struct nsp_cs_configdata *cfg_mem;
        struct Scsi_Host *host;
        nsp_hw_data      *data = &nsp_data_base;
 
        nsp_dbg(NSP_DEBUG_INIT, "in");
 
-       cfg_mem = kzalloc(sizeof(*cfg_mem), GFP_KERNEL);
-       if (!cfg_mem)
-               return -ENOMEM;
-       cfg_mem->data = data;
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC |
+               CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IOMEM |
+               CONF_AUTO_SET_IO;
 
-       ret = pcmcia_loop_config(link, nsp_cs_config_check, cfg_mem);
+       ret = pcmcia_loop_config(link, nsp_cs_config_check, data);
        if (ret)
                goto cs_failed;
 
        if (pcmcia_request_irq(link, nspintr))
                goto cs_failed;
 
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto cs_failed;
 
@@ -1754,41 +1666,16 @@ static int nsp_cs_config(struct pcmcia_device *link)
 
        info->host = host;
 
-       /* Finally, report what we've done */
-       printk(KERN_INFO "nsp_cs: index 0x%02x: ",
-              link->conf.ConfigIndex);
-       if (link->conf.Vpp) {
-               printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
-       }
-       if (link->conf.Attributes & CONF_ENABLE_IRQ) {
-               printk(", irq %d", link->irq);
-       }
-       if (link->resource[0])
-               printk(", io %pR", link->resource[0]);
-       if (link->resource[1])
-               printk(" & %pR", link->resource[1]);
-       if (link->win)
-               printk(", mem 0x%06lx-0x%06lx", cfg_mem->req.Base,
-                      cfg_mem->req.Base+cfg_mem->req.Size-1);
-       printk("\n");
-
-       kfree(cfg_mem);
        return 0;
 
  cs_failed:
        nsp_dbg(NSP_DEBUG_INIT, "config fail");
        nsp_cs_release(link);
-       kfree(cfg_mem);
 
        return -ENODEV;
 } /* nsp_cs_config */
 
 
-/*======================================================================
-    After a card is removed, nsp_cs_release() will unregister the net
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-======================================================================*/
 static void nsp_cs_release(struct pcmcia_device *link)
 {
        scsi_info_t *info = link->priv;
@@ -1807,7 +1694,7 @@ static void nsp_cs_release(struct pcmcia_device *link)
                scsi_remove_host(info->host);
        }
 
-       if (link->win) {
+       if (resource_size(link->resource[2])) {
                if (data != NULL) {
                        iounmap((void *)(data->MmioAddress));
                }
@@ -1877,9 +1764,7 @@ MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
 
 static struct pcmcia_driver nsp_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "nsp_cs",
-       },
+       .name           = "nsp_cs",
        .probe          = nsp_cs_probe,
        .remove         = nsp_cs_detach,
        .id_table       = nsp_cs_ids,
@@ -1889,14 +1774,11 @@ static struct pcmcia_driver nsp_driver = {
 
 static int __init nsp_cs_init(void)
 {
-       nsp_msg(KERN_INFO, "loading...");
-
        return pcmcia_register_driver(&nsp_driver);
 }
 
 static void __exit nsp_cs_exit(void)
 {
-       nsp_msg(KERN_INFO, "unloading...");
        pcmcia_unregister_driver(&nsp_driver);
 }
 
index eb775f1a523cef364b0666db7baa01609a9d833d..9c96ca889ec97ac03d9bdaec0329b3e967c2250e 100644 (file)
@@ -48,7 +48,6 @@
 #include <scsi/scsi_host.h>
 #include "../qlogicfas408.h"
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ciscode.h>
@@ -156,11 +155,8 @@ static int qlogic_probe(struct pcmcia_device *link)
                return -ENOMEM;
        info->p_dev = link;
        link->priv = info;
-       link->resource[0]->end = 16;
-       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-       link->conf.Present = PRESENT_OPTION;
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+       link->config_regs = PRESENT_OPTION;
 
        return qlogic_config(link);
 }                              /* qlogic_attach */
@@ -178,15 +174,11 @@ static void qlogic_detach(struct pcmcia_device *link)
 
 /*====================================================================*/
 
-static int qlogic_config_check(struct pcmcia_device *p_dev,
-                              cistpl_cftable_entry_t *cfg,
-                              cistpl_cftable_entry_t *dflt,
-                              unsigned int vcc,
-                              void *priv_data)
+static int qlogic_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
        p_dev->io_lines = 10;
-       p_dev->resource[0]->start = cfg->io.win[0].base;
-       p_dev->resource[0]->end = cfg->io.win[0].len;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
 
        if (p_dev->resource[0]->start == 0)
                return -ENODEV;
@@ -209,7 +201,7 @@ static int qlogic_config(struct pcmcia_device * link)
        if (!link->irq)
                goto failed;
 
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
@@ -264,7 +256,7 @@ static int qlogic_resume(struct pcmcia_device *link)
 {
        scsi_info_t *info = link->priv;
 
-       pcmcia_request_configuration(link, &link->conf);
+       pcmcia_enable_device(link);
        if ((info->manf_id == MANFID_MACNICA) ||
            (info->manf_id == MANFID_PIONEER) ||
            (info->manf_id == 0x0098)) {
@@ -302,9 +294,7 @@ MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
 
 static struct pcmcia_driver qlogic_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
        .name           = "qlogic_cs",
-       },
        .probe          = qlogic_probe,
        .remove         = qlogic_detach,
        .id_table       = qlogic_ids,
index 321e390c9120631f07b81434e2dfe853bf78f05c..0ae27cb5cd6f30334d6e2dd19bae9c187729733d 100644 (file)
@@ -71,7 +71,6 @@
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/ciscode.h>
@@ -684,15 +683,11 @@ static struct scsi_host_template sym53c500_driver_template = {
      .shost_attrs              = SYM53C500_shost_attrs
 };
 
-static int SYM53C500_config_check(struct pcmcia_device *p_dev,
-                                 cistpl_cftable_entry_t *cfg,
-                                 cistpl_cftable_entry_t *dflt,
-                                 unsigned int vcc,
-                                 void *priv_data)
+static int SYM53C500_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
        p_dev->io_lines = 10;
-       p_dev->resource[0]->start = cfg->io.win[0].base;
-       p_dev->resource[0]->end = cfg->io.win[0].len;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
 
        if (p_dev->resource[0]->start == 0)
                return -ENODEV;
@@ -721,7 +716,7 @@ SYM53C500_config(struct pcmcia_device *link)
        if (!link->irq)
                goto failed;
 
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
@@ -859,10 +854,7 @@ SYM53C500_probe(struct pcmcia_device *link)
                return -ENOMEM;
        info->p_dev = link;
        link->priv = info;
-       link->resource[0]->end = 16;
-       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 
        return SYM53C500_config(link);
 } /* SYM53C500_attach */
@@ -881,9 +873,7 @@ MODULE_DEVICE_TABLE(pcmcia, sym53c500_ids);
 
 static struct pcmcia_driver sym53c500_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "sym53c500_cs",
-       },
+       .name           = "sym53c500_cs",
        .probe          = SYM53C500_probe,
        .remove         = SYM53C500_detach,
        .id_table       = sym53c500_ids,
index ad0ed212db4ad094441f7a5656639e989c980738..348fba0a8976467fa9724411699b918a9cd8b0ea 100644 (file)
@@ -1046,13 +1046,13 @@ int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf,
 
        /* If the user actually wanted this page, we can skip the rest */
        if (page == 0)
-               return -EINVAL;
+               return 0;
 
        for (i = 0; i < min((int)buf[3], buf_len - 4); i++)
                if (buf[i + 4] == page)
                        goto found;
 
-       if (i < buf[3] && i > buf_len)
+       if (i < buf[3] && i >= buf_len - 4)
                /* ran off the end of the buffer, give us benefit of doubt */
                goto found;
        /* The device claims it doesn't support the requested page */
index 12900f7083b08819fdf31b3ab626d560bbfa01f8..3198c5335f0bcfae8f08680592164a0f1953281a 100644 (file)
@@ -458,6 +458,7 @@ config SERIAL_SAMSUNG_UARTS
        int
        depends on ARM && PLAT_SAMSUNG
        default 2 if ARCH_S3C2400
+       default 6 if ARCH_S5P6450
        default 4 if SERIAL_SAMSUNG_UARTS_4
        default 3
        help
@@ -526,12 +527,12 @@ config SERIAL_S3C24A0
          Serial port support for the Samsung S3C24A0 SoC
 
 config SERIAL_S3C6400
-       tristate "Samsung S3C6400/S3C6410/S5P6440/S5PC100 Serial port support"
-       depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5PC100)
+       tristate "Samsung S3C6400/S3C6410/S5P6440/S5P6450/S5PC100 Serial port support"
+       depends on SERIAL_SAMSUNG && (CPU_S3C6400 || CPU_S3C6410 || CPU_S5P6440 || CPU_S5P6450 || CPU_S5PC100)
        select SERIAL_SAMSUNG_UARTS_4
        default y
        help
-         Serial port support for the Samsung S3C6400, S3C6410, S5P6440
+         Serial port support for the Samsung S3C6400, S3C6410, S5P6440, S5P6450
          and S5PC100 SoCs
 
 config SERIAL_S5PV210
index 93de907b12088a54ab5809cf79c46ba5ec2757f2..ee43efc7bdcc5b1dcc406f69845f7bbcca0582e5 100644 (file)
@@ -2017,6 +2017,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
        struct ioc3_port *port;
        struct ioc3_port *ports[PORTS_PER_CARD];
        int phys_port;
+       int cnt;
 
        DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd));
 
@@ -2044,6 +2045,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
                if (!port) {
                        printk(KERN_WARNING
                               "IOC3 serial memory not available for port\n");
+                       ret = -ENOMEM;
                        goto out4;
                }
                spin_lock_init(&port->ip_lock);
@@ -2146,6 +2148,9 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd)
 
        /* error exits that give back resources */
 out4:
+       for (cnt = 0; cnt < phys_port; cnt++)
+               kfree(ports[cnt]);
+
        kfree(card_ptr);
        return ret;
 }
index b1156ba8ad1452c113fff20740a1d01596ab3cb2..7ac2bf5167cd8052f7f82b1361258f93643a03bd 100644 (file)
@@ -1101,7 +1101,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
        dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
 
        port->mapbase = res->start;
-       port->membase = S3C_VA_UART + res->start - (S3C_PA_UART & 0xfff00000);
+       port->membase = S3C_VA_UART + (res->start & 0xfffff);
        ret = platform_get_irq(platdev, 0);
        if (ret < 0)
                port->irq = 0;
index 7d475b2a79e8bb7fee0cd8f1f048fc61d1b7db3c..93760b2ea1727a908ca862dfc9922e4b13a3db63 100644 (file)
@@ -45,7 +45,6 @@
 #include <asm/io.h>
 #include <asm/system.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
@@ -183,10 +182,8 @@ static void quirk_config_socket(struct pcmcia_device *link)
 {
        struct serial_info *info = link->priv;
 
-       if (info->multi) {
-               link->conf.Present |= PRESENT_EXT_STATUS;
-               link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
-       }
+       if (info->multi)
+               link->config_flags |= CONF_ENABLE_ESR;
 }
 
 static const struct serial_quirk quirks[] = {
@@ -265,13 +262,6 @@ static const struct serial_quirk quirks[] = {
 static int serial_config(struct pcmcia_device * link);
 
 
-/*======================================================================
-
-    After a card is removed, serial_remove() will unregister
-    the serial device(s), and release the PCMCIA configuration.
-    
-======================================================================*/
-
 static void serial_remove(struct pcmcia_device *link)
 {
        struct serial_info *info = link->priv;
@@ -314,14 +304,6 @@ static int serial_resume(struct pcmcia_device *link)
        return 0;
 }
 
-/*======================================================================
-
-    serial_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-======================================================================*/
-
 static int serial_probe(struct pcmcia_device *link)
 {
        struct serial_info *info;
@@ -335,36 +317,19 @@ static int serial_probe(struct pcmcia_device *link)
        info->p_dev = link;
        link->priv = info;
 
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       if (do_sound) {
-               link->conf.Attributes |= CONF_ENABLE_SPKR;
-               link->conf.Status = CCSR_AUDIO_ENA;
-       }
-       link->conf.IntType = INT_MEMORY_AND_IO;
+       link->config_flags |= CONF_ENABLE_IRQ;
+       if (do_sound)
+               link->config_flags |= CONF_ENABLE_SPKR;
 
        return serial_config(link);
 }
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void serial_detach(struct pcmcia_device *link)
 {
        struct serial_info *info = link->priv;
 
        dev_dbg(&link->dev, "serial_detach\n");
 
-       /*
-        * Ensure any outstanding scheduled tasks are completed.
-        */
-       flush_scheduled_work();
-
        /*
         * Ensure that the ports have been released.
         */
@@ -430,47 +395,45 @@ static int pfc_config(struct pcmcia_device *p_dev)
        return -ENODEV;
 }
 
-static int simple_config_check(struct pcmcia_device *p_dev,
-                              cistpl_cftable_entry_t *cf,
-                              cistpl_cftable_entry_t *dflt,
-                              unsigned int vcc,
-                              void *priv_data)
+static int simple_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
        static const int size_table[2] = { 8, 16 };
        int *try = priv_data;
 
-       if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+       if (p_dev->resource[0]->start == 0)
+               return -ENODEV;
 
-       p_dev->io_lines = ((*try & 0x1) == 0) ?
-                       16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+       if ((*try & 0x1) == 0)
+               p_dev->io_lines = 16;
 
-       if ((cf->io.nwin > 0) && (cf->io.win[0].len == size_table[(*try >> 1)])
-           && (cf->io.win[0].base != 0)) {
-               p_dev->resource[0]->start = cf->io.win[0].base;
-               if (!pcmcia_request_io(p_dev))
-                       return 0;
-       }
-       return -EINVAL;
+       if (p_dev->resource[0]->end != size_table[(*try >> 1)])
+               return -ENODEV;
+
+       p_dev->resource[0]->end = 8;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+       return pcmcia_request_io(p_dev);
 }
 
 static int simple_config_check_notpicky(struct pcmcia_device *p_dev,
-                                       cistpl_cftable_entry_t *cf,
-                                       cistpl_cftable_entry_t *dflt,
-                                       unsigned int vcc,
                                        void *priv_data)
 {
        static const unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
        int j;
 
-       if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
-               for (j = 0; j < 5; j++) {
-                       p_dev->resource[0]->start = base[j];
-                       p_dev->io_lines = base[j] ? 16 : 3;
-                       if (!pcmcia_request_io(p_dev))
-                               return 0;
-               }
+       if (p_dev->io_lines > 3)
+               return -ENODEV;
+
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[0]->end = 8;
+
+       for (j = 0; j < 5; j++) {
+               p_dev->resource[0]->start = base[j];
+               p_dev->io_lines = base[j] ? 16 : 3;
+               if (!pcmcia_request_io(p_dev))
+                       return 0;
        }
        return -ENODEV;
 }
@@ -480,11 +443,9 @@ static int simple_config(struct pcmcia_device *link)
        struct serial_info *info = link->priv;
        int i = -ENODEV, try;
 
-       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-       link->resource[0]->end = 8;
-
        /* First pass: look for a config entry that looks normal.
         * Two tries: without IO aliases, then with aliases */
+       link->config_flags |= CONF_AUTO_SET_VPP | CONF_AUTO_SET_IO;
        for (try = 0; try < 4; try++)
                if (!pcmcia_loop_config(link, simple_config_check, &try))
                        goto found_port;
@@ -500,7 +461,7 @@ static int simple_config(struct pcmcia_device *link)
 
 found_port:
        if (info->multi && (info->manfid == MANFID_3COM))
-               link->conf.ConfigIndex &= ~(0x08);
+               link->config_index &= ~(0x08);
 
        /*
         * Apply any configuration quirks.
@@ -508,51 +469,50 @@ found_port:
        if (info->quirk && info->quirk->config)
                info->quirk->config(link);
 
-       i = pcmcia_request_configuration(link, &link->conf);
+       i = pcmcia_enable_device(link);
        if (i != 0)
                return -1;
        return setup_serial(link, info, link->resource[0]->start, link->irq);
 }
 
-static int multi_config_check(struct pcmcia_device *p_dev,
-                             cistpl_cftable_entry_t *cf,
-                             cistpl_cftable_entry_t *dflt,
-                             unsigned int vcc,
-                             void *priv_data)
+static int multi_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       int *base2 = priv_data;
+       int *multi = priv_data;
+
+       if (p_dev->resource[1]->end)
+               return -EINVAL;
 
        /* The quad port cards have bad CIS's, so just look for a
           window larger than 8 ports and assume it will be right */
-       if ((cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
-               p_dev->resource[0]->start = cf->io.win[0].base;
-               p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
-               if (!pcmcia_request_io(p_dev)) {
-                       *base2 = p_dev->resource[0]->start + 8;
-                       return 0;
-               }
-       }
-       return -ENODEV;
+       if (p_dev->resource[0]->end <= 8)
+               return -EINVAL;
+
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[0]->end = *multi * 8;
+
+       if (pcmcia_request_io(p_dev))
+               return -ENODEV;
+       return 0;
 }
 
 static int multi_config_check_notpicky(struct pcmcia_device *p_dev,
-                                      cistpl_cftable_entry_t *cf,
-                                      cistpl_cftable_entry_t *dflt,
-                                      unsigned int vcc,
                                       void *priv_data)
 {
        int *base2 = priv_data;
 
-       if (cf->io.nwin == 2) {
-               p_dev->resource[0]->start = cf->io.win[0].base;
-               p_dev->resource[1]->start = cf->io.win[1].base;
-               p_dev->io_lines = cf->io.flags & CISTPL_IO_LINES_MASK;
-               if (!pcmcia_request_io(p_dev)) {
-                       *base2 = p_dev->resource[1]->start;
-                       return 0;
-               }
-       }
-       return -ENODEV;
+       if (!p_dev->resource[0]->end || !p_dev->resource[1]->end)
+               return -ENODEV;
+
+       p_dev->resource[0]->end = p_dev->resource[1]->end = 8;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+
+       if (pcmcia_request_io(p_dev))
+               return -ENODEV;
+
+       *base2 = p_dev->resource[0]->start + 8;
+       return 0;
 }
 
 static int multi_config(struct pcmcia_device *link)
@@ -560,12 +520,12 @@ static int multi_config(struct pcmcia_device *link)
        struct serial_info *info = link->priv;
        int i, base2 = 0;
 
+       link->config_flags |= CONF_AUTO_SET_IO;
        /* First, look for a generic full-sized window */
-       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-       link->resource[0]->end = info->multi * 8;
-       if (pcmcia_loop_config(link, multi_config_check, &base2)) {
+       if (!pcmcia_loop_config(link, multi_config_check, &info->multi))
+               base2 = link->resource[0]->start + 8;
+       else {
                /* If that didn't work, look for two windows */
-               link->resource[0]->end = link->resource[1]->end = 8;
                info->multi = 2;
                if (pcmcia_loop_config(link, multi_config_check_notpicky,
                                       &base2)) {
@@ -584,7 +544,7 @@ static int multi_config(struct pcmcia_device *link)
        if (info->quirk && info->quirk->config)
                info->quirk->config(link);
 
-       i = pcmcia_request_configuration(link, &link->conf);
+       i = pcmcia_enable_device(link);
        if (i != 0)
                return -ENODEV;
 
@@ -596,11 +556,11 @@ static int multi_config(struct pcmcia_device *link)
                                info->prodid == PRODID_POSSIO_GCC)) {
                int err;
 
-               if (link->conf.ConfigIndex == 1 ||
-                   link->conf.ConfigIndex == 3) {
+               if (link->config_index == 1 ||
+                   link->config_index == 3) {
                        err = setup_serial(link, info, base2,
                                        link->irq);
-                       base2 = link->resource[0]->start;;
+                       base2 = link->resource[0]->start;
                } else {
                        err = setup_serial(link, info, link->resource[0]->start,
                                        link->irq);
@@ -624,33 +584,24 @@ static int multi_config(struct pcmcia_device *link)
        return 0;
 }
 
-static int serial_check_for_multi(struct pcmcia_device *p_dev,
-                                 cistpl_cftable_entry_t *cf,
-                                 cistpl_cftable_entry_t *dflt,
-                                 unsigned int vcc,
-                                 void *priv_data)
+static int serial_check_for_multi(struct pcmcia_device *p_dev,  void *priv_data)
 {
        struct serial_info *info = p_dev->priv;
 
-       if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
-               info->multi = cf->io.win[0].len >> 3;
+       if (!p_dev->resource[0]->end)
+               return -EINVAL;
+
+       if ((!p_dev->resource[1]->end) && (p_dev->resource[0]->end % 8 == 0))
+               info->multi = p_dev->resource[0]->end >> 3;
 
-       if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
-               (cf->io.win[1].len == 8))
+       if ((p_dev->resource[1]->end) && (p_dev->resource[0]->end == 8)
+               && (p_dev->resource[1]->end == 8))
                info->multi = 2;
 
        return 0; /* break */
 }
 
 
-/*======================================================================
-
-    serial_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    serial device available to the system.
-
-======================================================================*/
-
 static int serial_config(struct pcmcia_device * link)
 {
        struct serial_info *info = link->priv;
@@ -894,9 +845,7 @@ MODULE_FIRMWARE("cis/RS-COM-2P.cis");
 
 static struct pcmcia_driver serial_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "serial_cs",
-       },
+       .name           = "serial_cs",
        .probe          = serial_probe,
        .remove         = serial_detach,
        .id_table       = serial_ids,
index 91c2f4f3af10ecfc33a6a101a19b0f1762c79aea..4b9eec68fad6b84bca9c2f5f6f397f0e9be79c45 100644 (file)
@@ -143,10 +143,26 @@ config SPI_GPIO
          GPIO operations, you should be able to leverage that for better
          speed with a custom version of this driver; see the source code.
 
+config SPI_IMX_VER_IMX1
+       def_bool y if SOC_IMX1
+
+config SPI_IMX_VER_0_0
+       def_bool y if SOC_IMX21 || SOC_IMX27
+
+config SPI_IMX_VER_0_4
+       def_bool y if ARCH_MX31
+
+config SPI_IMX_VER_0_7
+       def_bool y if ARCH_MX25 || ARCH_MX35 || ARCH_MX51
+
+config SPI_IMX_VER_2_3
+       def_bool y if ARCH_MX51
+
 config SPI_IMX
        tristate "Freescale i.MX SPI controllers"
        depends on ARCH_MXC
        select SPI_BITBANG
+       default m if IMX_HAVE_PLATFORM_SPI_IMX
        help
          This enables using the Freescale i.MX SPI controllers in master
          mode.
@@ -182,12 +198,27 @@ config SPI_MPC512x_PSC
          This enables using the Freescale MPC5121 Programmable Serial
          Controller in SPI master mode.
 
-config SPI_MPC8xxx
-       tristate "Freescale MPC8xxx SPI controller"
+config SPI_FSL_LIB
+       tristate
+       depends on FSL_SOC
+
+config SPI_FSL_SPI
+       tristate "Freescale SPI controller"
        depends on FSL_SOC
+       select SPI_FSL_LIB
        help
-         This enables using the Freescale MPC8xxx SPI controllers in master
-         mode.
+         This enables using the Freescale SPI controllers in master mode.
+         MPC83xx platform uses the controller in cpu mode or CPM/QE mode.
+         MPC8569 uses the controller in QE mode, MPC8610 in cpu mode.
+
+config SPI_FSL_ESPI
+       tristate "Freescale eSPI controller"
+       depends on FSL_SOC
+       select SPI_FSL_LIB
+       help
+         This enables using the Freescale eSPI controllers in master mode.
+         From MPC8536, 85xx platform uses the controller, and all P10xx,
+         P20xx, P30xx,P40xx, P50xx uses this controller.
 
 config SPI_OMAP_UWIRE
        tristate "OMAP1 MicroWire"
@@ -298,6 +329,13 @@ config SPI_STMP3XXX
        help
          SPI driver for Freescale STMP37xx/378x SoC SSP interface
 
+config SPI_TOPCLIFF_PCH
+       tristate "Topcliff PCH SPI Controller"
+       depends on PCI
+       help
+         SPI driver for the Topcliff PCH (Platform Controller Hub) SPI bus
+         used in some x86 embedded processors.
+
 config SPI_TXX9
        tristate "Toshiba TXx9 SPI controller"
        depends on GENERIC_GPIO && CPU_TX49XX
index e9cbd18217a0559248698075141b6dd3f9d1277f..557aaadf56b2df40620a3b02073b44b78f09fb66 100644 (file)
@@ -2,9 +2,7 @@
 # Makefile for kernel SPI drivers.
 #
 
-ifeq ($(CONFIG_SPI_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG
 
 # small core, mostly translating board-specific
 # config declarations into driver model code
@@ -34,11 +32,14 @@ obj-$(CONFIG_SPI_PL022)                     += amba-pl022.o
 obj-$(CONFIG_SPI_MPC512x_PSC)          += mpc512x_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx_PSC)          += mpc52xx_psc_spi.o
 obj-$(CONFIG_SPI_MPC52xx)              += mpc52xx_spi.o
-obj-$(CONFIG_SPI_MPC8xxx)              += spi_mpc8xxx.o
+obj-$(CONFIG_SPI_FSL_LIB)              += spi_fsl_lib.o
+obj-$(CONFIG_SPI_FSL_ESPI)             += spi_fsl_espi.o
+obj-$(CONFIG_SPI_FSL_SPI)              += spi_fsl_spi.o
 obj-$(CONFIG_SPI_PPC4xx)               += spi_ppc4xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)         += spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)              += spi_s3c24xx_hw.o
 obj-$(CONFIG_SPI_S3C64XX)              += spi_s3c64xx.o
+obj-$(CONFIG_SPI_TOPCLIFF_PCH)         += spi_topcliff_pch.o
 obj-$(CONFIG_SPI_TXX9)                 += spi_txx9.o
 obj-$(CONFIG_SPI_XILINX)               += xilinx_spi.o
 obj-$(CONFIG_SPI_XILINX_OF)            += xilinx_spi_of.o
index 4c37c4e28647e68f62e1eaadcc92ac887857bf44..fb3d1b31772d223e24840ae2ac2c1e18b224ef76 100644 (file)
@@ -27,7 +27,6 @@
 /*
  * TODO:
  * - add timeout on polled transfers
- * - add generic DMA framework support
  */
 
 #include <linux/init.h>
@@ -45,6 +44,9 @@
 #include <linux/amba/pl022.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
 
 /*
  * This macro is used to define some register default values.
@@ -381,6 +383,14 @@ struct pl022 {
        enum ssp_reading                read;
        enum ssp_writing                write;
        u32                             exp_fifo_level;
+       /* DMA settings */
+#ifdef CONFIG_DMA_ENGINE
+       struct dma_chan                 *dma_rx_channel;
+       struct dma_chan                 *dma_tx_channel;
+       struct sg_table                 sgt_rx;
+       struct sg_table                 sgt_tx;
+       char                            *dummypage;
+#endif
 };
 
 /**
@@ -406,7 +416,7 @@ struct chip_data {
        u16 dmacr;
        u16 cpsr;
        u8 n_bytes;
-       u8 enable_dma:1;
+       bool enable_dma;
        enum ssp_reading read;
        enum ssp_writing write;
        void (*cs_control) (u32 command);
@@ -763,6 +773,371 @@ static void *next_transfer(struct pl022 *pl022)
        }
        return STATE_DONE;
 }
+
+/*
+ * This DMA functionality is only compiled in if we have
+ * access to the generic DMA devices/DMA engine.
+ */
+#ifdef CONFIG_DMA_ENGINE
+static void unmap_free_dma_scatter(struct pl022 *pl022)
+{
+       /* Unmap and free the SG tables */
+       dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+                    pl022->sgt_tx.nents, DMA_TO_DEVICE);
+       dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+                    pl022->sgt_rx.nents, DMA_FROM_DEVICE);
+       sg_free_table(&pl022->sgt_rx);
+       sg_free_table(&pl022->sgt_tx);
+}
+
+static void dma_callback(void *data)
+{
+       struct pl022 *pl022 = data;
+       struct spi_message *msg = pl022->cur_msg;
+
+       BUG_ON(!pl022->sgt_rx.sgl);
+
+#ifdef VERBOSE_DEBUG
+       /*
+        * Optionally dump out buffers to inspect contents, this is
+        * good if you want to convince yourself that the loopback
+        * read/write contents are the same, when adopting to a new
+        * DMA engine.
+        */
+       {
+               struct scatterlist *sg;
+               unsigned int i;
+
+               dma_sync_sg_for_cpu(&pl022->adev->dev,
+                                   pl022->sgt_rx.sgl,
+                                   pl022->sgt_rx.nents,
+                                   DMA_FROM_DEVICE);
+
+               for_each_sg(pl022->sgt_rx.sgl, sg, pl022->sgt_rx.nents, i) {
+                       dev_dbg(&pl022->adev->dev, "SPI RX SG ENTRY: %d", i);
+                       print_hex_dump(KERN_ERR, "SPI RX: ",
+                                      DUMP_PREFIX_OFFSET,
+                                      16,
+                                      1,
+                                      sg_virt(sg),
+                                      sg_dma_len(sg),
+                                      1);
+               }
+               for_each_sg(pl022->sgt_tx.sgl, sg, pl022->sgt_tx.nents, i) {
+                       dev_dbg(&pl022->adev->dev, "SPI TX SG ENTRY: %d", i);
+                       print_hex_dump(KERN_ERR, "SPI TX: ",
+                                      DUMP_PREFIX_OFFSET,
+                                      16,
+                                      1,
+                                      sg_virt(sg),
+                                      sg_dma_len(sg),
+                                      1);
+               }
+       }
+#endif
+
+       unmap_free_dma_scatter(pl022);
+
+       /* 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);
+}
+
+static void setup_dma_scatter(struct pl022 *pl022,
+                             void *buffer,
+                             unsigned int length,
+                             struct sg_table *sgtab)
+{
+       struct scatterlist *sg;
+       int bytesleft = length;
+       void *bufp = buffer;
+       int mapbytes;
+       int i;
+
+       if (buffer) {
+               for_each_sg(sgtab->sgl, sg, sgtab->nents, i) {
+                       /*
+                        * If there are less bytes left than what fits
+                        * in the current page (plus page alignment offset)
+                        * we just feed in this, else we stuff in as much
+                        * as we can.
+                        */
+                       if (bytesleft < (PAGE_SIZE - offset_in_page(bufp)))
+                               mapbytes = bytesleft;
+                       else
+                               mapbytes = PAGE_SIZE - offset_in_page(bufp);
+                       sg_set_page(sg, virt_to_page(bufp),
+                                   mapbytes, offset_in_page(bufp));
+                       bufp += mapbytes;
+                       bytesleft -= mapbytes;
+                       dev_dbg(&pl022->adev->dev,
+                               "set RX/TX target page @ %p, %d bytes, %d left\n",
+                               bufp, mapbytes, bytesleft);
+               }
+       } else {
+               /* Map the dummy buffer on every page */
+               for_each_sg(sgtab->sgl, sg, sgtab->nents, i) {
+                       if (bytesleft < PAGE_SIZE)
+                               mapbytes = bytesleft;
+                       else
+                               mapbytes = PAGE_SIZE;
+                       sg_set_page(sg, virt_to_page(pl022->dummypage),
+                                   mapbytes, 0);
+                       bytesleft -= mapbytes;
+                       dev_dbg(&pl022->adev->dev,
+                               "set RX/TX to dummy page %d bytes, %d left\n",
+                               mapbytes, bytesleft);
+
+               }
+       }
+       BUG_ON(bytesleft);
+}
+
+/**
+ * configure_dma - configures the channels for the next transfer
+ * @pl022: SSP driver's private data structure
+ */
+static int configure_dma(struct pl022 *pl022)
+{
+       struct dma_slave_config rx_conf = {
+               .src_addr = SSP_DR(pl022->phybase),
+               .direction = DMA_FROM_DEVICE,
+               .src_maxburst = pl022->vendor->fifodepth >> 1,
+       };
+       struct dma_slave_config tx_conf = {
+               .dst_addr = SSP_DR(pl022->phybase),
+               .direction = DMA_TO_DEVICE,
+               .dst_maxburst = pl022->vendor->fifodepth >> 1,
+       };
+       unsigned int pages;
+       int ret;
+       int sglen;
+       struct dma_chan *rxchan = pl022->dma_rx_channel;
+       struct dma_chan *txchan = pl022->dma_tx_channel;
+       struct dma_async_tx_descriptor *rxdesc;
+       struct dma_async_tx_descriptor *txdesc;
+       dma_cookie_t cookie;
+
+       /* Check that the channels are available */
+       if (!rxchan || !txchan)
+               return -ENODEV;
+
+       switch (pl022->read) {
+       case READING_NULL:
+               /* Use the same as for writing */
+               rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+               break;
+       case READING_U8:
+               rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+               break;
+       case READING_U16:
+               rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+               break;
+       case READING_U32:
+               rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+               break;
+       }
+
+       switch (pl022->write) {
+       case WRITING_NULL:
+               /* Use the same as for reading */
+               tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+               break;
+       case WRITING_U8:
+               tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+               break;
+       case WRITING_U16:
+               tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+               break;
+       case WRITING_U32:
+               tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;;
+               break;
+       }
+
+       /* SPI pecularity: we need to read and write the same width */
+       if (rx_conf.src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+               rx_conf.src_addr_width = tx_conf.dst_addr_width;
+       if (tx_conf.dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+               tx_conf.dst_addr_width = rx_conf.src_addr_width;
+       BUG_ON(rx_conf.src_addr_width != tx_conf.dst_addr_width);
+
+       rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
+                                      (unsigned long) &rx_conf);
+       txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
+                                      (unsigned long) &tx_conf);
+
+       /* Create sglists for the transfers */
+       pages = (pl022->cur_transfer->len >> PAGE_SHIFT) + 1;
+       dev_dbg(&pl022->adev->dev, "using %d pages for transfer\n", pages);
+
+       ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_KERNEL);
+       if (ret)
+               goto err_alloc_rx_sg;
+
+       ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_KERNEL);
+       if (ret)
+               goto err_alloc_tx_sg;
+
+       /* Fill in the scatterlists for the RX+TX buffers */
+       setup_dma_scatter(pl022, pl022->rx,
+                         pl022->cur_transfer->len, &pl022->sgt_rx);
+       setup_dma_scatter(pl022, pl022->tx,
+                         pl022->cur_transfer->len, &pl022->sgt_tx);
+
+       /* Map DMA buffers */
+       sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+                          pl022->sgt_rx.nents, DMA_FROM_DEVICE);
+       if (!sglen)
+               goto err_rx_sgmap;
+
+       sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+                          pl022->sgt_tx.nents, DMA_TO_DEVICE);
+       if (!sglen)
+               goto err_tx_sgmap;
+
+       /* Send both scatterlists */
+       rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
+                                     pl022->sgt_rx.sgl,
+                                     pl022->sgt_rx.nents,
+                                     DMA_FROM_DEVICE,
+                                     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!rxdesc)
+               goto err_rxdesc;
+
+       txdesc = txchan->device->device_prep_slave_sg(txchan,
+                                     pl022->sgt_tx.sgl,
+                                     pl022->sgt_tx.nents,
+                                     DMA_TO_DEVICE,
+                                     DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       if (!txdesc)
+               goto err_txdesc;
+
+       /* Put the callback on the RX transfer only, that should finish last */
+       rxdesc->callback = dma_callback;
+       rxdesc->callback_param = pl022;
+
+       /* Submit and fire RX and TX with TX last so we're ready to read! */
+       cookie = rxdesc->tx_submit(rxdesc);
+       if (dma_submit_error(cookie))
+               goto err_submit_rx;
+       cookie = txdesc->tx_submit(txdesc);
+       if (dma_submit_error(cookie))
+               goto err_submit_tx;
+       rxchan->device->device_issue_pending(rxchan);
+       txchan->device->device_issue_pending(txchan);
+
+       return 0;
+
+err_submit_tx:
+err_submit_rx:
+err_txdesc:
+       txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
+err_rxdesc:
+       rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
+       dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
+                    pl022->sgt_tx.nents, DMA_TO_DEVICE);
+err_tx_sgmap:
+       dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
+                    pl022->sgt_tx.nents, DMA_FROM_DEVICE);
+err_rx_sgmap:
+       sg_free_table(&pl022->sgt_tx);
+err_alloc_tx_sg:
+       sg_free_table(&pl022->sgt_rx);
+err_alloc_rx_sg:
+       return -ENOMEM;
+}
+
+static int __init pl022_dma_probe(struct pl022 *pl022)
+{
+       dma_cap_mask_t mask;
+
+       /* Try to acquire a generic DMA engine slave channel */
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       /*
+        * We need both RX and TX channels to do DMA, else do none
+        * of them.
+        */
+       pl022->dma_rx_channel = dma_request_channel(mask,
+                                           pl022->master_info->dma_filter,
+                                           pl022->master_info->dma_rx_param);
+       if (!pl022->dma_rx_channel) {
+               dev_err(&pl022->adev->dev, "no RX DMA channel!\n");
+               goto err_no_rxchan;
+       }
+
+       pl022->dma_tx_channel = dma_request_channel(mask,
+                                           pl022->master_info->dma_filter,
+                                           pl022->master_info->dma_tx_param);
+       if (!pl022->dma_tx_channel) {
+               dev_err(&pl022->adev->dev, "no TX DMA channel!\n");
+               goto err_no_txchan;
+       }
+
+       pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!pl022->dummypage) {
+               dev_err(&pl022->adev->dev, "no DMA dummypage!\n");
+               goto err_no_dummypage;
+       }
+
+       dev_info(&pl022->adev->dev, "setup for DMA on RX %s, TX %s\n",
+                dma_chan_name(pl022->dma_rx_channel),
+                dma_chan_name(pl022->dma_tx_channel));
+
+       return 0;
+
+err_no_dummypage:
+       dma_release_channel(pl022->dma_tx_channel);
+err_no_txchan:
+       dma_release_channel(pl022->dma_rx_channel);
+       pl022->dma_rx_channel = NULL;
+err_no_rxchan:
+       return -ENODEV;
+}
+
+static void terminate_dma(struct pl022 *pl022)
+{
+       struct dma_chan *rxchan = pl022->dma_rx_channel;
+       struct dma_chan *txchan = pl022->dma_tx_channel;
+
+       rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
+       txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
+       unmap_free_dma_scatter(pl022);
+}
+
+static void pl022_dma_remove(struct pl022 *pl022)
+{
+       if (pl022->busy)
+               terminate_dma(pl022);
+       if (pl022->dma_tx_channel)
+               dma_release_channel(pl022->dma_tx_channel);
+       if (pl022->dma_rx_channel)
+               dma_release_channel(pl022->dma_rx_channel);
+       kfree(pl022->dummypage);
+}
+
+#else
+static inline int configure_dma(struct pl022 *pl022)
+{
+       return -ENODEV;
+}
+
+static inline int pl022_dma_probe(struct pl022 *pl022)
+{
+       return 0;
+}
+
+static inline void pl022_dma_remove(struct pl022 *pl022)
+{
+}
+#endif
+
 /**
  * pl022_interrupt_handler - Interrupt handler for SSP controller
  *
@@ -794,14 +1169,17 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
        if (unlikely(!irq_status))
                return IRQ_NONE;
 
-       /* This handles the error code interrupts */
+       /*
+        * This handles the FIFO interrupts, the timeout
+        * interrupts are flatly ignored, they cannot be
+        * trusted.
+        */
        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");
+               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");
@@ -896,8 +1274,8 @@ static int set_up_next_transfer(struct pl022 *pl022,
 }
 
 /**
- * pump_transfers - Tasklet function which schedules next interrupt transfer
- * when running in interrupt transfer mode.
+ * pump_transfers - Tasklet function which schedules next transfer
+ * when running in interrupt or DMA transfer mode.
  * @data: SSP driver private data structure
  *
  */
@@ -954,65 +1332,23 @@ static void pump_transfers(unsigned long data)
        }
        /* 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);
+       if (pl022->cur_chip->enable_dma) {
+               if (configure_dma(pl022)) {
+                       dev_dbg(&pl022->adev->dev,
+                               "configuration of DMA failed, fall back to interrupt mode\n");
+                       goto err_config_dma;
+               }
                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;
+err_config_dma:
+       writew(ENABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
 }
 
-static void do_interrupt_transfer(void *data)
+static void do_interrupt_dma_transfer(struct pl022 *pl022)
 {
-       struct pl022 *pl022 = data;
+       u32 irqflags = ENABLE_ALL_INTERRUPTS;
 
        /* Enable target chip */
        pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
@@ -1023,15 +1359,26 @@ static void do_interrupt_transfer(void *data)
                giveback(pl022);
                return;
        }
+       /* If we're using DMA, set up DMA here */
+       if (pl022->cur_chip->enable_dma) {
+               /* Configure DMA transfer */
+               if (configure_dma(pl022)) {
+                       dev_dbg(&pl022->adev->dev,
+                               "configuration of DMA failed, fall back to interrupt mode\n");
+                       goto err_config_dma;
+               }
+               /* Disable interrupts in DMA mode, IRQ from DMA controller */
+               irqflags = DISABLE_ALL_INTERRUPTS;
+       }
+err_config_dma:
        /* 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));
+       writew(irqflags, SSP_IMSC(pl022->virtbase));
 }
 
-static void do_polling_transfer(void *data)
+static void do_polling_transfer(struct pl022 *pl022)
 {
-       struct pl022 *pl022 = data;
        struct spi_message *message = NULL;
        struct spi_transfer *transfer = NULL;
        struct spi_transfer *previous = NULL;
@@ -1101,7 +1448,7 @@ static void do_polling_transfer(void *data)
  *
  * 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()
+ * do_polling_transfer()/do_interrupt_dma_transfer()
  * based on the kind of the transfer
  *
  */
@@ -1150,10 +1497,8 @@ static void pump_messages(struct work_struct *work)
 
        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);
+               do_interrupt_dma_transfer(pl022);
 }
 
 
@@ -1248,100 +1593,56 @@ static int destroy_queue(struct pl022 *pl022)
 }
 
 static int verify_controller_parameters(struct pl022 *pl022,
-                                       struct pl022_config_chip *chip_info)
+                               struct pl022_config_chip const *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,
+               dev_err(&pl022->adev->dev,
                        "interface is configured incorrectly\n");
                return -EINVAL;
        }
        if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) &&
            (!pl022->vendor->unidir)) {
-               dev_err(chip_info->dev,
+               dev_err(&pl022->adev->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,
+               dev_err(&pl022->adev->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,
+               dev_err(&pl022->adev->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,
+               dev_err(&pl022->adev->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,
+               dev_err(&pl022->adev->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_FIRST_EDGE)
-                   && (chip_info->clk_phase != SSP_CLK_SECOND_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,
+                       dev_err(&pl022->adev->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,
+                       dev_err(&pl022->adev->dev,
                                "Wait State is configured incorrectly\n");
                        return -EINVAL;
                }
@@ -1350,24 +1651,20 @@ static int verify_controller_parameters(struct pl022 *pl022,
                        if ((chip_info->duplex !=
                             SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
                            && (chip_info->duplex !=
-                               SSP_MICROWIRE_CHANNEL_HALF_DUPLEX))
-                               dev_err(chip_info->dev,
+                               SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) {
+                               dev_err(&pl022->adev->dev,
                                        "Microwire duplex mode is configured incorrectly\n");
                                return -EINVAL;
+                       }
                } else {
                        if (chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
-                               dev_err(chip_info->dev,
+                               dev_err(&pl022->adev->dev,
                                        "Microwire half duplex mode requested,"
                                        " but this is only available in the"
                                        " ST version of PL022\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;
 }
 
@@ -1467,22 +1764,24 @@ static int calculate_effective_freq(struct pl022 *pl022,
        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
+
+/*
+ * A piece of default chip info unless the platform
+ * supplies it.
  */
-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;
-}
+static const struct pl022_config_chip pl022_default_chip_info = {
+       .com_mode = POLLING_TRANSFER,
+       .iface = SSP_INTERFACE_MOTOROLA_SPI,
+       .hierarchy = SSP_SLAVE,
+       .slave_tx_disable = DO_NOT_DRIVE_TX,
+       .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
+       .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
+       .ctrl_len = SSP_BITS_8,
+       .wait_state = SSP_MWIRE_WAIT_ZERO,
+       .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
+       .cs_control = null_cs_control,
+};
+
 
 /**
  * pl022_setup - setup function registered to SPI master framework
@@ -1496,23 +1795,15 @@ static int process_dma_info(struct pl022_config_chip *chip_info,
  * 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 pl022_config_chip const *chip_info;
        struct chip_data *chip;
+       struct ssp_clock_params clk_freq;
        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;
-       }
+       unsigned int bits = spi->bits_per_word;
+       u32 tmp;
 
        if (!spi->max_speed_hz)
                return -EINVAL;
@@ -1535,48 +1826,13 @@ static int pl022_setup(struct spi_device *spi)
        chip_info = spi->controller_data;
 
        if (chip_info == NULL) {
+               chip_info = &pl022_default_chip_info;
                /* 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_SECOND_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 {
+       } else
                dev_dbg(&spi->dev,
                        "using user supplied controller_data settings\n");
-       }
 
        /*
         * We can override with custom divisors, else we use the board
@@ -1586,29 +1842,48 @@ static int pl022_setup(struct spi_device *spi)
            && (0 == chip_info->clk_freq.scr)) {
                status = calculate_effective_freq(pl022,
                                                  spi->max_speed_hz,
-                                                 &chip_info->clk_freq);
+                                                 &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;
+               memcpy(&clk_freq, &chip_info->clk_freq, sizeof(clk_freq));
+               if ((clk_freq.cpsdvsr % 2) != 0)
+                       clk_freq.cpsdvsr =
+                               clk_freq.cpsdvsr - 1;
+       }
+       if ((clk_freq.cpsdvsr < CPSDVR_MIN)
+           || (clk_freq.cpsdvsr > CPSDVR_MAX)) {
+               dev_err(&spi->dev,
+                       "cpsdvsr is configured incorrectly\n");
+               goto err_config_params;
        }
+
+
        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");
+       if (!chip_info->cs_control) {
+               chip->cs_control = null_cs_control;
+               dev_warn(&spi->dev,
+                        "chip select function is NULL for this chip\n");
+       } else
+               chip->cs_control = chip_info->cs_control;
+
+       if (bits <= 3) {
+               /* PL022 doesn't support less than 4-bits */
+               status = -ENOTSUPP;
+               goto err_config_params;
+       } else if (bits <= 8) {
+               dev_dbg(&spi->dev, "4 <= 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) {
+       } else if (bits <= 16) {
                dev_dbg(&spi->dev, "9 <= n <= 16 bits per word\n");
                chip->n_bytes = 2;
                chip->read = READING_U16;
@@ -1625,6 +1900,7 @@ static int pl022_setup(struct spi_device *spi)
                        dev_err(&spi->dev,
                                "a standard pl022 can only handle "
                                "1 <= n <= 16 bit words\n");
+                       status = -ENOTSUPP;
                        goto err_config_params;
                }
        }
@@ -1636,9 +1912,8 @@ static int pl022_setup(struct spi_device *spi)
        chip->cpsr = 0;
        if ((chip_info->com_mode == DMA_TRANSFER)
            && ((pl022->master_info)->enable_dma)) {
-               chip->enable_dma = 1;
+               chip->enable_dma = true;
                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,
@@ -1646,7 +1921,7 @@ static int pl022_setup(struct spi_device *spi)
                SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
                               SSP_DMACR_MASK_TXDMAE, 1);
        } else {
-               chip->enable_dma = 0;
+               chip->enable_dma = false;
                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);
@@ -1654,10 +1929,12 @@ static int pl022_setup(struct spi_device *spi)
                               SSP_DMACR_MASK_TXDMAE, 1);
        }
 
-       chip->cpsr = chip_info->clk_freq.cpsdvsr;
+       chip->cpsr = clk_freq.cpsdvsr;
 
        /* Special setup for the ST micro extended control registers */
        if (pl022->vendor->extended_cr) {
+               u32 etx;
+
                if (pl022->vendor->pl023) {
                        /* These bits are only in the PL023 */
                        SSP_WRITE_BITS(chip->cr1, chip_info->clkdelay,
@@ -1673,29 +1950,51 @@ static int pl022_setup(struct spi_device *spi)
                        SSP_WRITE_BITS(chip->cr1, chip_info->wait_state,
                                       SSP_CR1_MASK_MWAIT_ST, 6);
                }
-               SSP_WRITE_BITS(chip->cr0, chip_info->data_size,
+               SSP_WRITE_BITS(chip->cr0, bits - 1,
                               SSP_CR0_MASK_DSS_ST, 0);
-               SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx,
-                              SSP_CR1_MASK_RENDN_ST, 4);
-               SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx,
-                              SSP_CR1_MASK_TENDN_ST, 5);
+
+               if (spi->mode & SPI_LSB_FIRST) {
+                       tmp = SSP_RX_LSB;
+                       etx = SSP_TX_LSB;
+               } else {
+                       tmp = SSP_RX_MSB;
+                       etx = SSP_TX_MSB;
+               }
+               SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_RENDN_ST, 4);
+               SSP_WRITE_BITS(chip->cr1, etx, SSP_CR1_MASK_TENDN_ST, 5);
                SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig,
                               SSP_CR1_MASK_RXIFLSEL_ST, 7);
                SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig,
                               SSP_CR1_MASK_TXIFLSEL_ST, 10);
        } else {
-               SSP_WRITE_BITS(chip->cr0, chip_info->data_size,
+               SSP_WRITE_BITS(chip->cr0, bits - 1,
                               SSP_CR0_MASK_DSS, 0);
                SSP_WRITE_BITS(chip->cr0, chip_info->iface,
                               SSP_CR0_MASK_FRF, 4);
        }
+
        /* Stuff that is common for all versions */
-       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);
+       if (spi->mode & SPI_CPOL)
+               tmp = SSP_CLK_POL_IDLE_HIGH;
+       else
+               tmp = SSP_CLK_POL_IDLE_LOW;
+       SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPO, 6);
+
+       if (spi->mode & SPI_CPHA)
+               tmp = SSP_CLK_SECOND_EDGE;
+       else
+               tmp = SSP_CLK_FIRST_EDGE;
+       SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPH, 7);
+
+       SSP_WRITE_BITS(chip->cr0, clk_freq.scr, SSP_CR0_MASK_SCR, 8);
        /* Loopback is available on all versions except PL023 */
-       if (!pl022->vendor->pl023)
-               SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0);
+       if (!pl022->vendor->pl023) {
+               if (spi->mode & SPI_LOOP)
+                       tmp = LOOPBACK_ENABLED;
+               else
+                       tmp = LOOPBACK_DISABLED;
+               SSP_WRITE_BITS(chip->cr1, tmp, 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);
@@ -1704,7 +2003,7 @@ static int pl022_setup(struct spi_device *spi)
        spi_set_ctldata(spi, chip);
        return status;
  err_config_params:
- err_first_setup:
+       spi_set_ctldata(spi, NULL);
        kfree(chip);
        return status;
 }
@@ -1766,12 +2065,21 @@ pl022_probe(struct amba_device *adev, struct amba_id *id)
        master->setup = pl022_setup;
        master->transfer = pl022_transfer;
 
+       /*
+        * Supports mode 0-3, loopback, and active low CS. Transfers are
+        * always MS bit first on the original pl022.
+        */
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
+       if (pl022->vendor->extended_cr)
+               master->mode_bits |= SPI_LSB_FIRST;
+
        dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num);
 
        status = amba_request_regions(adev, NULL);
        if (status)
                goto err_no_ioregion;
 
+       pl022->phybase = adev->res.start;
        pl022->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
        if (pl022->virtbase == NULL) {
                status = -ENOMEM;
@@ -1798,6 +2106,14 @@ pl022_probe(struct amba_device *adev, struct amba_id *id)
                dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status);
                goto err_no_irq;
        }
+
+       /* Get DMA channels */
+       if (platform_info->enable_dma) {
+               status = pl022_dma_probe(pl022);
+               if (status != 0)
+                       goto err_no_dma;
+       }
+
        /* Initialize and start queue */
        status = init_queue(pl022);
        if (status != 0) {
@@ -1826,6 +2142,8 @@ pl022_probe(struct amba_device *adev, struct amba_id *id)
  err_start_queue:
  err_init_queue:
        destroy_queue(pl022);
+       pl022_dma_remove(pl022);
+ err_no_dma:
        free_irq(adev->irq[0], pl022);
  err_no_irq:
        clk_put(pl022->clk);
@@ -1856,6 +2174,7 @@ pl022_remove(struct amba_device *adev)
                return status;
        }
        load_ssp_default_config(pl022);
+       pl022_dma_remove(pl022);
        free_irq(adev->irq[0], pl022);
        clk_disable(pl022->clk);
        clk_put(pl022->clk);
index c4e04428992de8302b3b3e2a512927bdb159643b..154529aacc037e332b005c418659089d80d5c9c5 100644 (file)
@@ -654,6 +654,8 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
        struct spi_transfer     *xfer;
        unsigned long           flags;
        struct device           *controller = spi->master->dev.parent;
+       u8                      bits;
+       struct atmel_spi_device *asd;
 
        as = spi_master_get_devdata(spi->master);
 
@@ -672,8 +674,18 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
                        return -EINVAL;
                }
 
+               if (xfer->bits_per_word) {
+                       asd = spi->controller_state;
+                       bits = (asd->csr >> 4) & 0xf;
+                       if (bits != xfer->bits_per_word - 8) {
+                               dev_dbg(&spi->dev, "you can't yet change "
+                                        "bits_per_word in transfers\n");
+                               return -ENOPROTOOPT;
+                       }
+               }
+
                /* FIXME implement these protocol options!! */
-               if (xfer->bits_per_word || xfer->speed_hz) {
+               if (xfer->speed_hz) {
                        dev_dbg(&spi->dev, "no protocol options yet\n");
                        return -ENOPROTOOPT;
                }
index b3a94ca0a75a01abc643f96fb3209b6a359d1dc6..2a651e61bfbff30f23e8e44dddfcb70ab8a05173 100644 (file)
@@ -296,6 +296,19 @@ static int omap2_mcspi_enable_clocks(struct omap2_mcspi *mcspi)
        return 0;
 }
 
+static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
+{
+       unsigned long timeout;
+
+       timeout = jiffies + msecs_to_jiffies(1000);
+       while (!(__raw_readl(reg) & bit)) {
+               if (time_after(jiffies, timeout))
+                       return -1;
+               cpu_relax();
+       }
+       return 0;
+}
+
 static unsigned
 omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
 {
@@ -309,11 +322,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        u32                     l;
        u8                      * rx;
        const u8                * tx;
+       void __iomem            *chstat_reg;
 
        mcspi = spi_master_get_devdata(spi->master);
        mcspi_dma = &mcspi->dma_channels[spi->chip_select];
        l = mcspi_cached_chconf0(spi);
 
+       chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0;
+
        count = xfer->len;
        c = count;
        word_len = cs->word_len;
@@ -382,6 +398,16 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        if (tx != NULL) {
                wait_for_completion(&mcspi_dma->dma_tx_completion);
                dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE);
+
+               /* for TX_ONLY mode, be sure all words have shifted out */
+               if (rx == NULL) {
+                       if (mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_TXS) < 0)
+                               dev_err(&spi->dev, "TXS timed out\n");
+                       else if (mcspi_wait_for_reg_bit(chstat_reg,
+                                               OMAP2_MCSPI_CHSTAT_EOT) < 0)
+                               dev_err(&spi->dev, "EOT timed out\n");
+               }
        }
 
        if (rx != NULL) {
@@ -435,19 +461,6 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
        return count;
 }
 
-static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit)
-{
-       unsigned long timeout;
-
-       timeout = jiffies + msecs_to_jiffies(1000);
-       while (!(__raw_readl(reg) & bit)) {
-               if (time_after(jiffies, timeout))
-                       return -1;
-               cpu_relax();
-       }
-       return 0;
-}
-
 static unsigned
 omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
 {
@@ -489,10 +502,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                        dev_err(&spi->dev, "TXS timed out\n");
                                        goto out;
                                }
-#ifdef VERBOSE
-                               dev_dbg(&spi->dev, "write-%d %02x\n",
+                               dev_vdbg(&spi->dev, "write-%d %02x\n",
                                                word_len, *tx);
-#endif
                                __raw_writel(*tx++, tx_reg);
                        }
                        if (rx != NULL) {
@@ -506,10 +517,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
                                        omap2_mcspi_set_enable(spi, 0);
                                        *rx++ = __raw_readl(rx_reg);
-#ifdef VERBOSE
-                                       dev_dbg(&spi->dev, "read-%d %02x\n",
+                                       dev_vdbg(&spi->dev, "read-%d %02x\n",
                                                    word_len, *(rx - 1));
-#endif
                                        if (mcspi_wait_for_reg_bit(chstat_reg,
                                                OMAP2_MCSPI_CHSTAT_RXS) < 0) {
                                                dev_err(&spi->dev,
@@ -522,10 +531,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                }
 
                                *rx++ = __raw_readl(rx_reg);
-#ifdef VERBOSE
-                               dev_dbg(&spi->dev, "read-%d %02x\n",
+                               dev_vdbg(&spi->dev, "read-%d %02x\n",
                                                word_len, *(rx - 1));
-#endif
                        }
                } while (c);
        } else if (word_len <= 16) {
@@ -542,10 +549,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                        dev_err(&spi->dev, "TXS timed out\n");
                                        goto out;
                                }
-#ifdef VERBOSE
-                               dev_dbg(&spi->dev, "write-%d %04x\n",
+                               dev_vdbg(&spi->dev, "write-%d %04x\n",
                                                word_len, *tx);
-#endif
                                __raw_writel(*tx++, tx_reg);
                        }
                        if (rx != NULL) {
@@ -559,10 +564,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
                                        omap2_mcspi_set_enable(spi, 0);
                                        *rx++ = __raw_readl(rx_reg);
-#ifdef VERBOSE
-                                       dev_dbg(&spi->dev, "read-%d %04x\n",
+                                       dev_vdbg(&spi->dev, "read-%d %04x\n",
                                                    word_len, *(rx - 1));
-#endif
                                        if (mcspi_wait_for_reg_bit(chstat_reg,
                                                OMAP2_MCSPI_CHSTAT_RXS) < 0) {
                                                dev_err(&spi->dev,
@@ -575,10 +578,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                }
 
                                *rx++ = __raw_readl(rx_reg);
-#ifdef VERBOSE
-                               dev_dbg(&spi->dev, "read-%d %04x\n",
+                               dev_vdbg(&spi->dev, "read-%d %04x\n",
                                                word_len, *(rx - 1));
-#endif
                        }
                } while (c);
        } else if (word_len <= 32) {
@@ -595,10 +596,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                        dev_err(&spi->dev, "TXS timed out\n");
                                        goto out;
                                }
-#ifdef VERBOSE
-                               dev_dbg(&spi->dev, "write-%d %08x\n",
+                               dev_vdbg(&spi->dev, "write-%d %08x\n",
                                                word_len, *tx);
-#endif
                                __raw_writel(*tx++, tx_reg);
                        }
                        if (rx != NULL) {
@@ -612,10 +611,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                    (l & OMAP2_MCSPI_CHCONF_TURBO)) {
                                        omap2_mcspi_set_enable(spi, 0);
                                        *rx++ = __raw_readl(rx_reg);
-#ifdef VERBOSE
-                                       dev_dbg(&spi->dev, "read-%d %08x\n",
+                                       dev_vdbg(&spi->dev, "read-%d %08x\n",
                                                    word_len, *(rx - 1));
-#endif
                                        if (mcspi_wait_for_reg_bit(chstat_reg,
                                                OMAP2_MCSPI_CHSTAT_RXS) < 0) {
                                                dev_err(&spi->dev,
@@ -628,10 +625,8 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                                }
 
                                *rx++ = __raw_readl(rx_reg);
-#ifdef VERBOSE
-                               dev_dbg(&spi->dev, "read-%d %08x\n",
+                               dev_vdbg(&spi->dev, "read-%d %08x\n",
                                                word_len, *(rx - 1));
-#endif
                        }
                } while (c);
        }
@@ -644,6 +639,12 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
                } else if (mcspi_wait_for_reg_bit(chstat_reg,
                                OMAP2_MCSPI_CHSTAT_EOT) < 0)
                        dev_err(&spi->dev, "EOT timed out\n");
+
+               /* disable chan to purge rx datas received in TX_ONLY transfer,
+                * otherwise these rx datas will affect the direct following
+                * RX_ONLY transfer.
+                */
+               omap2_mcspi_set_enable(spi, 0);
        }
 out:
        omap2_mcspi_set_enable(spi, 1);
index 3aea50da7b29f22211d7dc93410208b7dc876e87..0b677dc041ad1a6b07cf92c9a3e9444275cec4e8 100644 (file)
@@ -404,7 +404,7 @@ static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m)
                        goto msg_rejected;
                }
 
-               if ((t != NULL) && t->bits_per_word)
+               if (t->bits_per_word)
                        bits_per_word = t->bits_per_word;
 
                if ((bits_per_word != 8) && (bits_per_word != 16)) {
@@ -415,7 +415,7 @@ static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m)
                        goto msg_rejected;
                }
                /*make sure buffer length is even when working in 16 bit mode*/
-               if ((t != NULL) && (t->bits_per_word == 16) && (t->len & 1)) {
+               if ((t->bits_per_word == 16) && (t->len & 1)) {
                        dev_err(&spi->dev,
                                "message rejected : "
                                "odd data length (%d) while in 16 bit mode\n",
index 10a6dc3d37ac835568083698b1165ea027893739..ab483a0ec6d05b7738ab85aed075ee0a293598bf 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Blackfin On-Chip SPI Driver
  *
- * Copyright 2004-2007 Analog Devices Inc.
+ * Copyright 2004-2010 Analog Devices Inc.
  *
  * Enter bugs at http://blackfin.uclinux.org/
  *
@@ -41,13 +41,16 @@ MODULE_LICENSE("GPL");
 #define RUNNING_STATE  ((void *)1)
 #define DONE_STATE     ((void *)2)
 #define ERROR_STATE    ((void *)-1)
-#define QUEUE_RUNNING  0
-#define QUEUE_STOPPED  1
 
-/* Value to send if no TX value is supplied */
-#define SPI_IDLE_TXVAL 0x0000
+struct bfin_spi_master_data;
 
-struct driver_data {
+struct bfin_spi_transfer_ops {
+       void (*write) (struct bfin_spi_master_data *);
+       void (*read) (struct bfin_spi_master_data *);
+       void (*duplex) (struct bfin_spi_master_data *);
+};
+
+struct bfin_spi_master_data {
        /* Driver model hookup */
        struct platform_device *pdev;
 
@@ -69,7 +72,7 @@ struct driver_data {
        spinlock_t lock;
        struct list_head queue;
        int busy;
-       int run;
+       bool running;
 
        /* Message Transfer pump */
        struct tasklet_struct pump_transfers;
@@ -77,7 +80,7 @@ struct driver_data {
        /* Current message transfer state info */
        struct spi_message *cur_msg;
        struct spi_transfer *cur_transfer;
-       struct chip_data *cur_chip;
+       struct bfin_spi_slave_data *cur_chip;
        size_t len_in_bytes;
        size_t len;
        void *tx;
@@ -92,38 +95,37 @@ struct driver_data {
        dma_addr_t rx_dma;
        dma_addr_t tx_dma;
 
+       int irq_requested;
+       int spi_irq;
+
        size_t rx_map_len;
        size_t tx_map_len;
        u8 n_bytes;
+       u16 ctrl_reg;
+       u16 flag_reg;
+
        int cs_change;
-       void (*write) (struct driver_data *);
-       void (*read) (struct driver_data *);
-       void (*duplex) (struct driver_data *);
+       const struct bfin_spi_transfer_ops *ops;
 };
 
-struct chip_data {
+struct bfin_spi_slave_data {
        u16 ctl_reg;
        u16 baud;
        u16 flag;
 
        u8 chip_select_num;
-       u8 n_bytes;
-       u8 width;               /* 0 or 1 */
        u8 enable_dma;
-       u8 bits_per_word;       /* 8 or 16 */
-       u8 cs_change_per_word;
        u16 cs_chg_udelay;      /* Some devices require > 255usec delay */
        u32 cs_gpio;
        u16 idle_tx_val;
-       void (*write) (struct driver_data *);
-       void (*read) (struct driver_data *);
-       void (*duplex) (struct driver_data *);
+       u8 pio_interrupt;       /* use spi data irq */
+       const struct bfin_spi_transfer_ops *ops;
 };
 
 #define DEFINE_SPI_REG(reg, off) \
-static inline u16 read_##reg(struct driver_data *drv_data) \
+static inline u16 read_##reg(struct bfin_spi_master_data *drv_data) \
        { return bfin_read16(drv_data->regs_base + off); } \
-static inline void write_##reg(struct driver_data *drv_data, u16 v) \
+static inline void write_##reg(struct bfin_spi_master_data *drv_data, u16 v) \
        { bfin_write16(drv_data->regs_base + off, v); }
 
 DEFINE_SPI_REG(CTRL, 0x00)
@@ -134,7 +136,7 @@ DEFINE_SPI_REG(RDBR, 0x10)
 DEFINE_SPI_REG(BAUD, 0x14)
 DEFINE_SPI_REG(SHAW, 0x18)
 
-static void bfin_spi_enable(struct driver_data *drv_data)
+static void bfin_spi_enable(struct bfin_spi_master_data *drv_data)
 {
        u16 cr;
 
@@ -142,7 +144,7 @@ static void bfin_spi_enable(struct driver_data *drv_data)
        write_CTRL(drv_data, (cr | BIT_CTL_ENABLE));
 }
 
-static void bfin_spi_disable(struct driver_data *drv_data)
+static void bfin_spi_disable(struct bfin_spi_master_data *drv_data)
 {
        u16 cr;
 
@@ -165,7 +167,7 @@ static u16 hz_to_spi_baud(u32 speed_hz)
        return spi_baud;
 }
 
-static int bfin_spi_flush(struct driver_data *drv_data)
+static int bfin_spi_flush(struct bfin_spi_master_data *drv_data)
 {
        unsigned long limit = loops_per_jiffy << 1;
 
@@ -179,13 +181,12 @@ static int bfin_spi_flush(struct driver_data *drv_data)
 }
 
 /* Chip select operation functions for cs_change flag */
-static void bfin_spi_cs_active(struct driver_data *drv_data, struct chip_data *chip)
+static void bfin_spi_cs_active(struct bfin_spi_master_data *drv_data, struct bfin_spi_slave_data *chip)
 {
-       if (likely(chip->chip_select_num)) {
+       if (likely(chip->chip_select_num < MAX_CTRL_CS)) {
                u16 flag = read_FLAG(drv_data);
 
-               flag |= chip->flag;
-               flag &= ~(chip->flag << 8);
+               flag &= ~chip->flag;
 
                write_FLAG(drv_data, flag);
        } else {
@@ -193,13 +194,13 @@ static void bfin_spi_cs_active(struct driver_data *drv_data, struct chip_data *c
        }
 }
 
-static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data *chip)
+static void bfin_spi_cs_deactive(struct bfin_spi_master_data *drv_data,
+                                 struct bfin_spi_slave_data *chip)
 {
-       if (likely(chip->chip_select_num)) {
+       if (likely(chip->chip_select_num < MAX_CTRL_CS)) {
                u16 flag = read_FLAG(drv_data);
 
-               flag &= ~chip->flag;
-               flag |= (chip->flag << 8);
+               flag |= chip->flag;
 
                write_FLAG(drv_data, flag);
        } else {
@@ -211,16 +212,43 @@ static void bfin_spi_cs_deactive(struct driver_data *drv_data, struct chip_data
                udelay(chip->cs_chg_udelay);
 }
 
+/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */
+static inline void bfin_spi_cs_enable(struct bfin_spi_master_data *drv_data,
+                                      struct bfin_spi_slave_data *chip)
+{
+       if (chip->chip_select_num < MAX_CTRL_CS) {
+               u16 flag = read_FLAG(drv_data);
+
+               flag |= (chip->flag >> 8);
+
+               write_FLAG(drv_data, flag);
+       }
+}
+
+static inline void bfin_spi_cs_disable(struct bfin_spi_master_data *drv_data,
+                                       struct bfin_spi_slave_data *chip)
+{
+       if (chip->chip_select_num < MAX_CTRL_CS) {
+               u16 flag = read_FLAG(drv_data);
+
+               flag &= ~(chip->flag >> 8);
+
+               write_FLAG(drv_data, flag);
+       }
+}
+
 /* stop controller and re-config current chip*/
-static void bfin_spi_restore_state(struct driver_data *drv_data)
+static void bfin_spi_restore_state(struct bfin_spi_master_data *drv_data)
 {
-       struct chip_data *chip = drv_data->cur_chip;
+       struct bfin_spi_slave_data *chip = drv_data->cur_chip;
 
        /* Clear status and disable clock */
        write_STAT(drv_data, BIT_STAT_CLR);
        bfin_spi_disable(drv_data);
        dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");
 
+       SSYNC();
+
        /* Load the registers */
        write_CTRL(drv_data, chip->ctl_reg);
        write_BAUD(drv_data, chip->baud);
@@ -230,49 +258,12 @@ static void bfin_spi_restore_state(struct driver_data *drv_data)
 }
 
 /* used to kick off transfer in rx mode and read unwanted RX data */
-static inline void bfin_spi_dummy_read(struct driver_data *drv_data)
+static inline void bfin_spi_dummy_read(struct bfin_spi_master_data *drv_data)
 {
        (void) read_RDBR(drv_data);
 }
 
-static void bfin_spi_null_writer(struct driver_data *drv_data)
-{
-       u8 n_bytes = drv_data->n_bytes;
-       u16 tx_val = drv_data->cur_chip->idle_tx_val;
-
-       /* clear RXS (we check for RXS inside the loop) */
-       bfin_spi_dummy_read(drv_data);
-
-       while (drv_data->tx < drv_data->tx_end) {
-               write_TDBR(drv_data, tx_val);
-               drv_data->tx += n_bytes;
-               /* wait until transfer finished.
-                  checking SPIF or TXS may not guarantee transfer completion */
-               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-                       cpu_relax();
-               /* discard RX data and clear RXS */
-               bfin_spi_dummy_read(drv_data);
-       }
-}
-
-static void bfin_spi_null_reader(struct driver_data *drv_data)
-{
-       u8 n_bytes = drv_data->n_bytes;
-       u16 tx_val = drv_data->cur_chip->idle_tx_val;
-
-       /* discard old RX data and clear RXS */
-       bfin_spi_dummy_read(drv_data);
-
-       while (drv_data->rx < drv_data->rx_end) {
-               write_TDBR(drv_data, tx_val);
-               drv_data->rx += n_bytes;
-               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-                       cpu_relax();
-               bfin_spi_dummy_read(drv_data);
-       }
-}
-
-static void bfin_spi_u8_writer(struct driver_data *drv_data)
+static void bfin_spi_u8_writer(struct bfin_spi_master_data *drv_data)
 {
        /* clear RXS (we check for RXS inside the loop) */
        bfin_spi_dummy_read(drv_data);
@@ -288,25 +279,7 @@ static void bfin_spi_u8_writer(struct driver_data *drv_data)
        }
 }
 
-static void bfin_spi_u8_cs_chg_writer(struct driver_data *drv_data)
-{
-       struct chip_data *chip = drv_data->cur_chip;
-
-       /* clear RXS (we check for RXS inside the loop) */
-       bfin_spi_dummy_read(drv_data);
-
-       while (drv_data->tx < drv_data->tx_end) {
-               bfin_spi_cs_active(drv_data, chip);
-               write_TDBR(drv_data, (*(u8 *) (drv_data->tx++)));
-               /* make sure transfer finished before deactiving CS */
-               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-                       cpu_relax();
-               bfin_spi_dummy_read(drv_data);
-               bfin_spi_cs_deactive(drv_data, chip);
-       }
-}
-
-static void bfin_spi_u8_reader(struct driver_data *drv_data)
+static void bfin_spi_u8_reader(struct bfin_spi_master_data *drv_data)
 {
        u16 tx_val = drv_data->cur_chip->idle_tx_val;
 
@@ -321,25 +294,7 @@ static void bfin_spi_u8_reader(struct driver_data *drv_data)
        }
 }
 
-static void bfin_spi_u8_cs_chg_reader(struct driver_data *drv_data)
-{
-       struct chip_data *chip = drv_data->cur_chip;
-       u16 tx_val = chip->idle_tx_val;
-
-       /* discard old RX data and clear RXS */
-       bfin_spi_dummy_read(drv_data);
-
-       while (drv_data->rx < drv_data->rx_end) {
-               bfin_spi_cs_active(drv_data, chip);
-               write_TDBR(drv_data, tx_val);
-               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-                       cpu_relax();
-               *(u8 *) (drv_data->rx++) = read_RDBR(drv_data);
-               bfin_spi_cs_deactive(drv_data, chip);
-       }
-}
-
-static void bfin_spi_u8_duplex(struct driver_data *drv_data)
+static void bfin_spi_u8_duplex(struct bfin_spi_master_data *drv_data)
 {
        /* discard old RX data and clear RXS */
        bfin_spi_dummy_read(drv_data);
@@ -352,24 +307,13 @@ static void bfin_spi_u8_duplex(struct driver_data *drv_data)
        }
 }
 
-static void bfin_spi_u8_cs_chg_duplex(struct driver_data *drv_data)
-{
-       struct chip_data *chip = drv_data->cur_chip;
-
-       /* discard old RX data and clear RXS */
-       bfin_spi_dummy_read(drv_data);
-
-       while (drv_data->rx < drv_data->rx_end) {
-               bfin_spi_cs_active(drv_data, chip);
-               write_TDBR(drv_data, (*(u8 *) (drv_data->tx++)));
-               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-                       cpu_relax();
-               *(u8 *) (drv_data->rx++) = read_RDBR(drv_data);
-               bfin_spi_cs_deactive(drv_data, chip);
-       }
-}
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = {
+       .write  = bfin_spi_u8_writer,
+       .read   = bfin_spi_u8_reader,
+       .duplex = bfin_spi_u8_duplex,
+};
 
-static void bfin_spi_u16_writer(struct driver_data *drv_data)
+static void bfin_spi_u16_writer(struct bfin_spi_master_data *drv_data)
 {
        /* clear RXS (we check for RXS inside the loop) */
        bfin_spi_dummy_read(drv_data);
@@ -386,26 +330,7 @@ static void bfin_spi_u16_writer(struct driver_data *drv_data)
        }
 }
 
-static void bfin_spi_u16_cs_chg_writer(struct driver_data *drv_data)
-{
-       struct chip_data *chip = drv_data->cur_chip;
-
-       /* clear RXS (we check for RXS inside the loop) */
-       bfin_spi_dummy_read(drv_data);
-
-       while (drv_data->tx < drv_data->tx_end) {
-               bfin_spi_cs_active(drv_data, chip);
-               write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               drv_data->tx += 2;
-               /* make sure transfer finished before deactiving CS */
-               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-                       cpu_relax();
-               bfin_spi_dummy_read(drv_data);
-               bfin_spi_cs_deactive(drv_data, chip);
-       }
-}
-
-static void bfin_spi_u16_reader(struct driver_data *drv_data)
+static void bfin_spi_u16_reader(struct bfin_spi_master_data *drv_data)
 {
        u16 tx_val = drv_data->cur_chip->idle_tx_val;
 
@@ -421,26 +346,7 @@ static void bfin_spi_u16_reader(struct driver_data *drv_data)
        }
 }
 
-static void bfin_spi_u16_cs_chg_reader(struct driver_data *drv_data)
-{
-       struct chip_data *chip = drv_data->cur_chip;
-       u16 tx_val = chip->idle_tx_val;
-
-       /* discard old RX data and clear RXS */
-       bfin_spi_dummy_read(drv_data);
-
-       while (drv_data->rx < drv_data->rx_end) {
-               bfin_spi_cs_active(drv_data, chip);
-               write_TDBR(drv_data, tx_val);
-               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-                       cpu_relax();
-               *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
-               drv_data->rx += 2;
-               bfin_spi_cs_deactive(drv_data, chip);
-       }
-}
-
-static void bfin_spi_u16_duplex(struct driver_data *drv_data)
+static void bfin_spi_u16_duplex(struct bfin_spi_master_data *drv_data)
 {
        /* discard old RX data and clear RXS */
        bfin_spi_dummy_read(drv_data);
@@ -455,27 +361,14 @@ static void bfin_spi_u16_duplex(struct driver_data *drv_data)
        }
 }
 
-static void bfin_spi_u16_cs_chg_duplex(struct driver_data *drv_data)
-{
-       struct chip_data *chip = drv_data->cur_chip;
-
-       /* discard old RX data and clear RXS */
-       bfin_spi_dummy_read(drv_data);
-
-       while (drv_data->rx < drv_data->rx_end) {
-               bfin_spi_cs_active(drv_data, chip);
-               write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
-               drv_data->tx += 2;
-               while (!(read_STAT(drv_data) & BIT_STAT_RXS))
-                       cpu_relax();
-               *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
-               drv_data->rx += 2;
-               bfin_spi_cs_deactive(drv_data, chip);
-       }
-}
+static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = {
+       .write  = bfin_spi_u16_writer,
+       .read   = bfin_spi_u16_reader,
+       .duplex = bfin_spi_u16_duplex,
+};
 
-/* test if ther is more transfer to be done */
-static void *bfin_spi_next_transfer(struct driver_data *drv_data)
+/* test if there is more transfer to be done */
+static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data)
 {
        struct spi_message *msg = drv_data->cur_msg;
        struct spi_transfer *trans = drv_data->cur_transfer;
@@ -494,9 +387,9 @@ static void *bfin_spi_next_transfer(struct driver_data *drv_data)
  * caller already set message->status;
  * dma and pio irqs are blocked give finished message back
  */
-static void bfin_spi_giveback(struct driver_data *drv_data)
+static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data)
 {
-       struct chip_data *chip = drv_data->cur_chip;
+       struct bfin_spi_slave_data *chip = drv_data->cur_chip;
        struct spi_transfer *last_transfer;
        unsigned long flags;
        struct spi_message *msg;
@@ -525,10 +418,83 @@ static void bfin_spi_giveback(struct driver_data *drv_data)
                msg->complete(msg->context);
 }
 
+/* spi data irq handler */
+static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
+{
+       struct bfin_spi_master_data *drv_data = dev_id;
+       struct bfin_spi_slave_data *chip = drv_data->cur_chip;
+       struct spi_message *msg = drv_data->cur_msg;
+       int n_bytes = drv_data->n_bytes;
+
+       /* wait until transfer finished. */
+       while (!(read_STAT(drv_data) & BIT_STAT_RXS))
+               cpu_relax();
+
+       if ((drv_data->tx && drv_data->tx >= drv_data->tx_end) ||
+               (drv_data->rx && drv_data->rx >= (drv_data->rx_end - n_bytes))) {
+               /* last read */
+               if (drv_data->rx) {
+                       dev_dbg(&drv_data->pdev->dev, "last read\n");
+                       if (n_bytes == 2)
+                               *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
+                       else if (n_bytes == 1)
+                               *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
+                       drv_data->rx += n_bytes;
+               }
+
+               msg->actual_length += drv_data->len_in_bytes;
+               if (drv_data->cs_change)
+                       bfin_spi_cs_deactive(drv_data, chip);
+               /* Move to next transfer */
+               msg->state = bfin_spi_next_transfer(drv_data);
+
+               disable_irq_nosync(drv_data->spi_irq);
+
+               /* Schedule transfer tasklet */
+               tasklet_schedule(&drv_data->pump_transfers);
+               return IRQ_HANDLED;
+       }
+
+       if (drv_data->rx && drv_data->tx) {
+               /* duplex */
+               dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n");
+               if (drv_data->n_bytes == 2) {
+                       *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
+                       write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+               } else if (drv_data->n_bytes == 1) {
+                       *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
+                       write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+               }
+       } else if (drv_data->rx) {
+               /* read */
+               dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n");
+               if (drv_data->n_bytes == 2)
+                       *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
+               else if (drv_data->n_bytes == 1)
+                       *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
+               write_TDBR(drv_data, chip->idle_tx_val);
+       } else if (drv_data->tx) {
+               /* write */
+               dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n");
+               bfin_spi_dummy_read(drv_data);
+               if (drv_data->n_bytes == 2)
+                       write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+               else if (drv_data->n_bytes == 1)
+                       write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+       }
+
+       if (drv_data->tx)
+               drv_data->tx += n_bytes;
+       if (drv_data->rx)
+               drv_data->rx += n_bytes;
+
+       return IRQ_HANDLED;
+}
+
 static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
 {
-       struct driver_data *drv_data = dev_id;
-       struct chip_data *chip = drv_data->cur_chip;
+       struct bfin_spi_master_data *drv_data = dev_id;
+       struct bfin_spi_slave_data *chip = drv_data->cur_chip;
        struct spi_message *msg = drv_data->cur_msg;
        unsigned long timeout;
        unsigned short dmastat = get_dma_curr_irqstat(drv_data->dma_channel);
@@ -540,10 +506,6 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
 
        clear_dma_irqstat(drv_data->dma_channel);
 
-       /* Wait for DMA to complete */
-       while (get_dma_curr_irqstat(drv_data->dma_channel) & DMA_RUN)
-               cpu_relax();
-
        /*
         * wait for the last transaction shifted out.  HRM states:
         * at this point there may still be data in the SPI DMA FIFO waiting
@@ -551,8 +513,8 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
         * register until it goes low for 2 successive reads
         */
        if (drv_data->tx != NULL) {
-               while ((read_STAT(drv_data) & TXS) ||
-                      (read_STAT(drv_data) & TXS))
+               while ((read_STAT(drv_data) & BIT_STAT_TXS) ||
+                      (read_STAT(drv_data) & BIT_STAT_TXS))
                        cpu_relax();
        }
 
@@ -561,14 +523,14 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
                dmastat, read_STAT(drv_data));
 
        timeout = jiffies + HZ;
-       while (!(read_STAT(drv_data) & SPIF))
+       while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
                if (!time_before(jiffies, timeout)) {
                        dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF");
                        break;
                } else
                        cpu_relax();
 
-       if ((dmastat & DMA_ERR) && (spistat & RBSY)) {
+       if ((dmastat & DMA_ERR) && (spistat & BIT_STAT_RBSY)) {
                msg->state = ERROR_STATE;
                dev_err(&drv_data->pdev->dev, "dma receive: fifo/buffer overflow\n");
        } else {
@@ -588,20 +550,20 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
        dev_dbg(&drv_data->pdev->dev,
                "disable dma channel irq%d\n",
                drv_data->dma_channel);
-       dma_disable_irq(drv_data->dma_channel);
+       dma_disable_irq_nosync(drv_data->dma_channel);
 
        return IRQ_HANDLED;
 }
 
 static void bfin_spi_pump_transfers(unsigned long data)
 {
-       struct driver_data *drv_data = (struct driver_data *)data;
+       struct bfin_spi_master_data *drv_data = (struct bfin_spi_master_data *)data;
        struct spi_message *message = NULL;
        struct spi_transfer *transfer = NULL;
        struct spi_transfer *previous = NULL;
-       struct chip_data *chip = NULL;
-       u8 width;
-       u16 cr, dma_width, dma_config;
+       struct bfin_spi_slave_data *chip = NULL;
+       unsigned int bits_per_word;
+       u16 cr, cr_width, dma_width, dma_config;
        u32 tranf_success = 1;
        u8 full_duplex = 0;
 
@@ -639,7 +601,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
                        udelay(previous->delay_usecs);
        }
 
-       /* Setup the transfer state based on the type of transfer */
+       /* Flush any existing transfers that may be sitting in the hardware */
        if (bfin_spi_flush(drv_data) == 0) {
                dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
                message->status = -EIO;
@@ -679,52 +641,31 @@ static void bfin_spi_pump_transfers(unsigned long data)
        drv_data->cs_change = transfer->cs_change;
 
        /* Bits per word setup */
-       switch (transfer->bits_per_word) {
-       case 8:
+       bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word;
+       if (bits_per_word == 8) {
                drv_data->n_bytes = 1;
-               width = CFG_SPI_WORDSIZE8;
-               drv_data->read = chip->cs_change_per_word ?
-                       bfin_spi_u8_cs_chg_reader : bfin_spi_u8_reader;
-               drv_data->write = chip->cs_change_per_word ?
-                       bfin_spi_u8_cs_chg_writer : bfin_spi_u8_writer;
-               drv_data->duplex = chip->cs_change_per_word ?
-                       bfin_spi_u8_cs_chg_duplex : bfin_spi_u8_duplex;
-               break;
-
-       case 16:
+               drv_data->len = transfer->len;
+               cr_width = 0;
+               drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
+       } else if (bits_per_word == 16) {
                drv_data->n_bytes = 2;
-               width = CFG_SPI_WORDSIZE16;
-               drv_data->read = chip->cs_change_per_word ?
-                       bfin_spi_u16_cs_chg_reader : bfin_spi_u16_reader;
-               drv_data->write = chip->cs_change_per_word ?
-                       bfin_spi_u16_cs_chg_writer : bfin_spi_u16_writer;
-               drv_data->duplex = chip->cs_change_per_word ?
-                       bfin_spi_u16_cs_chg_duplex : bfin_spi_u16_duplex;
-               break;
-
-       default:
-               /* No change, the same as default setting */
-               drv_data->n_bytes = chip->n_bytes;
-               width = chip->width;
-               drv_data->write = drv_data->tx ? chip->write : bfin_spi_null_writer;
-               drv_data->read = drv_data->rx ? chip->read : bfin_spi_null_reader;
-               drv_data->duplex = chip->duplex ? chip->duplex : bfin_spi_null_writer;
-               break;
-       }
-       cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
-       cr |= (width << 8);
-       write_CTRL(drv_data, cr);
-
-       if (width == CFG_SPI_WORDSIZE16) {
                drv_data->len = (transfer->len) >> 1;
+               cr_width = BIT_CTL_WORDSIZE;
+               drv_data->ops = &bfin_bfin_spi_transfer_ops_u16;
        } else {
-               drv_data->len = transfer->len;
+               dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n");
+               message->status = -EINVAL;
+               bfin_spi_giveback(drv_data);
+               return;
        }
+       cr = read_CTRL(drv_data) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE);
+       cr |= cr_width;
+       write_CTRL(drv_data, cr);
+
        dev_dbg(&drv_data->pdev->dev,
-               "transfer: drv_data->write is %p, chip->write is %p, null_wr is %p\n",
-               drv_data->write, chip->write, bfin_spi_null_writer);
+               "transfer: drv_data->ops is %p, chip->ops is %p, u8_ops is %p\n",
+               drv_data->ops, chip->ops, &bfin_bfin_spi_transfer_ops_u8);
 
-       /* speed and width has been set on per message */
        message->state = RUNNING_STATE;
        dma_config = 0;
 
@@ -735,13 +676,11 @@ static void bfin_spi_pump_transfers(unsigned long data)
                write_BAUD(drv_data, chip->baud);
 
        write_STAT(drv_data, BIT_STAT_CLR);
-       cr = (read_CTRL(drv_data) & (~BIT_CTL_TIMOD));
-       if (drv_data->cs_change)
-               bfin_spi_cs_active(drv_data, chip);
+       bfin_spi_cs_active(drv_data, chip);
 
        dev_dbg(&drv_data->pdev->dev,
                "now pumping a transfer: width is %d, len is %d\n",
-               width, transfer->len);
+               cr_width, transfer->len);
 
        /*
         * Try to map dma buffer and do a dma transfer.  If successful use,
@@ -760,7 +699,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
                /* config dma channel */
                dev_dbg(&drv_data->pdev->dev, "doing dma transfer\n");
                set_dma_x_count(drv_data->dma_channel, drv_data->len);
-               if (width == CFG_SPI_WORDSIZE16) {
+               if (cr_width == BIT_CTL_WORDSIZE) {
                        set_dma_x_modify(drv_data->dma_channel, 2);
                        dma_width = WDSIZE_16;
                } else {
@@ -846,73 +785,100 @@ static void bfin_spi_pump_transfers(unsigned long data)
                dma_enable_irq(drv_data->dma_channel);
                local_irq_restore(flags);
 
-       } else {
-               /* IO mode write then read */
-               dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
-
-               /* we always use SPI_WRITE mode. SPI_READ mode
-                  seems to have problems with setting up the
-                  output value in TDBR prior to the transfer. */
-               write_CTRL(drv_data, (cr | CFG_SPI_WRITE));
-
-               if (full_duplex) {
-                       /* full duplex mode */
-                       BUG_ON((drv_data->tx_end - drv_data->tx) !=
-                              (drv_data->rx_end - drv_data->rx));
-                       dev_dbg(&drv_data->pdev->dev,
-                               "IO duplex: cr is 0x%x\n", cr);
-
-                       drv_data->duplex(drv_data);
+               return;
+       }
 
-                       if (drv_data->tx != drv_data->tx_end)
-                               tranf_success = 0;
-               } else if (drv_data->tx != NULL) {
-                       /* write only half duplex */
-                       dev_dbg(&drv_data->pdev->dev,
-                               "IO write: cr is 0x%x\n", cr);
+       /*
+        * We always use SPI_WRITE mode (transfer starts with TDBR write).
+        * SPI_READ mode (transfer starts with RDBR read) seems to have
+        * problems with setting up the output value in TDBR prior to the
+        * start of the transfer.
+        */
+       write_CTRL(drv_data, cr | BIT_CTL_TXMOD);
 
-                       drv_data->write(drv_data);
+       if (chip->pio_interrupt) {
+               /* SPI irq should have been disabled by now */
 
-                       if (drv_data->tx != drv_data->tx_end)
-                               tranf_success = 0;
-               } else if (drv_data->rx != NULL) {
-                       /* read only half duplex */
-                       dev_dbg(&drv_data->pdev->dev,
-                               "IO read: cr is 0x%x\n", cr);
+               /* discard old RX data and clear RXS */
+               bfin_spi_dummy_read(drv_data);
 
-                       drv_data->read(drv_data);
-                       if (drv_data->rx != drv_data->rx_end)
-                               tranf_success = 0;
+               /* start transfer */
+               if (drv_data->tx == NULL)
+                       write_TDBR(drv_data, chip->idle_tx_val);
+               else {
+                       if (bits_per_word == 8)
+                               write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+                       else
+                               write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+                       drv_data->tx += drv_data->n_bytes;
                }
 
-               if (!tranf_success) {
-                       dev_dbg(&drv_data->pdev->dev,
-                               "IO write error!\n");
-                       message->state = ERROR_STATE;
-               } else {
-                       /* Update total byte transfered */
-                       message->actual_length += drv_data->len_in_bytes;
-                       /* Move to next transfer of this msg */
-                       message->state = bfin_spi_next_transfer(drv_data);
-                       if (drv_data->cs_change)
-                               bfin_spi_cs_deactive(drv_data, chip);
-               }
-               /* Schedule next transfer tasklet */
-               tasklet_schedule(&drv_data->pump_transfers);
+               /* once TDBR is empty, interrupt is triggered */
+               enable_irq(drv_data->spi_irq);
+               return;
+       }
+
+       /* IO mode */
+       dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
+
+       if (full_duplex) {
+               /* full duplex mode */
+               BUG_ON((drv_data->tx_end - drv_data->tx) !=
+                      (drv_data->rx_end - drv_data->rx));
+               dev_dbg(&drv_data->pdev->dev,
+                       "IO duplex: cr is 0x%x\n", cr);
+
+               drv_data->ops->duplex(drv_data);
+
+               if (drv_data->tx != drv_data->tx_end)
+                       tranf_success = 0;
+       } else if (drv_data->tx != NULL) {
+               /* write only half duplex */
+               dev_dbg(&drv_data->pdev->dev,
+                       "IO write: cr is 0x%x\n", cr);
+
+               drv_data->ops->write(drv_data);
+
+               if (drv_data->tx != drv_data->tx_end)
+                       tranf_success = 0;
+       } else if (drv_data->rx != NULL) {
+               /* read only half duplex */
+               dev_dbg(&drv_data->pdev->dev,
+                       "IO read: cr is 0x%x\n", cr);
+
+               drv_data->ops->read(drv_data);
+               if (drv_data->rx != drv_data->rx_end)
+                       tranf_success = 0;
+       }
+
+       if (!tranf_success) {
+               dev_dbg(&drv_data->pdev->dev,
+                       "IO write error!\n");
+               message->state = ERROR_STATE;
+       } else {
+               /* Update total byte transfered */
+               message->actual_length += drv_data->len_in_bytes;
+               /* Move to next transfer of this msg */
+               message->state = bfin_spi_next_transfer(drv_data);
+               if (drv_data->cs_change)
+                       bfin_spi_cs_deactive(drv_data, chip);
        }
+
+       /* Schedule next transfer tasklet */
+       tasklet_schedule(&drv_data->pump_transfers);
 }
 
 /* pop a msg from queue and kick off real transfer */
 static void bfin_spi_pump_messages(struct work_struct *work)
 {
-       struct driver_data *drv_data;
+       struct bfin_spi_master_data *drv_data;
        unsigned long flags;
 
-       drv_data = container_of(work, struct driver_data, pump_messages);
+       drv_data = container_of(work, struct bfin_spi_master_data, pump_messages);
 
        /* Lock queue and check for queue work */
        spin_lock_irqsave(&drv_data->lock, flags);
-       if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {
+       if (list_empty(&drv_data->queue) || !drv_data->running) {
                /* pumper kicked off but no work to do */
                drv_data->busy = 0;
                spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -962,12 +928,12 @@ static void bfin_spi_pump_messages(struct work_struct *work)
  */
 static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg)
 {
-       struct driver_data *drv_data = spi_master_get_devdata(spi->master);
+       struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master);
        unsigned long flags;
 
        spin_lock_irqsave(&drv_data->lock, flags);
 
-       if (drv_data->run == QUEUE_STOPPED) {
+       if (!drv_data->running) {
                spin_unlock_irqrestore(&drv_data->lock, flags);
                return -ESHUTDOWN;
        }
@@ -979,7 +945,7 @@ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg)
        dev_dbg(&spi->dev, "adding an msg in transfer() \n");
        list_add_tail(&msg->queue, &drv_data->queue);
 
-       if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
+       if (drv_data->running && !drv_data->busy)
                queue_work(drv_data->workqueue, &drv_data->pump_messages);
 
        spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -1003,147 +969,184 @@ static u16 ssel[][MAX_SPI_SSEL] = {
        P_SPI2_SSEL6, P_SPI2_SSEL7},
 };
 
-/* first setup for new devices */
+/* setup for devices (may be called multiple times -- not just first setup) */
 static int bfin_spi_setup(struct spi_device *spi)
 {
-       struct bfin5xx_spi_chip *chip_info = NULL;
-       struct chip_data *chip;
-       struct driver_data *drv_data = spi_master_get_devdata(spi->master);
-       int ret;
-
-       if (spi->bits_per_word != 8 && spi->bits_per_word != 16)
-               return -EINVAL;
+       struct bfin5xx_spi_chip *chip_info;
+       struct bfin_spi_slave_data *chip = NULL;
+       struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master);
+       u16 bfin_ctl_reg;
+       int ret = -EINVAL;
 
        /* Only alloc (or use chip_info) on first setup */
+       chip_info = NULL;
        chip = spi_get_ctldata(spi);
        if (chip == NULL) {
-               chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
-               if (!chip)
-                       return -ENOMEM;
+               chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+               if (!chip) {
+                       dev_err(&spi->dev, "cannot allocate chip data\n");
+                       ret = -ENOMEM;
+                       goto error;
+               }
 
                chip->enable_dma = 0;
                chip_info = spi->controller_data;
        }
 
+       /* Let people set non-standard bits directly */
+       bfin_ctl_reg = BIT_CTL_OPENDRAIN | BIT_CTL_EMISO |
+               BIT_CTL_PSSE | BIT_CTL_GM | BIT_CTL_SZ;
+
        /* chip_info isn't always needed */
        if (chip_info) {
                /* Make sure people stop trying to set fields via ctl_reg
                 * when they should actually be using common SPI framework.
-                * Currently we let through: WOM EMISO PSSE GM SZ TIMOD.
+                * Currently we let through: WOM EMISO PSSE GM SZ.
                 * Not sure if a user actually needs/uses any of these,
                 * but let's assume (for now) they do.
                 */
-               if (chip_info->ctl_reg & (SPE|MSTR|CPOL|CPHA|LSBF|SIZE)) {
+               if (chip_info->ctl_reg & ~bfin_ctl_reg) {
                        dev_err(&spi->dev, "do not set bits in ctl_reg "
                                "that the SPI framework manages\n");
-                       return -EINVAL;
+                       goto error;
                }
-
                chip->enable_dma = chip_info->enable_dma != 0
                    && drv_data->master_info->enable_dma;
                chip->ctl_reg = chip_info->ctl_reg;
-               chip->bits_per_word = chip_info->bits_per_word;
-               chip->cs_change_per_word = chip_info->cs_change_per_word;
                chip->cs_chg_udelay = chip_info->cs_chg_udelay;
-               chip->cs_gpio = chip_info->cs_gpio;
                chip->idle_tx_val = chip_info->idle_tx_val;
+               chip->pio_interrupt = chip_info->pio_interrupt;
+               spi->bits_per_word = chip_info->bits_per_word;
+       } else {
+               /* force a default base state */
+               chip->ctl_reg &= bfin_ctl_reg;
+       }
+
+       if (spi->bits_per_word != 8 && spi->bits_per_word != 16) {
+               dev_err(&spi->dev, "%d bits_per_word is not supported\n",
+                               spi->bits_per_word);
+               goto error;
        }
 
        /* translate common spi framework into our register */
+       if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) {
+               dev_err(&spi->dev, "unsupported spi modes detected\n");
+               goto error;
+       }
        if (spi->mode & SPI_CPOL)
-               chip->ctl_reg |= CPOL;
+               chip->ctl_reg |= BIT_CTL_CPOL;
        if (spi->mode & SPI_CPHA)
-               chip->ctl_reg |= CPHA;
+               chip->ctl_reg |= BIT_CTL_CPHA;
        if (spi->mode & SPI_LSB_FIRST)
-               chip->ctl_reg |= LSBF;
+               chip->ctl_reg |= BIT_CTL_LSBF;
        /* we dont support running in slave mode (yet?) */
-       chip->ctl_reg |= MSTR;
+       chip->ctl_reg |= BIT_CTL_MASTER;
 
+       /*
+        * Notice: for blackfin, the speed_hz is the value of register
+        * SPI_BAUD, not the real baudrate
+        */
+       chip->baud = hz_to_spi_baud(spi->max_speed_hz);
+       chip->chip_select_num = spi->chip_select;
+       if (chip->chip_select_num < MAX_CTRL_CS) {
+               if (!(spi->mode & SPI_CPHA))
+                       dev_warn(&spi->dev, "Warning: SPI CPHA not set:"
+                               " Slave Select not under software control!\n"
+                               " See Documentation/blackfin/bfin-spi-notes.txt");
+
+               chip->flag = (1 << spi->chip_select) << 8;
+       } else
+               chip->cs_gpio = chip->chip_select_num - MAX_CTRL_CS;
+
+       if (chip->enable_dma && chip->pio_interrupt) {
+               dev_err(&spi->dev, "enable_dma is set, "
+                               "do not set pio_interrupt\n");
+               goto error;
+       }
        /*
         * if any one SPI chip is registered and wants DMA, request the
         * DMA channel for it
         */
        if (chip->enable_dma && !drv_data->dma_requested) {
                /* register dma irq handler */
-               if (request_dma(drv_data->dma_channel, "BFIN_SPI_DMA") < 0) {
-                       dev_dbg(&spi->dev,
+               ret = request_dma(drv_data->dma_channel, "BFIN_SPI_DMA");
+               if (ret) {
+                       dev_err(&spi->dev,
                                "Unable to request BlackFin SPI DMA channel\n");
-                       return -ENODEV;
+                       goto error;
                }
-               if (set_dma_callback(drv_data->dma_channel,
-                   bfin_spi_dma_irq_handler, drv_data) < 0) {
-                       dev_dbg(&spi->dev, "Unable to set dma callback\n");
-                       return -EPERM;
+               drv_data->dma_requested = 1;
+
+               ret = set_dma_callback(drv_data->dma_channel,
+                       bfin_spi_dma_irq_handler, drv_data);
+               if (ret) {
+                       dev_err(&spi->dev, "Unable to set dma callback\n");
+                       goto error;
                }
                dma_disable_irq(drv_data->dma_channel);
-               drv_data->dma_requested = 1;
        }
 
-       /*
-        * Notice: for blackfin, the speed_hz is the value of register
-        * SPI_BAUD, not the real baudrate
-        */
-       chip->baud = hz_to_spi_baud(spi->max_speed_hz);
-       chip->flag = 1 << (spi->chip_select);
-       chip->chip_select_num = spi->chip_select;
+       if (chip->pio_interrupt && !drv_data->irq_requested) {
+               ret = request_irq(drv_data->spi_irq, bfin_spi_pio_irq_handler,
+                       IRQF_DISABLED, "BFIN_SPI", drv_data);
+               if (ret) {
+                       dev_err(&spi->dev, "Unable to register spi IRQ\n");
+                       goto error;
+               }
+               drv_data->irq_requested = 1;
+               /* we use write mode, spi irq has to be disabled here */
+               disable_irq(drv_data->spi_irq);
+       }
 
-       if (chip->chip_select_num == 0) {
+       if (chip->chip_select_num >= MAX_CTRL_CS) {
                ret = gpio_request(chip->cs_gpio, spi->modalias);
                if (ret) {
-                       if (drv_data->dma_requested)
-                               free_dma(drv_data->dma_channel);
-                       return ret;
+                       dev_err(&spi->dev, "gpio_request() error\n");
+                       goto pin_error;
                }
                gpio_direction_output(chip->cs_gpio, 1);
        }
 
-       switch (chip->bits_per_word) {
-       case 8:
-               chip->n_bytes = 1;
-               chip->width = CFG_SPI_WORDSIZE8;
-               chip->read = chip->cs_change_per_word ?
-                       bfin_spi_u8_cs_chg_reader : bfin_spi_u8_reader;
-               chip->write = chip->cs_change_per_word ?
-                       bfin_spi_u8_cs_chg_writer : bfin_spi_u8_writer;
-               chip->duplex = chip->cs_change_per_word ?
-                       bfin_spi_u8_cs_chg_duplex : bfin_spi_u8_duplex;
-               break;
-
-       case 16:
-               chip->n_bytes = 2;
-               chip->width = CFG_SPI_WORDSIZE16;
-               chip->read = chip->cs_change_per_word ?
-                       bfin_spi_u16_cs_chg_reader : bfin_spi_u16_reader;
-               chip->write = chip->cs_change_per_word ?
-                       bfin_spi_u16_cs_chg_writer : bfin_spi_u16_writer;
-               chip->duplex = chip->cs_change_per_word ?
-                       bfin_spi_u16_cs_chg_duplex : bfin_spi_u16_duplex;
-               break;
-
-       default:
-               dev_err(&spi->dev, "%d bits_per_word is not supported\n",
-                               chip->bits_per_word);
-               if (chip_info)
-                       kfree(chip);
-               return -ENODEV;
-       }
-
        dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n",
-                       spi->modalias, chip->width, chip->enable_dma);
+                       spi->modalias, spi->bits_per_word, chip->enable_dma);
        dev_dbg(&spi->dev, "ctl_reg is 0x%x, flag_reg is 0x%x\n",
                        chip->ctl_reg, chip->flag);
 
        spi_set_ctldata(spi, chip);
 
        dev_dbg(&spi->dev, "chip select number is %d\n", chip->chip_select_num);
-       if ((chip->chip_select_num > 0)
-               && (chip->chip_select_num <= spi->master->num_chipselect))
-               peripheral_request(ssel[spi->master->bus_num]
-                       [chip->chip_select_num-1], spi->modalias);
+       if (chip->chip_select_num < MAX_CTRL_CS) {
+               ret = peripheral_request(ssel[spi->master->bus_num]
+                                        [chip->chip_select_num-1], spi->modalias);
+               if (ret) {
+                       dev_err(&spi->dev, "peripheral_request() error\n");
+                       goto pin_error;
+               }
+       }
 
+       bfin_spi_cs_enable(drv_data, chip);
        bfin_spi_cs_deactive(drv_data, chip);
 
        return 0;
+
+ pin_error:
+       if (chip->chip_select_num >= MAX_CTRL_CS)
+               gpio_free(chip->cs_gpio);
+       else
+               peripheral_free(ssel[spi->master->bus_num]
+                       [chip->chip_select_num - 1]);
+ error:
+       if (chip) {
+               if (drv_data->dma_requested)
+                       free_dma(drv_data->dma_channel);
+               drv_data->dma_requested = 0;
+
+               kfree(chip);
+               /* prevent free 'chip' twice */
+               spi_set_ctldata(spi, NULL);
+       }
+
+       return ret;
 }
 
 /*
@@ -1152,28 +1155,30 @@ static int bfin_spi_setup(struct spi_device *spi)
  */
 static void bfin_spi_cleanup(struct spi_device *spi)
 {
-       struct chip_data *chip = spi_get_ctldata(spi);
+       struct bfin_spi_slave_data *chip = spi_get_ctldata(spi);
+       struct bfin_spi_master_data *drv_data = spi_master_get_devdata(spi->master);
 
        if (!chip)
                return;
 
-       if ((chip->chip_select_num > 0)
-               && (chip->chip_select_num <= spi->master->num_chipselect))
+       if (chip->chip_select_num < MAX_CTRL_CS) {
                peripheral_free(ssel[spi->master->bus_num]
                                        [chip->chip_select_num-1]);
-
-       if (chip->chip_select_num == 0)
+               bfin_spi_cs_disable(drv_data, chip);
+       } else
                gpio_free(chip->cs_gpio);
 
        kfree(chip);
+       /* prevent free 'chip' twice */
+       spi_set_ctldata(spi, NULL);
 }
 
-static inline int bfin_spi_init_queue(struct driver_data *drv_data)
+static inline int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data)
 {
        INIT_LIST_HEAD(&drv_data->queue);
        spin_lock_init(&drv_data->lock);
 
-       drv_data->run = QUEUE_STOPPED;
+       drv_data->running = false;
        drv_data->busy = 0;
 
        /* init transfer tasklet */
@@ -1190,18 +1195,18 @@ static inline int bfin_spi_init_queue(struct driver_data *drv_data)
        return 0;
 }
 
-static inline int bfin_spi_start_queue(struct driver_data *drv_data)
+static inline int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data)
 {
        unsigned long flags;
 
        spin_lock_irqsave(&drv_data->lock, flags);
 
-       if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {
+       if (drv_data->running || drv_data->busy) {
                spin_unlock_irqrestore(&drv_data->lock, flags);
                return -EBUSY;
        }
 
-       drv_data->run = QUEUE_RUNNING;
+       drv_data->running = true;
        drv_data->cur_msg = NULL;
        drv_data->cur_transfer = NULL;
        drv_data->cur_chip = NULL;
@@ -1212,7 +1217,7 @@ static inline int bfin_spi_start_queue(struct driver_data *drv_data)
        return 0;
 }
 
-static inline int bfin_spi_stop_queue(struct driver_data *drv_data)
+static inline int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data)
 {
        unsigned long flags;
        unsigned limit = 500;
@@ -1226,7 +1231,7 @@ static inline int bfin_spi_stop_queue(struct driver_data *drv_data)
         * execution path (pump_messages) would be required to call wake_up or
         * friends on every SPI message. Do this instead
         */
-       drv_data->run = QUEUE_STOPPED;
+       drv_data->running = false;
        while (!list_empty(&drv_data->queue) && drv_data->busy && limit--) {
                spin_unlock_irqrestore(&drv_data->lock, flags);
                msleep(10);
@@ -1241,7 +1246,7 @@ static inline int bfin_spi_stop_queue(struct driver_data *drv_data)
        return status;
 }
 
-static inline int bfin_spi_destroy_queue(struct driver_data *drv_data)
+static inline int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data)
 {
        int status;
 
@@ -1259,14 +1264,14 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct bfin5xx_spi_master *platform_info;
        struct spi_master *master;
-       struct driver_data *drv_data = 0;
+       struct bfin_spi_master_data *drv_data;
        struct resource *res;
        int status = 0;
 
        platform_info = dev->platform_data;
 
        /* Allocate master with space for drv_data */
-       master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
+       master = spi_alloc_master(dev, sizeof(*drv_data));
        if (!master) {
                dev_err(&pdev->dev, "can not alloc spi_master\n");
                return -ENOMEM;
@@ -1302,11 +1307,19 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
                goto out_error_ioremap;
        }
 
-       drv_data->dma_channel = platform_get_irq(pdev, 0);
-       if (drv_data->dma_channel < 0) {
+       res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+       if (res == NULL) {
                dev_err(dev, "No DMA channel specified\n");
                status = -ENOENT;
-               goto out_error_no_dma_ch;
+               goto out_error_free_io;
+       }
+       drv_data->dma_channel = res->start;
+
+       drv_data->spi_irq = platform_get_irq(pdev, 0);
+       if (drv_data->spi_irq < 0) {
+               dev_err(dev, "No spi pio irq specified\n");
+               status = -ENOENT;
+               goto out_error_free_io;
        }
 
        /* Initial and start queue */
@@ -1328,6 +1341,12 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
                goto out_error_queue_alloc;
        }
 
+       /* Reset SPI registers. If these registers were used by the boot loader,
+        * the sky may fall on your head if you enable the dma controller.
+        */
+       write_CTRL(drv_data, BIT_CTL_CPHA | BIT_CTL_MASTER);
+       write_FLAG(drv_data, 0xFF00);
+
        /* Register with the SPI framework */
        platform_set_drvdata(pdev, drv_data);
        status = spi_register_master(master);
@@ -1343,7 +1362,7 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
 
 out_error_queue_alloc:
        bfin_spi_destroy_queue(drv_data);
-out_error_no_dma_ch:
+out_error_free_io:
        iounmap((void *) drv_data->regs_base);
 out_error_ioremap:
 out_error_get_res:
@@ -1355,7 +1374,7 @@ out_error_get_res:
 /* stop hardware and remove the driver */
 static int __devexit bfin_spi_remove(struct platform_device *pdev)
 {
-       struct driver_data *drv_data = platform_get_drvdata(pdev);
+       struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
        int status = 0;
 
        if (!drv_data)
@@ -1375,6 +1394,11 @@ static int __devexit bfin_spi_remove(struct platform_device *pdev)
                        free_dma(drv_data->dma_channel);
        }
 
+       if (drv_data->irq_requested) {
+               free_irq(drv_data->spi_irq, drv_data);
+               drv_data->irq_requested = 0;
+       }
+
        /* Disconnect from the SPI framework */
        spi_unregister_master(drv_data->master);
 
@@ -1389,26 +1413,32 @@ static int __devexit bfin_spi_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct driver_data *drv_data = platform_get_drvdata(pdev);
+       struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
        int status = 0;
 
        status = bfin_spi_stop_queue(drv_data);
        if (status != 0)
                return status;
 
-       /* stop hardware */
-       bfin_spi_disable(drv_data);
+       drv_data->ctrl_reg = read_CTRL(drv_data);
+       drv_data->flag_reg = read_FLAG(drv_data);
+
+       /*
+        * reset SPI_CTL and SPI_FLG registers
+        */
+       write_CTRL(drv_data, BIT_CTL_CPHA | BIT_CTL_MASTER);
+       write_FLAG(drv_data, 0xFF00);
 
        return 0;
 }
 
 static int bfin_spi_resume(struct platform_device *pdev)
 {
-       struct driver_data *drv_data = platform_get_drvdata(pdev);
+       struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
        int status = 0;
 
-       /* Enable the SPI interface */
-       bfin_spi_enable(drv_data);
+       write_CTRL(drv_data, drv_data->ctrl_reg);
+       write_FLAG(drv_data, drv_data->flag_reg);
 
        /* Start the queue running */
        status = bfin_spi_start_queue(drv_data);
@@ -1439,7 +1469,7 @@ static int __init bfin_spi_init(void)
 {
        return platform_driver_probe(&bfin_spi_driver, bfin_spi_probe);
 }
-module_init(bfin_spi_init);
+subsys_initcall(bfin_spi_init);
 
 static void __exit bfin_spi_exit(void)
 {
diff --git a/drivers/spi/spi_fsl_espi.c b/drivers/spi/spi_fsl_espi.c
new file mode 100644 (file)
index 0000000..e3b4f64
--- /dev/null
@@ -0,0 +1,748 @@
+/*
+ * Freescale eSPI controller driver.
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_spi.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <sysdev/fsl_soc.h>
+
+#include "spi_fsl_lib.h"
+
+/* eSPI Controller registers */
+struct fsl_espi_reg {
+       __be32 mode;            /* 0x000 - eSPI mode register */
+       __be32 event;           /* 0x004 - eSPI event register */
+       __be32 mask;            /* 0x008 - eSPI mask register */
+       __be32 command;         /* 0x00c - eSPI command register */
+       __be32 transmit;        /* 0x010 - eSPI transmit FIFO access register*/
+       __be32 receive;         /* 0x014 - eSPI receive FIFO access register*/
+       u8 res[8];              /* 0x018 - 0x01c reserved */
+       __be32 csmode[4];       /* 0x020 - 0x02c eSPI cs mode register */
+};
+
+struct fsl_espi_transfer {
+       const void *tx_buf;
+       void *rx_buf;
+       unsigned len;
+       unsigned n_tx;
+       unsigned n_rx;
+       unsigned actual_length;
+       int status;
+};
+
+/* eSPI Controller mode register definitions */
+#define SPMODE_ENABLE          (1 << 31)
+#define SPMODE_LOOP            (1 << 30)
+#define SPMODE_TXTHR(x)                ((x) << 8)
+#define SPMODE_RXTHR(x)                ((x) << 0)
+
+/* eSPI Controller CS mode register definitions */
+#define CSMODE_CI_INACTIVEHIGH (1 << 31)
+#define CSMODE_CP_BEGIN_EDGECLK        (1 << 30)
+#define CSMODE_REV             (1 << 29)
+#define CSMODE_DIV16           (1 << 28)
+#define CSMODE_PM(x)           ((x) << 24)
+#define CSMODE_POL_1           (1 << 20)
+#define CSMODE_LEN(x)          ((x) << 16)
+#define CSMODE_BEF(x)          ((x) << 12)
+#define CSMODE_AFT(x)          ((x) << 8)
+#define CSMODE_CG(x)           ((x) << 3)
+
+/* Default mode/csmode for eSPI controller */
+#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(3))
+#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \
+               | CSMODE_AFT(0) | CSMODE_CG(1))
+
+/* SPIE register values */
+#define        SPIE_NE         0x00000200      /* Not empty */
+#define        SPIE_NF         0x00000100      /* Not full */
+
+/* SPIM register values */
+#define        SPIM_NE         0x00000200      /* Not empty */
+#define        SPIM_NF         0x00000100      /* Not full */
+#define SPIE_RXCNT(reg)     ((reg >> 24) & 0x3F)
+#define SPIE_TXCNT(reg)     ((reg >> 16) & 0x3F)
+
+/* SPCOM register values */
+#define SPCOM_CS(x)            ((x) << 30)
+#define SPCOM_TRANLEN(x)       ((x) << 0)
+#define        SPCOM_TRANLEN_MAX       0xFFFF  /* Max transaction length */
+
+static void fsl_espi_change_mode(struct spi_device *spi)
+{
+       struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
+       struct spi_mpc8xxx_cs *cs = spi->controller_state;
+       struct fsl_espi_reg *reg_base = mspi->reg_base;
+       __be32 __iomem *mode = &reg_base->csmode[spi->chip_select];
+       __be32 __iomem *espi_mode = &reg_base->mode;
+       u32 tmp;
+       unsigned long flags;
+
+       /* Turn off IRQs locally to minimize time that SPI is disabled. */
+       local_irq_save(flags);
+
+       /* Turn off SPI unit prior changing mode */
+       tmp = mpc8xxx_spi_read_reg(espi_mode);
+       mpc8xxx_spi_write_reg(espi_mode, tmp & ~SPMODE_ENABLE);
+       mpc8xxx_spi_write_reg(mode, cs->hw_mode);
+       mpc8xxx_spi_write_reg(espi_mode, tmp);
+
+       local_irq_restore(flags);
+}
+
+static u32 fsl_espi_tx_buf_lsb(struct mpc8xxx_spi *mpc8xxx_spi)
+{
+       u32 data;
+       u16 data_h;
+       u16 data_l;
+       const u32 *tx = mpc8xxx_spi->tx;
+
+       if (!tx)
+               return 0;
+
+       data = *tx++ << mpc8xxx_spi->tx_shift;
+       data_l = data & 0xffff;
+       data_h = (data >> 16) & 0xffff;
+       swab16s(&data_l);
+       swab16s(&data_h);
+       data = data_h | data_l;
+
+       mpc8xxx_spi->tx = tx;
+       return data;
+}
+
+static int fsl_espi_setup_transfer(struct spi_device *spi,
+                                       struct spi_transfer *t)
+{
+       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+       int bits_per_word = 0;
+       u8 pm;
+       u32 hz = 0;
+       struct spi_mpc8xxx_cs *cs = spi->controller_state;
+
+       if (t) {
+               bits_per_word = t->bits_per_word;
+               hz = t->speed_hz;
+       }
+
+       /* spi_transfer level calls that work per-word */
+       if (!bits_per_word)
+               bits_per_word = spi->bits_per_word;
+
+       /* Make sure its a bit width we support [4..16] */
+       if ((bits_per_word < 4) || (bits_per_word > 16))
+               return -EINVAL;
+
+       if (!hz)
+               hz = spi->max_speed_hz;
+
+       cs->rx_shift = 0;
+       cs->tx_shift = 0;
+       cs->get_rx = mpc8xxx_spi_rx_buf_u32;
+       cs->get_tx = mpc8xxx_spi_tx_buf_u32;
+       if (bits_per_word <= 8) {
+               cs->rx_shift = 8 - bits_per_word;
+       } else if (bits_per_word <= 16) {
+               cs->rx_shift = 16 - bits_per_word;
+               if (spi->mode & SPI_LSB_FIRST)
+                       cs->get_tx = fsl_espi_tx_buf_lsb;
+       } else {
+               return -EINVAL;
+       }
+
+       mpc8xxx_spi->rx_shift = cs->rx_shift;
+       mpc8xxx_spi->tx_shift = cs->tx_shift;
+       mpc8xxx_spi->get_rx = cs->get_rx;
+       mpc8xxx_spi->get_tx = cs->get_tx;
+
+       bits_per_word = bits_per_word - 1;
+
+       /* mask out bits we are going to set */
+       cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16 | CSMODE_PM(0xF));
+
+       cs->hw_mode |= CSMODE_LEN(bits_per_word);
+
+       if ((mpc8xxx_spi->spibrg / hz) > 64) {
+               cs->hw_mode |= CSMODE_DIV16;
+               pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1;
+
+               WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. "
+                         "Will use %d Hz instead.\n", dev_name(&spi->dev),
+                         hz, mpc8xxx_spi->spibrg / 1024);
+               if (pm > 16)
+                       pm = 16;
+       } else {
+               pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
+       }
+       if (pm)
+               pm--;
+
+       cs->hw_mode |= CSMODE_PM(pm);
+
+       fsl_espi_change_mode(spi);
+       return 0;
+}
+
+static int fsl_espi_cpu_bufs(struct mpc8xxx_spi *mspi, struct spi_transfer *t,
+               unsigned int len)
+{
+       u32 word;
+       struct fsl_espi_reg *reg_base = mspi->reg_base;
+
+       mspi->count = len;
+
+       /* enable rx ints */
+       mpc8xxx_spi_write_reg(&reg_base->mask, SPIM_NE);
+
+       /* transmit word */
+       word = mspi->get_tx(mspi);
+       mpc8xxx_spi_write_reg(&reg_base->transmit, word);
+
+       return 0;
+}
+
+static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+       struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base;
+       unsigned int len = t->len;
+       u8 bits_per_word;
+       int ret;
+
+       bits_per_word = spi->bits_per_word;
+       if (t->bits_per_word)
+               bits_per_word = t->bits_per_word;
+
+       mpc8xxx_spi->len = t->len;
+       len = roundup(len, 4) / 4;
+
+       mpc8xxx_spi->tx = t->tx_buf;
+       mpc8xxx_spi->rx = t->rx_buf;
+
+       INIT_COMPLETION(mpc8xxx_spi->done);
+
+       /* Set SPCOM[CS] and SPCOM[TRANLEN] field */
+       if ((t->len - 1) > SPCOM_TRANLEN_MAX) {
+               dev_err(mpc8xxx_spi->dev, "Transaction length (%d)"
+                               " beyond the SPCOM[TRANLEN] field\n", t->len);
+               return -EINVAL;
+       }
+       mpc8xxx_spi_write_reg(&reg_base->command,
+               (SPCOM_CS(spi->chip_select) | SPCOM_TRANLEN(t->len - 1)));
+
+       ret = fsl_espi_cpu_bufs(mpc8xxx_spi, t, len);
+       if (ret)
+               return ret;
+
+       wait_for_completion(&mpc8xxx_spi->done);
+
+       /* disable rx ints */
+       mpc8xxx_spi_write_reg(&reg_base->mask, 0);
+
+       return mpc8xxx_spi->count;
+}
+
+static void fsl_espi_addr2cmd(unsigned int addr, u8 *cmd)
+{
+       if (cmd[1] && cmd[2] && cmd[3]) {
+               cmd[1] = (u8)(addr >> 16);
+               cmd[2] = (u8)(addr >> 8);
+               cmd[3] = (u8)(addr >> 0);
+       }
+}
+
+static unsigned int fsl_espi_cmd2addr(u8 *cmd)
+{
+       if (cmd[1] && cmd[2] && cmd[3])
+               return cmd[1] << 16 | cmd[2] << 8 | cmd[3] << 0;
+
+       return 0;
+}
+
+static void fsl_espi_do_trans(struct spi_message *m,
+                               struct fsl_espi_transfer *tr)
+{
+       struct spi_device *spi = m->spi;
+       struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
+       struct fsl_espi_transfer *espi_trans = tr;
+       struct spi_message message;
+       struct spi_transfer *t, *first, trans;
+       int status = 0;
+
+       spi_message_init(&message);
+       memset(&trans, 0, sizeof(trans));
+
+       first = list_first_entry(&m->transfers, struct spi_transfer,
+                       transfer_list);
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if ((first->bits_per_word != t->bits_per_word) ||
+                       (first->speed_hz != t->speed_hz)) {
+                       espi_trans->status = -EINVAL;
+                       dev_err(mspi->dev, "bits_per_word/speed_hz should be"
+                                       " same for the same SPI transfer\n");
+                       return;
+               }
+
+               trans.speed_hz = t->speed_hz;
+               trans.bits_per_word = t->bits_per_word;
+               trans.delay_usecs = max(first->delay_usecs, t->delay_usecs);
+       }
+
+       trans.len = espi_trans->len;
+       trans.tx_buf = espi_trans->tx_buf;
+       trans.rx_buf = espi_trans->rx_buf;
+       spi_message_add_tail(&trans, &message);
+
+       list_for_each_entry(t, &message.transfers, transfer_list) {
+               if (t->bits_per_word || t->speed_hz) {
+                       status = -EINVAL;
+
+                       status = fsl_espi_setup_transfer(spi, t);
+                       if (status < 0)
+                               break;
+               }
+
+               if (t->len)
+                       status = fsl_espi_bufs(spi, t);
+
+               if (status) {
+                       status = -EMSGSIZE;
+                       break;
+               }
+
+               if (t->delay_usecs)
+                       udelay(t->delay_usecs);
+       }
+
+       espi_trans->status = status;
+       fsl_espi_setup_transfer(spi, NULL);
+}
+
+static void fsl_espi_cmd_trans(struct spi_message *m,
+                               struct fsl_espi_transfer *trans, u8 *rx_buff)
+{
+       struct spi_transfer *t;
+       u8 *local_buf;
+       int i = 0;
+       struct fsl_espi_transfer *espi_trans = trans;
+
+       local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL);
+       if (!local_buf) {
+               espi_trans->status = -ENOMEM;
+               return;
+       }
+
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if (t->tx_buf) {
+                       memcpy(local_buf + i, t->tx_buf, t->len);
+                       i += t->len;
+               }
+       }
+
+       espi_trans->tx_buf = local_buf;
+       espi_trans->rx_buf = local_buf + espi_trans->n_tx;
+       fsl_espi_do_trans(m, espi_trans);
+
+       espi_trans->actual_length = espi_trans->len;
+       kfree(local_buf);
+}
+
+static void fsl_espi_rw_trans(struct spi_message *m,
+                               struct fsl_espi_transfer *trans, u8 *rx_buff)
+{
+       struct fsl_espi_transfer *espi_trans = trans;
+       unsigned int n_tx = espi_trans->n_tx;
+       unsigned int n_rx = espi_trans->n_rx;
+       struct spi_transfer *t;
+       u8 *local_buf;
+       u8 *rx_buf = rx_buff;
+       unsigned int trans_len;
+       unsigned int addr;
+       int i, pos, loop;
+
+       local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL);
+       if (!local_buf) {
+               espi_trans->status = -ENOMEM;
+               return;
+       }
+
+       for (pos = 0, loop = 0; pos < n_rx; pos += trans_len, loop++) {
+               trans_len = n_rx - pos;
+               if (trans_len > SPCOM_TRANLEN_MAX - n_tx)
+                       trans_len = SPCOM_TRANLEN_MAX - n_tx;
+
+               i = 0;
+               list_for_each_entry(t, &m->transfers, transfer_list) {
+                       if (t->tx_buf) {
+                               memcpy(local_buf + i, t->tx_buf, t->len);
+                               i += t->len;
+                       }
+               }
+
+               addr = fsl_espi_cmd2addr(local_buf);
+               addr += pos;
+               fsl_espi_addr2cmd(addr, local_buf);
+
+               espi_trans->n_tx = n_tx;
+               espi_trans->n_rx = trans_len;
+               espi_trans->len = trans_len + n_tx;
+               espi_trans->tx_buf = local_buf;
+               espi_trans->rx_buf = local_buf + n_tx;
+               fsl_espi_do_trans(m, espi_trans);
+
+               memcpy(rx_buf + pos, espi_trans->rx_buf + n_tx, trans_len);
+
+               if (loop > 0)
+                       espi_trans->actual_length += espi_trans->len - n_tx;
+               else
+                       espi_trans->actual_length += espi_trans->len;
+       }
+
+       kfree(local_buf);
+}
+
+static void fsl_espi_do_one_msg(struct spi_message *m)
+{
+       struct spi_transfer *t;
+       u8 *rx_buf = NULL;
+       unsigned int n_tx = 0;
+       unsigned int n_rx = 0;
+       struct fsl_espi_transfer espi_trans;
+
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               if (t->tx_buf)
+                       n_tx += t->len;
+               if (t->rx_buf) {
+                       n_rx += t->len;
+                       rx_buf = t->rx_buf;
+               }
+       }
+
+       espi_trans.n_tx = n_tx;
+       espi_trans.n_rx = n_rx;
+       espi_trans.len = n_tx + n_rx;
+       espi_trans.actual_length = 0;
+       espi_trans.status = 0;
+
+       if (!rx_buf)
+               fsl_espi_cmd_trans(m, &espi_trans, NULL);
+       else
+               fsl_espi_rw_trans(m, &espi_trans, rx_buf);
+
+       m->actual_length = espi_trans.actual_length;
+       m->status = espi_trans.status;
+       m->complete(m->context);
+}
+
+static int fsl_espi_setup(struct spi_device *spi)
+{
+       struct mpc8xxx_spi *mpc8xxx_spi;
+       struct fsl_espi_reg *reg_base;
+       int retval;
+       u32 hw_mode;
+       u32 loop_mode;
+       struct spi_mpc8xxx_cs *cs = spi->controller_state;
+
+       if (!spi->max_speed_hz)
+               return -EINVAL;
+
+       if (!cs) {
+               cs = kzalloc(sizeof *cs, GFP_KERNEL);
+               if (!cs)
+                       return -ENOMEM;
+               spi->controller_state = cs;
+       }
+
+       mpc8xxx_spi = spi_master_get_devdata(spi->master);
+       reg_base = mpc8xxx_spi->reg_base;
+
+       hw_mode = cs->hw_mode; /* Save orginal settings */
+       cs->hw_mode = mpc8xxx_spi_read_reg(
+                       &reg_base->csmode[spi->chip_select]);
+       /* mask out bits we are going to set */
+       cs->hw_mode &= ~(CSMODE_CP_BEGIN_EDGECLK | CSMODE_CI_INACTIVEHIGH
+                        | CSMODE_REV);
+
+       if (spi->mode & SPI_CPHA)
+               cs->hw_mode |= CSMODE_CP_BEGIN_EDGECLK;
+       if (spi->mode & SPI_CPOL)
+               cs->hw_mode |= CSMODE_CI_INACTIVEHIGH;
+       if (!(spi->mode & SPI_LSB_FIRST))
+               cs->hw_mode |= CSMODE_REV;
+
+       /* Handle the loop mode */
+       loop_mode = mpc8xxx_spi_read_reg(&reg_base->mode);
+       loop_mode &= ~SPMODE_LOOP;
+       if (spi->mode & SPI_LOOP)
+               loop_mode |= SPMODE_LOOP;
+       mpc8xxx_spi_write_reg(&reg_base->mode, loop_mode);
+
+       retval = fsl_espi_setup_transfer(spi, NULL);
+       if (retval < 0) {
+               cs->hw_mode = hw_mode; /* Restore settings */
+               return retval;
+       }
+       return 0;
+}
+
+void fsl_espi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
+{
+       struct fsl_espi_reg *reg_base = mspi->reg_base;
+
+       /* We need handle RX first */
+       if (events & SPIE_NE) {
+               u32 rx_data;
+
+               /* Spin until RX is done */
+               while (SPIE_RXCNT(events) < min(4, mspi->len)) {
+                       cpu_relax();
+                       events = mpc8xxx_spi_read_reg(&reg_base->event);
+               }
+               mspi->len -= 4;
+
+               rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
+
+               if (mspi->rx)
+                       mspi->get_rx(rx_data, mspi);
+       }
+
+       if (!(events & SPIE_NF)) {
+               int ret;
+
+               /* spin until TX is done */
+               ret = spin_event_timeout(((events = mpc8xxx_spi_read_reg(
+                               &reg_base->event)) & SPIE_NF) == 0, 1000, 0);
+               if (!ret) {
+                       dev_err(mspi->dev, "tired waiting for SPIE_NF\n");
+                       return;
+               }
+       }
+
+       /* Clear the events */
+       mpc8xxx_spi_write_reg(&reg_base->event, events);
+
+       mspi->count -= 1;
+       if (mspi->count) {
+               u32 word = mspi->get_tx(mspi);
+
+               mpc8xxx_spi_write_reg(&reg_base->transmit, word);
+       } else {
+               complete(&mspi->done);
+       }
+}
+
+static irqreturn_t fsl_espi_irq(s32 irq, void *context_data)
+{
+       struct mpc8xxx_spi *mspi = context_data;
+       struct fsl_espi_reg *reg_base = mspi->reg_base;
+       irqreturn_t ret = IRQ_NONE;
+       u32 events;
+
+       /* Get interrupt events(tx/rx) */
+       events = mpc8xxx_spi_read_reg(&reg_base->event);
+       if (events)
+               ret = IRQ_HANDLED;
+
+       dev_vdbg(mspi->dev, "%s: events %x\n", __func__, events);
+
+       fsl_espi_cpu_irq(mspi, events);
+
+       return ret;
+}
+
+static void fsl_espi_remove(struct mpc8xxx_spi *mspi)
+{
+       iounmap(mspi->reg_base);
+}
+
+static struct spi_master * __devinit fsl_espi_probe(struct device *dev,
+               struct resource *mem, unsigned int irq)
+{
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct spi_master *master;
+       struct mpc8xxx_spi *mpc8xxx_spi;
+       struct fsl_espi_reg *reg_base;
+       u32 regval;
+       int i, ret = 0;
+
+       master = spi_alloc_master(dev, sizeof(struct mpc8xxx_spi));
+       if (!master) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       dev_set_drvdata(dev, master);
+
+       ret = mpc8xxx_spi_probe(dev, mem, irq);
+       if (ret)
+               goto err_probe;
+
+       master->setup = fsl_espi_setup;
+
+       mpc8xxx_spi = spi_master_get_devdata(master);
+       mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg;
+       mpc8xxx_spi->spi_remove = fsl_espi_remove;
+
+       mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
+       if (!mpc8xxx_spi->reg_base) {
+               ret = -ENOMEM;
+               goto err_probe;
+       }
+
+       reg_base = mpc8xxx_spi->reg_base;
+
+       /* Register for SPI Interrupt */
+       ret = request_irq(mpc8xxx_spi->irq, fsl_espi_irq,
+                         0, "fsl_espi", mpc8xxx_spi);
+       if (ret)
+               goto free_irq;
+
+       if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
+               mpc8xxx_spi->rx_shift = 16;
+               mpc8xxx_spi->tx_shift = 24;
+       }
+
+       /* SPI controller initializations */
+       mpc8xxx_spi_write_reg(&reg_base->mode, 0);
+       mpc8xxx_spi_write_reg(&reg_base->mask, 0);
+       mpc8xxx_spi_write_reg(&reg_base->command, 0);
+       mpc8xxx_spi_write_reg(&reg_base->event, 0xffffffff);
+
+       /* Init eSPI CS mode register */
+       for (i = 0; i < pdata->max_chipselect; i++)
+               mpc8xxx_spi_write_reg(&reg_base->csmode[i], CSMODE_INIT_VAL);
+
+       /* Enable SPI interface */
+       regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
+
+       mpc8xxx_spi_write_reg(&reg_base->mode, regval);
+
+       ret = spi_register_master(master);
+       if (ret < 0)
+               goto unreg_master;
+
+       dev_info(dev, "at 0x%p (irq = %d)\n", reg_base, mpc8xxx_spi->irq);
+
+       return master;
+
+unreg_master:
+       free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
+free_irq:
+       iounmap(mpc8xxx_spi->reg_base);
+err_probe:
+       spi_master_put(master);
+err:
+       return ERR_PTR(ret);
+}
+
+static int of_fsl_espi_get_chipselects(struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       const u32 *prop;
+       int len;
+
+       prop = of_get_property(np, "fsl,espi-num-chipselects", &len);
+       if (!prop || len < sizeof(*prop)) {
+               dev_err(dev, "No 'fsl,espi-num-chipselects' property\n");
+               return -EINVAL;
+       }
+
+       pdata->max_chipselect = *prop;
+       pdata->cs_control = NULL;
+
+       return 0;
+}
+
+static int __devinit of_fsl_espi_probe(struct platform_device *ofdev,
+                                       const struct of_device_id *ofid)
+{
+       struct device *dev = &ofdev->dev;
+       struct device_node *np = ofdev->dev.of_node;
+       struct spi_master *master;
+       struct resource mem;
+       struct resource irq;
+       int ret = -ENOMEM;
+
+       ret = of_mpc8xxx_spi_probe(ofdev, ofid);
+       if (ret)
+               return ret;
+
+       ret = of_fsl_espi_get_chipselects(dev);
+       if (ret)
+               goto err;
+
+       ret = of_address_to_resource(np, 0, &mem);
+       if (ret)
+               goto err;
+
+       ret = of_irq_to_resource(np, 0, &irq);
+       if (!ret) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       master = fsl_espi_probe(dev, &mem, irq.start);
+       if (IS_ERR(master)) {
+               ret = PTR_ERR(master);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       return ret;
+}
+
+static int __devexit of_fsl_espi_remove(struct platform_device *dev)
+{
+       return mpc8xxx_spi_remove(&dev->dev);
+}
+
+static const struct of_device_id of_fsl_espi_match[] = {
+       { .compatible = "fsl,mpc8536-espi" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, of_fsl_espi_match);
+
+static struct of_platform_driver fsl_espi_driver = {
+       .driver = {
+               .name = "fsl_espi",
+               .owner = THIS_MODULE,
+               .of_match_table = of_fsl_espi_match,
+       },
+       .probe          = of_fsl_espi_probe,
+       .remove         = __devexit_p(of_fsl_espi_remove),
+};
+
+static int __init fsl_espi_init(void)
+{
+       return of_register_platform_driver(&fsl_espi_driver);
+}
+module_init(fsl_espi_init);
+
+static void __exit fsl_espi_exit(void)
+{
+       of_unregister_platform_driver(&fsl_espi_driver);
+}
+module_exit(fsl_espi_exit);
+
+MODULE_AUTHOR("Mingkai Hu");
+MODULE_DESCRIPTION("Enhanced Freescale SPI Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi_fsl_lib.c b/drivers/spi/spi_fsl_lib.c
new file mode 100644 (file)
index 0000000..5cd741f
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Freescale SPI/eSPI controller driver library.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright (C) 2006 Polycom, Inc.
+ *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009  MontaVista Software, Inc.
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/fsl_devices.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/of_platform.h>
+#include <linux/of_spi.h>
+#include <sysdev/fsl_soc.h>
+
+#include "spi_fsl_lib.h"
+
+#define MPC8XXX_SPI_RX_BUF(type)                                         \
+void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
+{                                                                        \
+       type *rx = mpc8xxx_spi->rx;                                       \
+       *rx++ = (type)(data >> mpc8xxx_spi->rx_shift);                    \
+       mpc8xxx_spi->rx = rx;                                             \
+}
+
+#define MPC8XXX_SPI_TX_BUF(type)                               \
+u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \
+{                                                              \
+       u32 data;                                               \
+       const type *tx = mpc8xxx_spi->tx;                       \
+       if (!tx)                                                \
+               return 0;                                       \
+       data = *tx++ << mpc8xxx_spi->tx_shift;                  \
+       mpc8xxx_spi->tx = tx;                                   \
+       return data;                                            \
+}
+
+MPC8XXX_SPI_RX_BUF(u8)
+MPC8XXX_SPI_RX_BUF(u16)
+MPC8XXX_SPI_RX_BUF(u32)
+MPC8XXX_SPI_TX_BUF(u8)
+MPC8XXX_SPI_TX_BUF(u16)
+MPC8XXX_SPI_TX_BUF(u32)
+
+struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata)
+{
+       return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
+}
+
+void mpc8xxx_spi_work(struct work_struct *work)
+{
+       struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
+                                                      work);
+
+       spin_lock_irq(&mpc8xxx_spi->lock);
+       while (!list_empty(&mpc8xxx_spi->queue)) {
+               struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
+                                                  struct spi_message, queue);
+
+               list_del_init(&m->queue);
+               spin_unlock_irq(&mpc8xxx_spi->lock);
+
+               if (mpc8xxx_spi->spi_do_one_msg)
+                       mpc8xxx_spi->spi_do_one_msg(m);
+
+               spin_lock_irq(&mpc8xxx_spi->lock);
+       }
+       spin_unlock_irq(&mpc8xxx_spi->lock);
+}
+
+int mpc8xxx_spi_transfer(struct spi_device *spi,
+                               struct spi_message *m)
+{
+       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+       unsigned long flags;
+
+       m->actual_length = 0;
+       m->status = -EINPROGRESS;
+
+       spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
+       list_add_tail(&m->queue, &mpc8xxx_spi->queue);
+       queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
+       spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
+
+       return 0;
+}
+
+void mpc8xxx_spi_cleanup(struct spi_device *spi)
+{
+       kfree(spi->controller_state);
+}
+
+const char *mpc8xxx_spi_strmode(unsigned int flags)
+{
+       if (flags & SPI_QE_CPU_MODE) {
+               return "QE CPU";
+       } else if (flags & SPI_CPM_MODE) {
+               if (flags & SPI_QE)
+                       return "QE";
+               else if (flags & SPI_CPM2)
+                       return "CPM2";
+               else
+                       return "CPM1";
+       }
+       return "CPU";
+}
+
+int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
+                       unsigned int irq)
+{
+       struct fsl_spi_platform_data *pdata = dev->platform_data;
+       struct spi_master *master;
+       struct mpc8xxx_spi *mpc8xxx_spi;
+       int ret = 0;
+
+       master = dev_get_drvdata(dev);
+
+       /* the spi->mode bits understood by this driver: */
+       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
+                       | SPI_LSB_FIRST | SPI_LOOP;
+
+       master->transfer = mpc8xxx_spi_transfer;
+       master->cleanup = mpc8xxx_spi_cleanup;
+       master->dev.of_node = dev->of_node;
+
+       mpc8xxx_spi = spi_master_get_devdata(master);
+       mpc8xxx_spi->dev = dev;
+       mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
+       mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
+       mpc8xxx_spi->flags = pdata->flags;
+       mpc8xxx_spi->spibrg = pdata->sysclk;
+       mpc8xxx_spi->irq = irq;
+
+       mpc8xxx_spi->rx_shift = 0;
+       mpc8xxx_spi->tx_shift = 0;
+
+       init_completion(&mpc8xxx_spi->done);
+
+       master->bus_num = pdata->bus_num;
+       master->num_chipselect = pdata->max_chipselect;
+
+       spin_lock_init(&mpc8xxx_spi->lock);
+       init_completion(&mpc8xxx_spi->done);
+       INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
+       INIT_LIST_HEAD(&mpc8xxx_spi->queue);
+
+       mpc8xxx_spi->workqueue = create_singlethread_workqueue(
+               dev_name(master->dev.parent));
+       if (mpc8xxx_spi->workqueue == NULL) {
+               ret = -EBUSY;
+               goto err;
+       }
+
+       return 0;
+
+err:
+       return ret;
+}
+
+int __devexit mpc8xxx_spi_remove(struct device *dev)
+{
+       struct mpc8xxx_spi *mpc8xxx_spi;
+       struct spi_master *master;
+
+       master = dev_get_drvdata(dev);
+       mpc8xxx_spi = spi_master_get_devdata(master);
+
+       flush_workqueue(mpc8xxx_spi->workqueue);
+       destroy_workqueue(mpc8xxx_spi->workqueue);
+       spi_unregister_master(master);
+
+       free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
+
+       if (mpc8xxx_spi->spi_remove)
+               mpc8xxx_spi->spi_remove(mpc8xxx_spi);
+
+       return 0;
+}
+
+int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
+                                       const struct of_device_id *ofid)
+{
+       struct device *dev = &ofdev->dev;
+       struct device_node *np = ofdev->dev.of_node;
+       struct mpc8xxx_spi_probe_info *pinfo;
+       struct fsl_spi_platform_data *pdata;
+       const void *prop;
+       int ret = -ENOMEM;
+
+       pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
+       if (!pinfo)
+               return -ENOMEM;
+
+       pdata = &pinfo->pdata;
+       dev->platform_data = pdata;
+
+       /* Allocate bus num dynamically. */
+       pdata->bus_num = -1;
+
+       /* SPI controller is either clocked from QE or SoC clock. */
+       pdata->sysclk = get_brgfreq();
+       if (pdata->sysclk == -1) {
+               pdata->sysclk = fsl_get_sys_freq();
+               if (pdata->sysclk == -1) {
+                       ret = -ENODEV;
+                       goto err;
+               }
+       }
+
+       prop = of_get_property(np, "mode", NULL);
+       if (prop && !strcmp(prop, "cpu-qe"))
+               pdata->flags = SPI_QE_CPU_MODE;
+       else if (prop && !strcmp(prop, "qe"))
+               pdata->flags = SPI_CPM_MODE | SPI_QE;
+       else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
+               pdata->flags = SPI_CPM_MODE | SPI_CPM2;
+       else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
+               pdata->flags = SPI_CPM_MODE | SPI_CPM1;
+
+       return 0;
+
+err:
+       kfree(pinfo);
+       return ret;
+}
diff --git a/drivers/spi/spi_fsl_lib.h b/drivers/spi/spi_fsl_lib.h
new file mode 100644 (file)
index 0000000..281e060
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Freescale SPI/eSPI controller driver library.
+ *
+ * Maintainer: Kumar Gala
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ * Copyright (C) 2006 Polycom, Inc.
+ *
+ * CPM SPI and QE buffer descriptors mode support:
+ * Copyright (c) 2009  MontaVista Software, Inc.
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __SPI_FSL_LIB_H__
+#define __SPI_FSL_LIB_H__
+
+#include <asm/io.h>
+
+/* SPI/eSPI Controller driver's private data. */
+struct mpc8xxx_spi {
+       struct device *dev;
+       void *reg_base;
+
+       /* rx & tx bufs from the spi_transfer */
+       const void *tx;
+       void *rx;
+#ifdef CONFIG_SPI_FSL_ESPI
+       int len;
+#endif
+
+       int subblock;
+       struct spi_pram __iomem *pram;
+       struct cpm_buf_desc __iomem *tx_bd;
+       struct cpm_buf_desc __iomem *rx_bd;
+
+       struct spi_transfer *xfer_in_progress;
+
+       /* dma addresses for CPM transfers */
+       dma_addr_t tx_dma;
+       dma_addr_t rx_dma;
+       bool map_tx_dma;
+       bool map_rx_dma;
+
+       dma_addr_t dma_dummy_tx;
+       dma_addr_t dma_dummy_rx;
+
+       /* functions to deal with different sized buffers */
+       void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
+       u32(*get_tx) (struct mpc8xxx_spi *);
+
+       /* hooks for different controller driver */
+       void (*spi_do_one_msg) (struct spi_message *m);
+       void (*spi_remove) (struct mpc8xxx_spi *mspi);
+
+       unsigned int count;
+       unsigned int irq;
+
+       unsigned nsecs;         /* (clock cycle time)/2 */
+
+       u32 spibrg;             /* SPIBRG input clock */
+       u32 rx_shift;           /* RX data reg shift when in qe mode */
+       u32 tx_shift;           /* TX data reg shift when in qe mode */
+
+       unsigned int flags;
+
+       struct workqueue_struct *workqueue;
+       struct work_struct work;
+
+       struct list_head queue;
+       spinlock_t lock;
+
+       struct completion done;
+};
+
+struct spi_mpc8xxx_cs {
+       /* functions to deal with different sized buffers */
+       void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
+       u32 (*get_tx) (struct mpc8xxx_spi *);
+       u32 rx_shift;           /* RX data reg shift when in qe mode */
+       u32 tx_shift;           /* TX data reg shift when in qe mode */
+       u32 hw_mode;            /* Holds HW mode register settings */
+};
+
+static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
+{
+       out_be32(reg, val);
+}
+
+static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
+{
+       return in_be32(reg);
+}
+
+struct mpc8xxx_spi_probe_info {
+       struct fsl_spi_platform_data pdata;
+       int *gpios;
+       bool *alow_flags;
+};
+
+extern u32 mpc8xxx_spi_tx_buf_u8(struct mpc8xxx_spi *mpc8xxx_spi);
+extern u32 mpc8xxx_spi_tx_buf_u16(struct mpc8xxx_spi *mpc8xxx_spi);
+extern u32 mpc8xxx_spi_tx_buf_u32(struct mpc8xxx_spi *mpc8xxx_spi);
+extern void mpc8xxx_spi_rx_buf_u8(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
+extern void mpc8xxx_spi_rx_buf_u16(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
+extern void mpc8xxx_spi_rx_buf_u32(u32 data, struct mpc8xxx_spi *mpc8xxx_spi);
+
+extern struct mpc8xxx_spi_probe_info *to_of_pinfo(
+               struct fsl_spi_platform_data *pdata);
+extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
+               struct spi_transfer *t, unsigned int len);
+extern int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m);
+extern void mpc8xxx_spi_cleanup(struct spi_device *spi);
+extern const char *mpc8xxx_spi_strmode(unsigned int flags);
+extern int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
+               unsigned int irq);
+extern int mpc8xxx_spi_remove(struct device *dev);
+extern int of_mpc8xxx_spi_probe(struct platform_device *ofdev,
+                               const struct of_device_id *ofid);
+
+#endif /* __SPI_FSL_LIB_H__ */
similarity index 64%
rename from drivers/spi/spi_mpc8xxx.c
rename to drivers/spi/spi_fsl_spi.c
index 1dd86b835cd86a800aa8db8257e4a37422a33b8a..7ca52d3ae8f8bc3d322ec273042960fbdc6a9e9c 100644 (file)
@@ -1,9 +1,10 @@
 /*
- * MPC8xxx SPI controller driver.
+ * Freescale SPI controller driver.
  *
  * Maintainer: Kumar Gala
  *
  * Copyright (C) 2006 Polycom, Inc.
+ * Copyright 2010 Freescale Semiconductor, Inc.
  *
  * CPM SPI and QE buffer descriptors mode support:
  * Copyright (c) 2009  MontaVista Software, Inc.
  * option) any later version.
  */
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/bug.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/completion.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/irq.h>
-#include <linux/device.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_bitbang.h>
 #include <linux/platform_device.h>
 #include <linux/of_platform.h>
 #include <linux/gpio.h>
 #include <linux/of_gpio.h>
-#include <linux/slab.h>
 
 #include <sysdev/fsl_soc.h>
 #include <asm/cpm.h>
 #include <asm/qe.h>
-#include <asm/irq.h>
+
+#include "spi_fsl_lib.h"
 
 /* CPM1 and CPM2 are mutually exclusive. */
 #ifdef CONFIG_CPM1
@@ -55,7 +49,7 @@
 #endif
 
 /* SPI Controller registers */
-struct mpc8xxx_spi_reg {
+struct fsl_spi_reg {
        u8 res1[0x20];
        __be32 mode;
        __be32 event;
@@ -80,7 +74,7 @@ struct mpc8xxx_spi_reg {
 
 /*
  * Default for SPI Mode:
- *     SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
+ *     SPI MODE 0 (inactive low, phase middle, MSB, 8-bit length, slow clk
  */
 #define        SPMODE_INIT_VAL (SPMODE_CI_INACTIVEHIGH | SPMODE_DIV16 | SPMODE_REV | \
                         SPMODE_MS | SPMODE_LEN(7) | SPMODE_PM(0xf))
@@ -102,112 +96,16 @@ struct mpc8xxx_spi_reg {
 #define        SPI_PRAM_SIZE   0x100
 #define        SPI_MRBLR       ((unsigned int)PAGE_SIZE)
 
-/* SPI Controller driver's private data. */
-struct mpc8xxx_spi {
-       struct device *dev;
-       struct mpc8xxx_spi_reg __iomem *base;
-
-       /* rx & tx bufs from the spi_transfer */
-       const void *tx;
-       void *rx;
-
-       int subblock;
-       struct spi_pram __iomem *pram;
-       struct cpm_buf_desc __iomem *tx_bd;
-       struct cpm_buf_desc __iomem *rx_bd;
-
-       struct spi_transfer *xfer_in_progress;
-
-       /* dma addresses for CPM transfers */
-       dma_addr_t tx_dma;
-       dma_addr_t rx_dma;
-       bool map_tx_dma;
-       bool map_rx_dma;
-
-       dma_addr_t dma_dummy_tx;
-       dma_addr_t dma_dummy_rx;
-
-       /* functions to deal with different sized buffers */
-       void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
-       u32(*get_tx) (struct mpc8xxx_spi *);
-
-       unsigned int count;
-       unsigned int irq;
-
-       unsigned nsecs;         /* (clock cycle time)/2 */
-
-       u32 spibrg;             /* SPIBRG input clock */
-       u32 rx_shift;           /* RX data reg shift when in qe mode */
-       u32 tx_shift;           /* TX data reg shift when in qe mode */
-
-       unsigned int flags;
-
-       struct workqueue_struct *workqueue;
-       struct work_struct work;
-
-       struct list_head queue;
-       spinlock_t lock;
-
-       struct completion done;
-};
-
-static void *mpc8xxx_dummy_rx;
-static DEFINE_MUTEX(mpc8xxx_dummy_rx_lock);
-static int mpc8xxx_dummy_rx_refcnt;
-
-struct spi_mpc8xxx_cs {
-       /* functions to deal with different sized buffers */
-       void (*get_rx) (u32 rx_data, struct mpc8xxx_spi *);
-       u32 (*get_tx) (struct mpc8xxx_spi *);
-       u32 rx_shift;           /* RX data reg shift when in qe mode */
-       u32 tx_shift;           /* TX data reg shift when in qe mode */
-       u32 hw_mode;            /* Holds HW mode register settings */
-};
-
-static inline void mpc8xxx_spi_write_reg(__be32 __iomem *reg, u32 val)
-{
-       out_be32(reg, val);
-}
-
-static inline u32 mpc8xxx_spi_read_reg(__be32 __iomem *reg)
-{
-       return in_be32(reg);
-}
-
-#define MPC83XX_SPI_RX_BUF(type)                                         \
-static                                                                   \
-void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
-{                                                                        \
-       type *rx = mpc8xxx_spi->rx;                                       \
-       *rx++ = (type)(data >> mpc8xxx_spi->rx_shift);                    \
-       mpc8xxx_spi->rx = rx;                                             \
-}
-
-#define MPC83XX_SPI_TX_BUF(type)                               \
-static                                                         \
-u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \
-{                                                              \
-       u32 data;                                               \
-       const type *tx = mpc8xxx_spi->tx;                       \
-       if (!tx)                                                \
-               return 0;                                       \
-       data = *tx++ << mpc8xxx_spi->tx_shift;                  \
-       mpc8xxx_spi->tx = tx;                                   \
-       return data;                                            \
-}
+static void *fsl_dummy_rx;
+static DEFINE_MUTEX(fsl_dummy_rx_lock);
+static int fsl_dummy_rx_refcnt;
 
-MPC83XX_SPI_RX_BUF(u8)
-MPC83XX_SPI_RX_BUF(u16)
-MPC83XX_SPI_RX_BUF(u32)
-MPC83XX_SPI_TX_BUF(u8)
-MPC83XX_SPI_TX_BUF(u16)
-MPC83XX_SPI_TX_BUF(u32)
-
-static void mpc8xxx_spi_change_mode(struct spi_device *spi)
+static void fsl_spi_change_mode(struct spi_device *spi)
 {
        struct mpc8xxx_spi *mspi = spi_master_get_devdata(spi->master);
        struct spi_mpc8xxx_cs *cs = spi->controller_state;
-       __be32 __iomem *mode = &mspi->base->mode;
+       struct fsl_spi_reg *reg_base = mspi->reg_base;
+       __be32 __iomem *mode = &reg_base->mode;
        unsigned long flags;
 
        if (cs->hw_mode == mpc8xxx_spi_read_reg(mode))
@@ -238,7 +136,7 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi)
        local_irq_restore(flags);
 }
 
-static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
+static void fsl_spi_chipselect(struct spi_device *spi, int value)
 {
        struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
        struct fsl_spi_platform_data *pdata = spi->dev.parent->platform_data;
@@ -256,18 +154,17 @@ static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
                mpc8xxx_spi->get_rx = cs->get_rx;
                mpc8xxx_spi->get_tx = cs->get_tx;
 
-               mpc8xxx_spi_change_mode(spi);
+               fsl_spi_change_mode(spi);
 
                if (pdata->cs_control)
                        pdata->cs_control(spi, pol);
        }
 }
 
-static int
-mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
-                          struct spi_device *spi,
-                          struct mpc8xxx_spi *mpc8xxx_spi,
-                          int bits_per_word)
+static int mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
+                               struct spi_device *spi,
+                               struct mpc8xxx_spi *mpc8xxx_spi,
+                               int bits_per_word)
 {
        cs->rx_shift = 0;
        cs->tx_shift = 0;
@@ -307,10 +204,9 @@ mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
        return bits_per_word;
 }
 
-static int
-mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
-                         struct spi_device *spi,
-                         int bits_per_word)
+static int mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
+                               struct spi_device *spi,
+                               int bits_per_word)
 {
        /* QE uses Little Endian for words > 8
         * so transform all words > 8 into 8 bits
@@ -326,13 +222,13 @@ mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
        return bits_per_word;
 }
 
-static
-int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+static int fsl_spi_setup_transfer(struct spi_device *spi,
+                                       struct spi_transfer *t)
 {
        struct mpc8xxx_spi *mpc8xxx_spi;
-       int bits_per_word;
+       int bits_per_word = 0;
        u8 pm;
-       u32 hz;
+       u32 hz = 0;
        struct spi_mpc8xxx_cs   *cs = spi->controller_state;
 
        mpc8xxx_spi = spi_master_get_devdata(spi->master);
@@ -340,9 +236,6 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
        if (t) {
                bits_per_word = t->bits_per_word;
                hz = t->speed_hz;
-       } else {
-               bits_per_word = 0;
-               hz = 0;
        }
 
        /* spi_transfer level calls that work per-word */
@@ -388,23 +281,25 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
                          hz, mpc8xxx_spi->spibrg / 1024);
                if (pm > 16)
                        pm = 16;
-       } else
+       } else {
                pm = (mpc8xxx_spi->spibrg - 1) / (hz * 4) + 1;
+       }
        if (pm)
                pm--;
 
        cs->hw_mode |= SPMODE_PM(pm);
 
-       mpc8xxx_spi_change_mode(spi);
+       fsl_spi_change_mode(spi);
        return 0;
 }
 
-static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
+static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
 {
        struct cpm_buf_desc __iomem *tx_bd = mspi->tx_bd;
        struct cpm_buf_desc __iomem *rx_bd = mspi->rx_bd;
        unsigned int xfer_len = min(mspi->count, SPI_MRBLR);
        unsigned int xfer_ofs;
+       struct fsl_spi_reg *reg_base = mspi->reg_base;
 
        xfer_ofs = mspi->xfer_in_progress->len - mspi->count;
 
@@ -424,13 +319,14 @@ static void mpc8xxx_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
                                 BD_SC_LAST);
 
        /* start transfer */
-       mpc8xxx_spi_write_reg(&mspi->base->command, SPCOM_STR);
+       mpc8xxx_spi_write_reg(&reg_base->command, SPCOM_STR);
 }
 
-static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
+static int fsl_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
                                struct spi_transfer *t, bool is_dma_mapped)
 {
        struct device *dev = mspi->dev;
+       struct fsl_spi_reg *reg_base = mspi->reg_base;
 
        if (is_dma_mapped) {
                mspi->map_tx_dma = 0;
@@ -475,13 +371,13 @@ static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
        }
 
        /* enable rx ints */
-       mpc8xxx_spi_write_reg(&mspi->base->mask, SPIE_RXB);
+       mpc8xxx_spi_write_reg(&reg_base->mask, SPIE_RXB);
 
        mspi->xfer_in_progress = t;
        mspi->count = t->len;
 
        /* start CPM transfers */
-       mpc8xxx_spi_cpm_bufs_start(mspi);
+       fsl_spi_cpm_bufs_start(mspi);
 
        return 0;
 
@@ -491,7 +387,7 @@ err_rx_dma:
        return -ENOMEM;
 }
 
-static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
+static void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
 {
        struct device *dev = mspi->dev;
        struct spi_transfer *t = mspi->xfer_in_progress;
@@ -503,31 +399,34 @@ static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
        mspi->xfer_in_progress = NULL;
 }
 
-static int mpc8xxx_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
+static int fsl_spi_cpu_bufs(struct mpc8xxx_spi *mspi,
                                struct spi_transfer *t, unsigned int len)
 {
        u32 word;
+       struct fsl_spi_reg *reg_base = mspi->reg_base;
 
        mspi->count = len;
 
        /* enable rx ints */
-       mpc8xxx_spi_write_reg(&mspi->base->mask, SPIM_NE);
+       mpc8xxx_spi_write_reg(&reg_base->mask, SPIM_NE);
 
        /* transmit word */
        word = mspi->get_tx(mspi);
-       mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
+       mpc8xxx_spi_write_reg(&reg_base->transmit, word);
 
        return 0;
 }
 
-static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
+static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
                            bool is_dma_mapped)
 {
        struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
+       struct fsl_spi_reg *reg_base;
        unsigned int len = t->len;
        u8 bits_per_word;
        int ret;
 
+       reg_base = mpc8xxx_spi->reg_base;
        bits_per_word = spi->bits_per_word;
        if (t->bits_per_word)
                bits_per_word = t->bits_per_word;
@@ -551,24 +450,24 @@ static int mpc8xxx_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
        INIT_COMPLETION(mpc8xxx_spi->done);
 
        if (mpc8xxx_spi->flags & SPI_CPM_MODE)
-               ret = mpc8xxx_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
+               ret = fsl_spi_cpm_bufs(mpc8xxx_spi, t, is_dma_mapped);
        else
-               ret = mpc8xxx_spi_cpu_bufs(mpc8xxx_spi, t, len);
+               ret = fsl_spi_cpu_bufs(mpc8xxx_spi, t, len);
        if (ret)
                return ret;
 
        wait_for_completion(&mpc8xxx_spi->done);
 
        /* disable rx ints */
-       mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
+       mpc8xxx_spi_write_reg(&reg_base->mask, 0);
 
        if (mpc8xxx_spi->flags & SPI_CPM_MODE)
-               mpc8xxx_spi_cpm_bufs_complete(mpc8xxx_spi);
+               fsl_spi_cpm_bufs_complete(mpc8xxx_spi);
 
        return mpc8xxx_spi->count;
 }
 
-static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
+static void fsl_spi_do_one_msg(struct spi_message *m)
 {
        struct spi_device *spi = m->spi;
        struct spi_transfer *t;
@@ -584,18 +483,18 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
                        status = -EINVAL;
 
                        if (cs_change)
-                               status = mpc8xxx_spi_setup_transfer(spi, t);
+                               status = fsl_spi_setup_transfer(spi, t);
                        if (status < 0)
                                break;
                }
 
                if (cs_change) {
-                       mpc8xxx_spi_chipselect(spi, BITBANG_CS_ACTIVE);
+                       fsl_spi_chipselect(spi, BITBANG_CS_ACTIVE);
                        ndelay(nsecs);
                }
                cs_change = t->cs_change;
                if (t->len)
-                       status = mpc8xxx_spi_bufs(spi, t, m->is_dma_mapped);
+                       status = fsl_spi_bufs(spi, t, m->is_dma_mapped);
                if (status) {
                        status = -EMSGSIZE;
                        break;
@@ -607,7 +506,7 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
 
                if (cs_change) {
                        ndelay(nsecs);
-                       mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+                       fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
                        ndelay(nsecs);
                }
        }
@@ -617,35 +516,16 @@ static void mpc8xxx_spi_do_one_msg(struct spi_message *m)
 
        if (status || !cs_change) {
                ndelay(nsecs);
-               mpc8xxx_spi_chipselect(spi, BITBANG_CS_INACTIVE);
+               fsl_spi_chipselect(spi, BITBANG_CS_INACTIVE);
        }
 
-       mpc8xxx_spi_setup_transfer(spi, NULL);
-}
-
-static void mpc8xxx_spi_work(struct work_struct *work)
-{
-       struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
-                                                      work);
-
-       spin_lock_irq(&mpc8xxx_spi->lock);
-       while (!list_empty(&mpc8xxx_spi->queue)) {
-               struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
-                                                  struct spi_message, queue);
-
-               list_del_init(&m->queue);
-               spin_unlock_irq(&mpc8xxx_spi->lock);
-
-               mpc8xxx_spi_do_one_msg(m);
-
-               spin_lock_irq(&mpc8xxx_spi->lock);
-       }
-       spin_unlock_irq(&mpc8xxx_spi->lock);
+       fsl_spi_setup_transfer(spi, NULL);
 }
 
-static int mpc8xxx_spi_setup(struct spi_device *spi)
+static int fsl_spi_setup(struct spi_device *spi)
 {
        struct mpc8xxx_spi *mpc8xxx_spi;
+       struct fsl_spi_reg *reg_base;
        int retval;
        u32 hw_mode;
        struct spi_mpc8xxx_cs   *cs = spi->controller_state;
@@ -661,8 +541,10 @@ static int mpc8xxx_spi_setup(struct spi_device *spi)
        }
        mpc8xxx_spi = spi_master_get_devdata(spi->master);
 
+       reg_base = mpc8xxx_spi->reg_base;
+
        hw_mode = cs->hw_mode; /* Save original settings */
-       cs->hw_mode = mpc8xxx_spi_read_reg(&mpc8xxx_spi->base->mode);
+       cs->hw_mode = mpc8xxx_spi_read_reg(&reg_base->mode);
        /* mask out bits we are going to set */
        cs->hw_mode &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
                         | SPMODE_REV | SPMODE_LOOP);
@@ -676,7 +558,7 @@ static int mpc8xxx_spi_setup(struct spi_device *spi)
        if (spi->mode & SPI_LOOP)
                cs->hw_mode |= SPMODE_LOOP;
 
-       retval = mpc8xxx_spi_setup_transfer(spi, NULL);
+       retval = fsl_spi_setup_transfer(spi, NULL);
        if (retval < 0) {
                cs->hw_mode = hw_mode; /* Restore settings */
                return retval;
@@ -684,9 +566,10 @@ static int mpc8xxx_spi_setup(struct spi_device *spi)
        return 0;
 }
 
-static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
+static void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
 {
        u16 len;
+       struct fsl_spi_reg *reg_base = mspi->reg_base;
 
        dev_dbg(mspi->dev, "%s: bd datlen %d, count %d\n", __func__,
                in_be16(&mspi->rx_bd->cbd_datlen), mspi->count);
@@ -698,20 +581,22 @@ static void mpc8xxx_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
        }
 
        /* Clear the events */
-       mpc8xxx_spi_write_reg(&mspi->base->event, events);
+       mpc8xxx_spi_write_reg(&reg_base->event, events);
 
        mspi->count -= len;
        if (mspi->count)
-               mpc8xxx_spi_cpm_bufs_start(mspi);
+               fsl_spi_cpm_bufs_start(mspi);
        else
                complete(&mspi->done);
 }
 
-static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
+static void fsl_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
 {
+       struct fsl_spi_reg *reg_base = mspi->reg_base;
+
        /* We need handle RX first */
        if (events & SPIE_NE) {
-               u32 rx_data = mpc8xxx_spi_read_reg(&mspi->base->receive);
+               u32 rx_data = mpc8xxx_spi_read_reg(&reg_base->receive);
 
                if (mspi->rx)
                        mspi->get_rx(rx_data, mspi);
@@ -720,102 +605,80 @@ static void mpc8xxx_spi_cpu_irq(struct mpc8xxx_spi *mspi, u32 events)
        if ((events & SPIE_NF) == 0)
                /* spin until TX is done */
                while (((events =
-                       mpc8xxx_spi_read_reg(&mspi->base->event)) &
+                       mpc8xxx_spi_read_reg(&reg_base->event)) &
                                                SPIE_NF) == 0)
                        cpu_relax();
 
        /* Clear the events */
-       mpc8xxx_spi_write_reg(&mspi->base->event, events);
+       mpc8xxx_spi_write_reg(&reg_base->event, events);
 
        mspi->count -= 1;
        if (mspi->count) {
                u32 word = mspi->get_tx(mspi);
 
-               mpc8xxx_spi_write_reg(&mspi->base->transmit, word);
+               mpc8xxx_spi_write_reg(&reg_base->transmit, word);
        } else {
                complete(&mspi->done);
        }
 }
 
-static irqreturn_t mpc8xxx_spi_irq(s32 irq, void *context_data)
+static irqreturn_t fsl_spi_irq(s32 irq, void *context_data)
 {
        struct mpc8xxx_spi *mspi = context_data;
        irqreturn_t ret = IRQ_NONE;
        u32 events;
+       struct fsl_spi_reg *reg_base = mspi->reg_base;
 
        /* Get interrupt events(tx/rx) */
-       events = mpc8xxx_spi_read_reg(&mspi->base->event);
+       events = mpc8xxx_spi_read_reg(&reg_base->event);
        if (events)
                ret = IRQ_HANDLED;
 
        dev_dbg(mspi->dev, "%s: events %x\n", __func__, events);
 
        if (mspi->flags & SPI_CPM_MODE)
-               mpc8xxx_spi_cpm_irq(mspi, events);
+               fsl_spi_cpm_irq(mspi, events);
        else
-               mpc8xxx_spi_cpu_irq(mspi, events);
+               fsl_spi_cpu_irq(mspi, events);
 
        return ret;
 }
 
-static int mpc8xxx_spi_transfer(struct spi_device *spi,
-                               struct spi_message *m)
+static void *fsl_spi_alloc_dummy_rx(void)
 {
-       struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
-       unsigned long flags;
+       mutex_lock(&fsl_dummy_rx_lock);
 
-       m->actual_length = 0;
-       m->status = -EINPROGRESS;
+       if (!fsl_dummy_rx)
+               fsl_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
+       if (fsl_dummy_rx)
+               fsl_dummy_rx_refcnt++;
 
-       spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
-       list_add_tail(&m->queue, &mpc8xxx_spi->queue);
-       queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
-       spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
+       mutex_unlock(&fsl_dummy_rx_lock);
 
-       return 0;
+       return fsl_dummy_rx;
 }
 
-
-static void mpc8xxx_spi_cleanup(struct spi_device *spi)
+static void fsl_spi_free_dummy_rx(void)
 {
-       kfree(spi->controller_state);
-}
+       mutex_lock(&fsl_dummy_rx_lock);
 
-static void *mpc8xxx_spi_alloc_dummy_rx(void)
-{
-       mutex_lock(&mpc8xxx_dummy_rx_lock);
-
-       if (!mpc8xxx_dummy_rx)
-               mpc8xxx_dummy_rx = kmalloc(SPI_MRBLR, GFP_KERNEL);
-       if (mpc8xxx_dummy_rx)
-               mpc8xxx_dummy_rx_refcnt++;
-
-       mutex_unlock(&mpc8xxx_dummy_rx_lock);
-
-       return mpc8xxx_dummy_rx;
-}
-
-static void mpc8xxx_spi_free_dummy_rx(void)
-{
-       mutex_lock(&mpc8xxx_dummy_rx_lock);
-
-       switch (mpc8xxx_dummy_rx_refcnt) {
+       switch (fsl_dummy_rx_refcnt) {
        case 0:
                WARN_ON(1);
                break;
        case 1:
-               kfree(mpc8xxx_dummy_rx);
-               mpc8xxx_dummy_rx = NULL;
+               kfree(fsl_dummy_rx);
+               fsl_dummy_rx = NULL;
                /* fall through */
        default:
-               mpc8xxx_dummy_rx_refcnt--;
+               fsl_dummy_rx_refcnt--;
                break;
        }
 
-       mutex_unlock(&mpc8xxx_dummy_rx_lock);
+       mutex_unlock(&fsl_dummy_rx_lock);
 }
 
-static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
+static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
 {
        struct device *dev = mspi->dev;
        struct device_node *np = dev->of_node;
@@ -869,7 +732,7 @@ static unsigned long mpc8xxx_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
        return pram_ofs;
 }
 
-static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
+static int fsl_spi_cpm_init(struct mpc8xxx_spi *mspi)
 {
        struct device *dev = mspi->dev;
        struct device_node *np = dev->of_node;
@@ -881,7 +744,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
        if (!(mspi->flags & SPI_CPM_MODE))
                return 0;
 
-       if (!mpc8xxx_spi_alloc_dummy_rx())
+       if (!fsl_spi_alloc_dummy_rx())
                return -ENOMEM;
 
        if (mspi->flags & SPI_QE) {
@@ -902,7 +765,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
                }
        }
 
-       pram_ofs = mpc8xxx_spi_cpm_get_pram(mspi);
+       pram_ofs = fsl_spi_cpm_get_pram(mspi);
        if (IS_ERR_VALUE(pram_ofs)) {
                dev_err(dev, "can't allocate spi parameter ram\n");
                goto err_pram;
@@ -922,7 +785,7 @@ static int mpc8xxx_spi_cpm_init(struct mpc8xxx_spi *mspi)
                goto err_dummy_tx;
        }
 
-       mspi->dma_dummy_rx = dma_map_single(dev, mpc8xxx_dummy_rx, SPI_MRBLR,
+       mspi->dma_dummy_rx = dma_map_single(dev, fsl_dummy_rx, SPI_MRBLR,
                                            DMA_FROM_DEVICE);
        if (dma_mapping_error(dev, mspi->dma_dummy_rx)) {
                dev_err(dev, "unable to map dummy rx buffer\n");
@@ -960,11 +823,11 @@ err_dummy_tx:
 err_bds:
        cpm_muram_free(pram_ofs);
 err_pram:
-       mpc8xxx_spi_free_dummy_rx();
+       fsl_spi_free_dummy_rx();
        return -ENOMEM;
 }
 
-static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
+static void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
 {
        struct device *dev = mspi->dev;
 
@@ -972,30 +835,22 @@ static void mpc8xxx_spi_cpm_free(struct mpc8xxx_spi *mspi)
        dma_unmap_single(dev, mspi->dma_dummy_tx, PAGE_SIZE, DMA_TO_DEVICE);
        cpm_muram_free(cpm_muram_offset(mspi->tx_bd));
        cpm_muram_free(cpm_muram_offset(mspi->pram));
-       mpc8xxx_spi_free_dummy_rx();
+       fsl_spi_free_dummy_rx();
 }
 
-static const char *mpc8xxx_spi_strmode(unsigned int flags)
+static void fsl_spi_remove(struct mpc8xxx_spi *mspi)
 {
-       if (flags & SPI_QE_CPU_MODE) {
-               return "QE CPU";
-       } else if (flags & SPI_CPM_MODE) {
-               if (flags & SPI_QE)
-                       return "QE";
-               else if (flags & SPI_CPM2)
-                       return "CPM2";
-               else
-                       return "CPM1";
-       }
-       return "CPU";
+       iounmap(mspi->reg_base);
+       fsl_spi_cpm_free(mspi);
 }
 
-static struct spi_master * __devinit
-mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
+static struct spi_master * __devinit fsl_spi_probe(struct device *dev,
+               struct resource *mem, unsigned int irq)
 {
        struct fsl_spi_platform_data *pdata = dev->platform_data;
        struct spi_master *master;
        struct mpc8xxx_spi *mpc8xxx_spi;
+       struct fsl_spi_reg *reg_base;
        u32 regval;
        int ret = 0;
 
@@ -1007,132 +862,77 @@ mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq)
 
        dev_set_drvdata(dev, master);
 
-       /* the spi->mode bits understood by this driver: */
-       master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
-                       | SPI_LSB_FIRST | SPI_LOOP;
+       ret = mpc8xxx_spi_probe(dev, mem, irq);
+       if (ret)
+               goto err_probe;
 
-       master->setup = mpc8xxx_spi_setup;
-       master->transfer = mpc8xxx_spi_transfer;
-       master->cleanup = mpc8xxx_spi_cleanup;
-       master->dev.of_node = dev->of_node;
+       master->setup = fsl_spi_setup;
 
        mpc8xxx_spi = spi_master_get_devdata(master);
-       mpc8xxx_spi->dev = dev;
-       mpc8xxx_spi->get_rx = mpc8xxx_spi_rx_buf_u8;
-       mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8;
-       mpc8xxx_spi->flags = pdata->flags;
-       mpc8xxx_spi->spibrg = pdata->sysclk;
+       mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg;
+       mpc8xxx_spi->spi_remove = fsl_spi_remove;
+
 
-       ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi);
+       ret = fsl_spi_cpm_init(mpc8xxx_spi);
        if (ret)
                goto err_cpm_init;
 
-       mpc8xxx_spi->rx_shift = 0;
-       mpc8xxx_spi->tx_shift = 0;
        if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) {
                mpc8xxx_spi->rx_shift = 16;
                mpc8xxx_spi->tx_shift = 24;
        }
 
-       init_completion(&mpc8xxx_spi->done);
-
-       mpc8xxx_spi->base = ioremap(mem->start, resource_size(mem));
-       if (mpc8xxx_spi->base == NULL) {
+       mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
+       if (mpc8xxx_spi->reg_base == NULL) {
                ret = -ENOMEM;
                goto err_ioremap;
        }
 
-       mpc8xxx_spi->irq = irq;
-
        /* Register for SPI Interrupt */
-       ret = request_irq(mpc8xxx_spi->irq, mpc8xxx_spi_irq,
-                         0, "mpc8xxx_spi", mpc8xxx_spi);
+       ret = request_irq(mpc8xxx_spi->irq, fsl_spi_irq,
+                         0, "fsl_spi", mpc8xxx_spi);
 
        if (ret != 0)
-               goto unmap_io;
+               goto free_irq;
 
-       master->bus_num = pdata->bus_num;
-       master->num_chipselect = pdata->max_chipselect;
+       reg_base = mpc8xxx_spi->reg_base;
 
        /* SPI controller initializations */
-       mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, 0);
-       mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mask, 0);
-       mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->command, 0);
-       mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->event, 0xffffffff);
+       mpc8xxx_spi_write_reg(&reg_base->mode, 0);
+       mpc8xxx_spi_write_reg(&reg_base->mask, 0);
+       mpc8xxx_spi_write_reg(&reg_base->command, 0);
+       mpc8xxx_spi_write_reg(&reg_base->event, 0xffffffff);
 
        /* Enable SPI interface */
        regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
        if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE)
                regval |= SPMODE_OP;
 
-       mpc8xxx_spi_write_reg(&mpc8xxx_spi->base->mode, regval);
-       spin_lock_init(&mpc8xxx_spi->lock);
-       init_completion(&mpc8xxx_spi->done);
-       INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
-       INIT_LIST_HEAD(&mpc8xxx_spi->queue);
-
-       mpc8xxx_spi->workqueue = create_singlethread_workqueue(
-               dev_name(master->dev.parent));
-       if (mpc8xxx_spi->workqueue == NULL) {
-               ret = -EBUSY;
-               goto free_irq;
-       }
+       mpc8xxx_spi_write_reg(&reg_base->mode, regval);
 
        ret = spi_register_master(master);
        if (ret < 0)
                goto unreg_master;
 
-       dev_info(dev, "at 0x%p (irq = %d), %s mode\n", mpc8xxx_spi->base,
+       dev_info(dev, "at 0x%p (irq = %d), %s mode\n", reg_base,
                 mpc8xxx_spi->irq, mpc8xxx_spi_strmode(mpc8xxx_spi->flags));
 
        return master;
 
 unreg_master:
-       destroy_workqueue(mpc8xxx_spi->workqueue);
-free_irq:
        free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-unmap_io:
-       iounmap(mpc8xxx_spi->base);
+free_irq:
+       iounmap(mpc8xxx_spi->reg_base);
 err_ioremap:
-       mpc8xxx_spi_cpm_free(mpc8xxx_spi);
+       fsl_spi_cpm_free(mpc8xxx_spi);
 err_cpm_init:
+err_probe:
        spi_master_put(master);
 err:
        return ERR_PTR(ret);
 }
 
-static int __devexit mpc8xxx_spi_remove(struct device *dev)
-{
-       struct mpc8xxx_spi *mpc8xxx_spi;
-       struct spi_master *master;
-
-       master = dev_get_drvdata(dev);
-       mpc8xxx_spi = spi_master_get_devdata(master);
-
-       flush_workqueue(mpc8xxx_spi->workqueue);
-       destroy_workqueue(mpc8xxx_spi->workqueue);
-       spi_unregister_master(master);
-
-       free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
-       iounmap(mpc8xxx_spi->base);
-       mpc8xxx_spi_cpm_free(mpc8xxx_spi);
-
-       return 0;
-}
-
-struct mpc8xxx_spi_probe_info {
-       struct fsl_spi_platform_data pdata;
-       int *gpios;
-       bool *alow_flags;
-};
-
-static struct mpc8xxx_spi_probe_info *
-to_of_pinfo(struct fsl_spi_platform_data *pdata)
-{
-       return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
-}
-
-static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
+static void fsl_spi_cs_control(struct spi_device *spi, bool on)
 {
        struct device *dev = spi->dev.parent;
        struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data);
@@ -1143,7 +943,7 @@ static void mpc8xxx_spi_cs_control(struct spi_device *spi, bool on)
        gpio_set_value(gpio, on ^ alow);
 }
 
-static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
+static int of_fsl_spi_get_chipselects(struct device *dev)
 {
        struct device_node *np = dev->of_node;
        struct fsl_spi_platform_data *pdata = dev->platform_data;
@@ -1204,7 +1004,7 @@ static int of_mpc8xxx_spi_get_chipselects(struct device *dev)
        }
 
        pdata->max_chipselect = ngpios;
-       pdata->cs_control = mpc8xxx_spi_cs_control;
+       pdata->cs_control = fsl_spi_cs_control;
 
        return 0;
 
@@ -1223,7 +1023,7 @@ err_alloc_flags:
        return ret;
 }
 
-static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
+static int of_fsl_spi_free_chipselects(struct device *dev)
 {
        struct fsl_spi_platform_data *pdata = dev->platform_data;
        struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata);
@@ -1242,50 +1042,21 @@ static int of_mpc8xxx_spi_free_chipselects(struct device *dev)
        return 0;
 }
 
-static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
-                                         const struct of_device_id *ofid)
+static int __devinit of_fsl_spi_probe(struct platform_device *ofdev,
+                                       const struct of_device_id *ofid)
 {
        struct device *dev = &ofdev->dev;
        struct device_node *np = ofdev->dev.of_node;
-       struct mpc8xxx_spi_probe_info *pinfo;
-       struct fsl_spi_platform_data *pdata;
        struct spi_master *master;
        struct resource mem;
        struct resource irq;
-       const void *prop;
        int ret = -ENOMEM;
 
-       pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL);
-       if (!pinfo)
-               return -ENOMEM;
-
-       pdata = &pinfo->pdata;
-       dev->platform_data = pdata;
-
-       /* Allocate bus num dynamically. */
-       pdata->bus_num = -1;
-
-       /* SPI controller is either clocked from QE or SoC clock. */
-       pdata->sysclk = get_brgfreq();
-       if (pdata->sysclk == -1) {
-               pdata->sysclk = fsl_get_sys_freq();
-               if (pdata->sysclk == -1) {
-                       ret = -ENODEV;
-                       goto err_clk;
-               }
-       }
+       ret = of_mpc8xxx_spi_probe(ofdev, ofid);
+       if (ret)
+               return ret;
 
-       prop = of_get_property(np, "mode", NULL);
-       if (prop && !strcmp(prop, "cpu-qe"))
-               pdata->flags = SPI_QE_CPU_MODE;
-       else if (prop && !strcmp(prop, "qe"))
-               pdata->flags = SPI_CPM_MODE | SPI_QE;
-       else if (of_device_is_compatible(np, "fsl,cpm2-spi"))
-               pdata->flags = SPI_CPM_MODE | SPI_CPM2;
-       else if (of_device_is_compatible(np, "fsl,cpm1-spi"))
-               pdata->flags = SPI_CPM_MODE | SPI_CPM1;
-
-       ret = of_mpc8xxx_spi_get_chipselects(dev);
+       ret = of_fsl_spi_get_chipselects(dev);
        if (ret)
                goto err;
 
@@ -1299,7 +1070,7 @@ static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
                goto err;
        }
 
-       master = mpc8xxx_spi_probe(dev, &mem, irq.start);
+       master = fsl_spi_probe(dev, &mem, irq.start);
        if (IS_ERR(master)) {
                ret = PTR_ERR(master);
                goto err;
@@ -1308,42 +1079,40 @@ static int __devinit of_mpc8xxx_spi_probe(struct platform_device *ofdev,
        return 0;
 
 err:
-       of_mpc8xxx_spi_free_chipselects(dev);
-err_clk:
-       kfree(pinfo);
+       of_fsl_spi_free_chipselects(dev);
        return ret;
 }
 
-static int __devexit of_mpc8xxx_spi_remove(struct platform_device *ofdev)
+static int __devexit of_fsl_spi_remove(struct platform_device *ofdev)
 {
        int ret;
 
        ret = mpc8xxx_spi_remove(&ofdev->dev);
        if (ret)
                return ret;
-       of_mpc8xxx_spi_free_chipselects(&ofdev->dev);
+       of_fsl_spi_free_chipselects(&ofdev->dev);
        return 0;
 }
 
-static const struct of_device_id of_mpc8xxx_spi_match[] = {
+static const struct of_device_id of_fsl_spi_match[] = {
        { .compatible = "fsl,spi" },
-       {},
+       {}
 };
-MODULE_DEVICE_TABLE(of, of_mpc8xxx_spi_match);
+MODULE_DEVICE_TABLE(of, of_fsl_spi_match);
 
-static struct of_platform_driver of_mpc8xxx_spi_driver = {
+static struct of_platform_driver of_fsl_spi_driver = {
        .driver = {
-               .name = "mpc8xxx_spi",
+               .name = "fsl_spi",
                .owner = THIS_MODULE,
-               .of_match_table = of_mpc8xxx_spi_match,
+               .of_match_table = of_fsl_spi_match,
        },
-       .probe          = of_mpc8xxx_spi_probe,
-       .remove         = __devexit_p(of_mpc8xxx_spi_remove),
+       .probe          = of_fsl_spi_probe,
+       .remove         = __devexit_p(of_fsl_spi_remove),
 };
 
 #ifdef CONFIG_MPC832x_RDB
 /*
- *                             XXX XXX XXX
+ * XXX XXX XXX
  * This is "legacy" platform driver, was used by the MPC8323E-RDB boards
  * only. The driver should go away soon, since newer MPC8323E-RDB's device
  * tree can work with OpenFirmware driver. But for now we support old trees
@@ -1366,7 +1135,7 @@ static int __devinit plat_mpc8xxx_spi_probe(struct platform_device *pdev)
        if (irq <= 0)
                return -EINVAL;
 
-       master = mpc8xxx_spi_probe(&pdev->dev, mem, irq);
+       master = fsl_spi_probe(&pdev->dev, mem, irq);
        if (IS_ERR(master))
                return PTR_ERR(master);
        return 0;
@@ -1405,21 +1174,20 @@ static void __init legacy_driver_register(void) {}
 static void __exit legacy_driver_unregister(void) {}
 #endif /* CONFIG_MPC832x_RDB */
 
-static int __init mpc8xxx_spi_init(void)
+static int __init fsl_spi_init(void)
 {
        legacy_driver_register();
-       return of_register_platform_driver(&of_mpc8xxx_spi_driver);
+       return of_register_platform_driver(&of_fsl_spi_driver);
 }
+module_init(fsl_spi_init);
 
-static void __exit mpc8xxx_spi_exit(void)
+static void __exit fsl_spi_exit(void)
 {
-       of_unregister_platform_driver(&of_mpc8xxx_spi_driver);
+       of_unregister_platform_driver(&of_fsl_spi_driver);
        legacy_driver_unregister();
 }
-
-module_init(mpc8xxx_spi_init);
-module_exit(mpc8xxx_spi_exit);
+module_exit(fsl_spi_exit);
 
 MODULE_AUTHOR("Kumar Gala");
-MODULE_DESCRIPTION("Simple MPC8xxx SPI Driver");
+MODULE_DESCRIPTION("Simple Freescale SPI Driver");
 MODULE_LICENSE("GPL");
index 7972e90774738d87d75b835be0a8555d63b78c58..55a38e2c6c137a0530b107bdfe5bc0ac0dd94e7b 100644 (file)
@@ -56,7 +56,28 @@ struct spi_imx_config {
        unsigned int speed_hz;
        unsigned int bpw;
        unsigned int mode;
-       int cs;
+       u8 cs;
+};
+
+enum spi_imx_devtype {
+       SPI_IMX_VER_IMX1,
+       SPI_IMX_VER_0_0,
+       SPI_IMX_VER_0_4,
+       SPI_IMX_VER_0_5,
+       SPI_IMX_VER_0_7,
+       SPI_IMX_VER_2_3,
+       SPI_IMX_VER_AUTODETECT,
+};
+
+struct spi_imx_data;
+
+struct spi_imx_devtype_data {
+       void (*intctrl)(struct spi_imx_data *, int);
+       int (*config)(struct spi_imx_data *, struct spi_imx_config *);
+       void (*trigger)(struct spi_imx_data *);
+       int (*rx_available)(struct spi_imx_data *);
+       void (*reset)(struct spi_imx_data *);
+       unsigned int fifosize;
 };
 
 struct spi_imx_data {
@@ -76,11 +97,7 @@ struct spi_imx_data {
        const void *tx_buf;
        unsigned int txfifo; /* number of words pushed in tx FIFO */
 
-       /* SoC specific functions */
-       void (*intctrl)(struct spi_imx_data *, int);
-       int (*config)(struct spi_imx_data *, struct spi_imx_config *);
-       void (*trigger)(struct spi_imx_data *);
-       int (*rx_available)(struct spi_imx_data *);
+       struct spi_imx_devtype_data devtype_data;
 };
 
 #define MXC_SPI_BUF_RX(type)                                           \
@@ -140,7 +157,7 @@ static unsigned int spi_imx_clkdiv_1(unsigned int fin,
        return max;
 }
 
-/* MX1, MX31, MX35 */
+/* MX1, MX31, MX35, MX51 CSPI */
 static unsigned int spi_imx_clkdiv_2(unsigned int fin,
                unsigned int fspi)
 {
@@ -155,6 +172,128 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
        return 7;
 }
 
+#define SPI_IMX2_3_CTRL                0x08
+#define SPI_IMX2_3_CTRL_ENABLE         (1 <<  0)
+#define SPI_IMX2_3_CTRL_XCH            (1 <<  2)
+#define SPI_IMX2_3_CTRL_MODE(cs)       (1 << ((cs) +  4))
+#define SPI_IMX2_3_CTRL_POSTDIV_OFFSET 8
+#define SPI_IMX2_3_CTRL_PREDIV_OFFSET  12
+#define SPI_IMX2_3_CTRL_CS(cs)         ((cs) << 18)
+#define SPI_IMX2_3_CTRL_BL_OFFSET      20
+
+#define SPI_IMX2_3_CONFIG      0x0c
+#define SPI_IMX2_3_CONFIG_SCLKPHA(cs)  (1 << ((cs) +  0))
+#define SPI_IMX2_3_CONFIG_SCLKPOL(cs)  (1 << ((cs) +  4))
+#define SPI_IMX2_3_CONFIG_SBBCTRL(cs)  (1 << ((cs) +  8))
+#define SPI_IMX2_3_CONFIG_SSBPOL(cs)   (1 << ((cs) + 12))
+
+#define SPI_IMX2_3_INT         0x10
+#define SPI_IMX2_3_INT_TEEN            (1 <<  0)
+#define SPI_IMX2_3_INT_RREN            (1 <<  3)
+
+#define SPI_IMX2_3_STAT                0x18
+#define SPI_IMX2_3_STAT_RR             (1 <<  3)
+
+/* MX51 eCSPI */
+static unsigned int spi_imx2_3_clkdiv(unsigned int fin, unsigned int fspi)
+{
+       /*
+        * there are two 4-bit dividers, the pre-divider divides by
+        * $pre, the post-divider by 2^$post
+        */
+       unsigned int pre, post;
+
+       if (unlikely(fspi > fin))
+               return 0;
+
+       post = fls(fin) - fls(fspi);
+       if (fin > fspi << post)
+               post++;
+
+       /* now we have: (fin <= fspi << post) with post being minimal */
+
+       post = max(4U, post) - 4;
+       if (unlikely(post > 0xf)) {
+               pr_err("%s: cannot set clock freq: %u (base freq: %u)\n",
+                               __func__, fspi, fin);
+               return 0xff;
+       }
+
+       pre = DIV_ROUND_UP(fin, fspi << post) - 1;
+
+       pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
+                       __func__, fin, fspi, post, pre);
+       return (pre << SPI_IMX2_3_CTRL_PREDIV_OFFSET) |
+               (post << SPI_IMX2_3_CTRL_POSTDIV_OFFSET);
+}
+
+static void __maybe_unused spi_imx2_3_intctrl(struct spi_imx_data *spi_imx, int enable)
+{
+       unsigned val = 0;
+
+       if (enable & MXC_INT_TE)
+               val |= SPI_IMX2_3_INT_TEEN;
+
+       if (enable & MXC_INT_RR)
+               val |= SPI_IMX2_3_INT_RREN;
+
+       writel(val, spi_imx->base + SPI_IMX2_3_INT);
+}
+
+static void __maybe_unused spi_imx2_3_trigger(struct spi_imx_data *spi_imx)
+{
+       u32 reg;
+
+       reg = readl(spi_imx->base + SPI_IMX2_3_CTRL);
+       reg |= SPI_IMX2_3_CTRL_XCH;
+       writel(reg, spi_imx->base + SPI_IMX2_3_CTRL);
+}
+
+static int __maybe_unused spi_imx2_3_config(struct spi_imx_data *spi_imx,
+               struct spi_imx_config *config)
+{
+       u32 ctrl = SPI_IMX2_3_CTRL_ENABLE, cfg = 0;
+
+       /* set master mode */
+       ctrl |= SPI_IMX2_3_CTRL_MODE(config->cs);
+
+       /* set clock speed */
+       ctrl |= spi_imx2_3_clkdiv(spi_imx->spi_clk, config->speed_hz);
+
+       /* set chip select to use */
+       ctrl |= SPI_IMX2_3_CTRL_CS(config->cs);
+
+       ctrl |= (config->bpw - 1) << SPI_IMX2_3_CTRL_BL_OFFSET;
+
+       cfg |= SPI_IMX2_3_CONFIG_SBBCTRL(config->cs);
+
+       if (config->mode & SPI_CPHA)
+               cfg |= SPI_IMX2_3_CONFIG_SCLKPHA(config->cs);
+
+       if (config->mode & SPI_CPOL)
+               cfg |= SPI_IMX2_3_CONFIG_SCLKPOL(config->cs);
+
+       if (config->mode & SPI_CS_HIGH)
+               cfg |= SPI_IMX2_3_CONFIG_SSBPOL(config->cs);
+
+       writel(ctrl, spi_imx->base + SPI_IMX2_3_CTRL);
+       writel(cfg, spi_imx->base + SPI_IMX2_3_CONFIG);
+
+       return 0;
+}
+
+static int __maybe_unused spi_imx2_3_rx_available(struct spi_imx_data *spi_imx)
+{
+       return readl(spi_imx->base + SPI_IMX2_3_STAT) & SPI_IMX2_3_STAT_RR;
+}
+
+static void __maybe_unused spi_imx2_3_reset(struct spi_imx_data *spi_imx)
+{
+       /* drain receive buffer */
+       while (spi_imx2_3_rx_available(spi_imx))
+               readl(spi_imx->base + MXC_CSPIRXDATA);
+}
+
 #define MX31_INTREG_TEEN       (1 << 0)
 #define MX31_INTREG_RREN       (1 << 3)
 
@@ -178,7 +317,7 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
  * the i.MX35 has a slightly different register layout for bits
  * we do not use here.
  */
-static void mx31_intctrl(struct spi_imx_data *spi_imx, int enable)
+static void __maybe_unused mx31_intctrl(struct spi_imx_data *spi_imx, int enable)
 {
        unsigned int val = 0;
 
@@ -190,7 +329,7 @@ static void mx31_intctrl(struct spi_imx_data *spi_imx, int enable)
        writel(val, spi_imx->base + MXC_CSPIINT);
 }
 
-static void mx31_trigger(struct spi_imx_data *spi_imx)
+static void __maybe_unused mx31_trigger(struct spi_imx_data *spi_imx)
 {
        unsigned int reg;
 
@@ -199,20 +338,16 @@ static void mx31_trigger(struct spi_imx_data *spi_imx)
        writel(reg, spi_imx->base + MXC_CSPICTRL);
 }
 
-static int mx31_config(struct spi_imx_data *spi_imx,
+static int __maybe_unused spi_imx0_4_config(struct spi_imx_data *spi_imx,
                struct spi_imx_config *config)
 {
        unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
+       int cs = spi_imx->chipselect[config->cs];
 
        reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
                MX31_CSPICTRL_DR_SHIFT;
 
-       if (cpu_is_mx31())
-               reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT;
-       else if (cpu_is_mx25() || cpu_is_mx35()) {
-               reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT;
-               reg |= MX31_CSPICTRL_SSCTL;
-       }
+       reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT;
 
        if (config->mode & SPI_CPHA)
                reg |= MX31_CSPICTRL_PHA;
@@ -220,23 +355,52 @@ static int mx31_config(struct spi_imx_data *spi_imx,
                reg |= MX31_CSPICTRL_POL;
        if (config->mode & SPI_CS_HIGH)
                reg |= MX31_CSPICTRL_SSPOL;
-       if (config->cs < 0) {
-               if (cpu_is_mx31())
-                       reg |= (config->cs + 32) << MX31_CSPICTRL_CS_SHIFT;
-               else if (cpu_is_mx25() || cpu_is_mx35())
-                       reg |= (config->cs + 32) << MX35_CSPICTRL_CS_SHIFT;
-       }
+       if (cs < 0)
+               reg |= (cs + 32) << MX31_CSPICTRL_CS_SHIFT;
+
+       writel(reg, spi_imx->base + MXC_CSPICTRL);
+
+       return 0;
+}
+
+static int __maybe_unused spi_imx0_7_config(struct spi_imx_data *spi_imx,
+               struct spi_imx_config *config)
+{
+       unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
+       int cs = spi_imx->chipselect[config->cs];
+
+       reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
+               MX31_CSPICTRL_DR_SHIFT;
+
+       reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT;
+       reg |= MX31_CSPICTRL_SSCTL;
+
+       if (config->mode & SPI_CPHA)
+               reg |= MX31_CSPICTRL_PHA;
+       if (config->mode & SPI_CPOL)
+               reg |= MX31_CSPICTRL_POL;
+       if (config->mode & SPI_CS_HIGH)
+               reg |= MX31_CSPICTRL_SSPOL;
+       if (cs < 0)
+               reg |= (cs + 32) << MX35_CSPICTRL_CS_SHIFT;
 
        writel(reg, spi_imx->base + MXC_CSPICTRL);
 
        return 0;
 }
 
-static int mx31_rx_available(struct spi_imx_data *spi_imx)
+static int __maybe_unused mx31_rx_available(struct spi_imx_data *spi_imx)
 {
        return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR;
 }
 
+static void __maybe_unused spi_imx0_4_reset(struct spi_imx_data *spi_imx)
+{
+       /* drain receive buffer */
+       while (readl(spi_imx->base + MX3_CSPISTAT) & MX3_CSPISTAT_RR)
+               readl(spi_imx->base + MXC_CSPIRXDATA);
+}
+
 #define MX27_INTREG_RR         (1 << 4)
 #define MX27_INTREG_TEEN       (1 << 9)
 #define MX27_INTREG_RREN       (1 << 13)
@@ -250,7 +414,7 @@ static int mx31_rx_available(struct spi_imx_data *spi_imx)
 #define MX27_CSPICTRL_DR_SHIFT 14
 #define MX27_CSPICTRL_CS_SHIFT 19
 
-static void mx27_intctrl(struct spi_imx_data *spi_imx, int enable)
+static void __maybe_unused mx27_intctrl(struct spi_imx_data *spi_imx, int enable)
 {
        unsigned int val = 0;
 
@@ -262,7 +426,7 @@ static void mx27_intctrl(struct spi_imx_data *spi_imx, int enable)
        writel(val, spi_imx->base + MXC_CSPIINT);
 }
 
-static void mx27_trigger(struct spi_imx_data *spi_imx)
+static void __maybe_unused mx27_trigger(struct spi_imx_data *spi_imx)
 {
        unsigned int reg;
 
@@ -271,10 +435,11 @@ static void mx27_trigger(struct spi_imx_data *spi_imx)
        writel(reg, spi_imx->base + MXC_CSPICTRL);
 }
 
-static int mx27_config(struct spi_imx_data *spi_imx,
+static int __maybe_unused mx27_config(struct spi_imx_data *spi_imx,
                struct spi_imx_config *config)
 {
        unsigned int reg = MX27_CSPICTRL_ENABLE | MX27_CSPICTRL_MASTER;
+       int cs = spi_imx->chipselect[config->cs];
 
        reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz) <<
                MX27_CSPICTRL_DR_SHIFT;
@@ -286,19 +451,24 @@ static int mx27_config(struct spi_imx_data *spi_imx,
                reg |= MX27_CSPICTRL_POL;
        if (config->mode & SPI_CS_HIGH)
                reg |= MX27_CSPICTRL_SSPOL;
-       if (config->cs < 0)
-               reg |= (config->cs + 32) << MX27_CSPICTRL_CS_SHIFT;
+       if (cs < 0)
+               reg |= (cs + 32) << MX27_CSPICTRL_CS_SHIFT;
 
        writel(reg, spi_imx->base + MXC_CSPICTRL);
 
        return 0;
 }
 
-static int mx27_rx_available(struct spi_imx_data *spi_imx)
+static int __maybe_unused mx27_rx_available(struct spi_imx_data *spi_imx)
 {
        return readl(spi_imx->base + MXC_CSPIINT) & MX27_INTREG_RR;
 }
 
+static void __maybe_unused spi_imx0_0_reset(struct spi_imx_data *spi_imx)
+{
+       writel(1, spi_imx->base + MXC_RESET);
+}
+
 #define MX1_INTREG_RR          (1 << 3)
 #define MX1_INTREG_TEEN                (1 << 8)
 #define MX1_INTREG_RREN                (1 << 11)
@@ -310,7 +480,7 @@ static int mx27_rx_available(struct spi_imx_data *spi_imx)
 #define MX1_CSPICTRL_MASTER    (1 << 10)
 #define MX1_CSPICTRL_DR_SHIFT  13
 
-static void mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
+static void __maybe_unused mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
 {
        unsigned int val = 0;
 
@@ -322,7 +492,7 @@ static void mx1_intctrl(struct spi_imx_data *spi_imx, int enable)
        writel(val, spi_imx->base + MXC_CSPIINT);
 }
 
-static void mx1_trigger(struct spi_imx_data *spi_imx)
+static void __maybe_unused mx1_trigger(struct spi_imx_data *spi_imx)
 {
        unsigned int reg;
 
@@ -331,7 +501,7 @@ static void mx1_trigger(struct spi_imx_data *spi_imx)
        writel(reg, spi_imx->base + MXC_CSPICTRL);
 }
 
-static int mx1_config(struct spi_imx_data *spi_imx,
+static int __maybe_unused mx1_config(struct spi_imx_data *spi_imx,
                struct spi_imx_config *config)
 {
        unsigned int reg = MX1_CSPICTRL_ENABLE | MX1_CSPICTRL_MASTER;
@@ -350,11 +520,73 @@ static int mx1_config(struct spi_imx_data *spi_imx,
        return 0;
 }
 
-static int mx1_rx_available(struct spi_imx_data *spi_imx)
+static int __maybe_unused mx1_rx_available(struct spi_imx_data *spi_imx)
 {
        return readl(spi_imx->base + MXC_CSPIINT) & MX1_INTREG_RR;
 }
 
+static void __maybe_unused mx1_reset(struct spi_imx_data *spi_imx)
+{
+       writel(1, spi_imx->base + MXC_RESET);
+}
+
+/*
+ * These version numbers are taken from the Freescale driver.  Unfortunately it
+ * doesn't support i.MX1, so this entry doesn't match the scheme. :-(
+ */
+static struct spi_imx_devtype_data spi_imx_devtype_data[] __devinitdata = {
+#ifdef CONFIG_SPI_IMX_VER_IMX1
+       [SPI_IMX_VER_IMX1] = {
+               .intctrl = mx1_intctrl,
+               .config = mx1_config,
+               .trigger = mx1_trigger,
+               .rx_available = mx1_rx_available,
+               .reset = mx1_reset,
+               .fifosize = 8,
+       },
+#endif
+#ifdef CONFIG_SPI_IMX_VER_0_0
+       [SPI_IMX_VER_0_0] = {
+               .intctrl = mx27_intctrl,
+               .config = mx27_config,
+               .trigger = mx27_trigger,
+               .rx_available = mx27_rx_available,
+               .reset = spi_imx0_0_reset,
+               .fifosize = 8,
+       },
+#endif
+#ifdef CONFIG_SPI_IMX_VER_0_4
+       [SPI_IMX_VER_0_4] = {
+               .intctrl = mx31_intctrl,
+               .config = spi_imx0_4_config,
+               .trigger = mx31_trigger,
+               .rx_available = mx31_rx_available,
+               .reset = spi_imx0_4_reset,
+               .fifosize = 8,
+       },
+#endif
+#ifdef CONFIG_SPI_IMX_VER_0_7
+       [SPI_IMX_VER_0_7] = {
+               .intctrl = mx31_intctrl,
+               .config = spi_imx0_7_config,
+               .trigger = mx31_trigger,
+               .rx_available = mx31_rx_available,
+               .reset = spi_imx0_4_reset,
+               .fifosize = 8,
+       },
+#endif
+#ifdef CONFIG_SPI_IMX_VER_2_3
+       [SPI_IMX_VER_2_3] = {
+               .intctrl = spi_imx2_3_intctrl,
+               .config = spi_imx2_3_config,
+               .trigger = spi_imx2_3_trigger,
+               .rx_available = spi_imx2_3_rx_available,
+               .reset = spi_imx2_3_reset,
+               .fifosize = 64,
+       },
+#endif
+};
+
 static void spi_imx_chipselect(struct spi_device *spi, int is_active)
 {
        struct spi_imx_data *spi_imx = spi_master_get_devdata(spi->master);
@@ -370,21 +602,21 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active)
 
 static void spi_imx_push(struct spi_imx_data *spi_imx)
 {
-       while (spi_imx->txfifo < 8) {
+       while (spi_imx->txfifo < spi_imx->devtype_data.fifosize) {
                if (!spi_imx->count)
                        break;
                spi_imx->tx(spi_imx);
                spi_imx->txfifo++;
        }
 
-       spi_imx->trigger(spi_imx);
+       spi_imx->devtype_data.trigger(spi_imx);
 }
 
 static irqreturn_t spi_imx_isr(int irq, void *dev_id)
 {
        struct spi_imx_data *spi_imx = dev_id;
 
-       while (spi_imx->rx_available(spi_imx)) {
+       while (spi_imx->devtype_data.rx_available(spi_imx)) {
                spi_imx->rx(spi_imx);
                spi_imx->txfifo--;
        }
@@ -398,11 +630,12 @@ static irqreturn_t spi_imx_isr(int irq, void *dev_id)
                /* No data left to push, but still waiting for rx data,
                 * enable receive data available interrupt.
                 */
-               spi_imx->intctrl(spi_imx, MXC_INT_RR);
+               spi_imx->devtype_data.intctrl(
+                               spi_imx, MXC_INT_RR);
                return IRQ_HANDLED;
        }
 
-       spi_imx->intctrl(spi_imx, 0);
+       spi_imx->devtype_data.intctrl(spi_imx, 0);
        complete(&spi_imx->xfer_done);
 
        return IRQ_HANDLED;
@@ -417,7 +650,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
        config.bpw = t ? t->bits_per_word : spi->bits_per_word;
        config.speed_hz  = t ? t->speed_hz : spi->max_speed_hz;
        config.mode = spi->mode;
-       config.cs = spi_imx->chipselect[spi->chip_select];
+       config.cs = spi->chip_select;
 
        if (!config.speed_hz)
                config.speed_hz = spi->max_speed_hz;
@@ -439,7 +672,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
        } else
                BUG();
 
-       spi_imx->config(spi_imx, &config);
+       spi_imx->devtype_data.config(spi_imx, &config);
 
        return 0;
 }
@@ -458,7 +691,7 @@ static int spi_imx_transfer(struct spi_device *spi,
 
        spi_imx_push(spi_imx);
 
-       spi_imx->intctrl(spi_imx, MXC_INT_TE);
+       spi_imx->devtype_data.intctrl(spi_imx, MXC_INT_TE);
 
        wait_for_completion(&spi_imx->xfer_done);
 
@@ -485,6 +718,39 @@ static void spi_imx_cleanup(struct spi_device *spi)
 {
 }
 
+static struct platform_device_id spi_imx_devtype[] = {
+       {
+               .name = DRIVER_NAME,
+               .driver_data = SPI_IMX_VER_AUTODETECT,
+       }, {
+               .name = "imx1-cspi",
+               .driver_data = SPI_IMX_VER_IMX1,
+       }, {
+               .name = "imx21-cspi",
+               .driver_data = SPI_IMX_VER_0_0,
+       }, {
+               .name = "imx25-cspi",
+               .driver_data = SPI_IMX_VER_0_7,
+       }, {
+               .name = "imx27-cspi",
+               .driver_data = SPI_IMX_VER_0_0,
+       }, {
+               .name = "imx31-cspi",
+               .driver_data = SPI_IMX_VER_0_4,
+       }, {
+               .name = "imx35-cspi",
+               .driver_data = SPI_IMX_VER_0_7,
+       }, {
+               .name = "imx51-cspi",
+               .driver_data = SPI_IMX_VER_0_7,
+       }, {
+               .name = "imx51-ecspi",
+               .driver_data = SPI_IMX_VER_2_3,
+       }, {
+               /* sentinel */
+       }
+};
+
 static int __devinit spi_imx_probe(struct platform_device *pdev)
 {
        struct spi_imx_master *mxc_platform_info;
@@ -536,6 +802,31 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
 
        init_completion(&spi_imx->xfer_done);
 
+       if (pdev->id_entry->driver_data == SPI_IMX_VER_AUTODETECT) {
+               if (cpu_is_mx25() || cpu_is_mx35())
+                       spi_imx->devtype_data =
+                               spi_imx_devtype_data[SPI_IMX_VER_0_7];
+               else if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35())
+                       spi_imx->devtype_data =
+                               spi_imx_devtype_data[SPI_IMX_VER_0_4];
+               else if (cpu_is_mx27() || cpu_is_mx21())
+                       spi_imx->devtype_data =
+                               spi_imx_devtype_data[SPI_IMX_VER_0_0];
+               else if (cpu_is_mx1())
+                       spi_imx->devtype_data =
+                               spi_imx_devtype_data[SPI_IMX_VER_IMX1];
+               else
+                       BUG();
+       } else
+               spi_imx->devtype_data =
+                       spi_imx_devtype_data[pdev->id_entry->driver_data];
+
+       if (!spi_imx->devtype_data.intctrl) {
+               dev_err(&pdev->dev, "no support for this device compiled in\n");
+               ret = -ENODEV;
+               goto out_gpio_free;
+       }
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(&pdev->dev, "can't get platform resource\n");
@@ -567,24 +858,6 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
                goto out_iounmap;
        }
 
-       if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35()) {
-               spi_imx->intctrl = mx31_intctrl;
-               spi_imx->config = mx31_config;
-               spi_imx->trigger = mx31_trigger;
-               spi_imx->rx_available = mx31_rx_available;
-       } else  if (cpu_is_mx27() || cpu_is_mx21()) {
-               spi_imx->intctrl = mx27_intctrl;
-               spi_imx->config = mx27_config;
-               spi_imx->trigger = mx27_trigger;
-               spi_imx->rx_available = mx27_rx_available;
-       } else if (cpu_is_mx1()) {
-               spi_imx->intctrl = mx1_intctrl;
-               spi_imx->config = mx1_config;
-               spi_imx->trigger = mx1_trigger;
-               spi_imx->rx_available = mx1_rx_available;
-       } else
-               BUG();
-
        spi_imx->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(spi_imx->clk)) {
                dev_err(&pdev->dev, "unable to get clock\n");
@@ -595,15 +868,9 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
        clk_enable(spi_imx->clk);
        spi_imx->spi_clk = clk_get_rate(spi_imx->clk);
 
-       if (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27())
-               writel(1, spi_imx->base + MXC_RESET);
-
-       /* drain receive buffer */
-       if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35())
-               while (readl(spi_imx->base + MX3_CSPISTAT) & MX3_CSPISTAT_RR)
-                       readl(spi_imx->base + MXC_CSPIRXDATA);
+       spi_imx->devtype_data.reset(spi_imx);
 
-       spi_imx->intctrl(spi_imx, 0);
+       spi_imx->devtype_data.intctrl(spi_imx, 0);
 
        ret = spi_bitbang_start(&spi_imx->bitbang);
        if (ret) {
@@ -668,6 +935,7 @@ static struct platform_driver spi_imx_driver = {
                   .name = DRIVER_NAME,
                   .owner = THIS_MODULE,
                   },
+       .id_table = spi_imx_devtype,
        .probe = spi_imx_probe,
        .remove = __devexit_p(spi_imx_remove),
 };
index c3038da2648aa4e621b0e6127b89c3017724cb55..795828b90f45ebe4eef243d4abccfebee503f2f7 100644 (file)
@@ -261,15 +261,25 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
                chcfg |= S3C64XX_SPI_CH_TXCH_ON;
                if (dma_mode) {
                        modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
-                       s3c2410_dma_config(sdd->tx_dmach, 1);
+                       s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8);
                        s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
                                                xfer->tx_dma, xfer->len);
                        s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
                } else {
-                       unsigned char *buf = (unsigned char *) xfer->tx_buf;
-                       int i = 0;
-                       while (i < xfer->len)
-                               writeb(buf[i++], regs + S3C64XX_SPI_TX_DATA);
+                       switch (sdd->cur_bpw) {
+                       case 32:
+                               iowrite32_rep(regs + S3C64XX_SPI_TX_DATA,
+                                       xfer->tx_buf, xfer->len / 4);
+                               break;
+                       case 16:
+                               iowrite16_rep(regs + S3C64XX_SPI_TX_DATA,
+                                       xfer->tx_buf, xfer->len / 2);
+                               break;
+                       default:
+                               iowrite8_rep(regs + S3C64XX_SPI_TX_DATA,
+                                       xfer->tx_buf, xfer->len);
+                               break;
+                       }
                }
        }
 
@@ -286,7 +296,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
                        writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
                                        | S3C64XX_SPI_PACKET_CNT_EN,
                                        regs + S3C64XX_SPI_PACKET_CNT);
-                       s3c2410_dma_config(sdd->rx_dmach, 1);
+                       s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8);
                        s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
                                                xfer->rx_dma, xfer->len);
                        s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
@@ -366,20 +376,26 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd,
                                return -EIO;
                }
        } else {
-               unsigned char *buf;
-               int i;
-
                /* If it was only Tx */
                if (xfer->rx_buf == NULL) {
                        sdd->state &= ~TXBUSY;
                        return 0;
                }
 
-               i = 0;
-               buf = xfer->rx_buf;
-               while (i < xfer->len)
-                       buf[i++] = readb(regs + S3C64XX_SPI_RX_DATA);
-
+               switch (sdd->cur_bpw) {
+               case 32:
+                       ioread32_rep(regs + S3C64XX_SPI_RX_DATA,
+                               xfer->rx_buf, xfer->len / 4);
+                       break;
+               case 16:
+                       ioread16_rep(regs + S3C64XX_SPI_RX_DATA,
+                               xfer->rx_buf, xfer->len / 2);
+                       break;
+               default:
+                       ioread8_rep(regs + S3C64XX_SPI_RX_DATA,
+                               xfer->rx_buf, xfer->len);
+                       break;
+               }
                sdd->state &= ~RXBUSY;
        }
 
@@ -399,13 +415,18 @@ static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd,
 
 static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 {
+       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        void __iomem *regs = sdd->regs;
        u32 val;
 
        /* Disable Clock */
-       val = readl(regs + S3C64XX_SPI_CLK_CFG);
-       val &= ~S3C64XX_SPI_ENCLK_ENABLE;
-       writel(val, regs + S3C64XX_SPI_CLK_CFG);
+       if (sci->clk_from_cmu) {
+               clk_disable(sdd->src_clk);
+       } else {
+               val = readl(regs + S3C64XX_SPI_CLK_CFG);
+               val &= ~S3C64XX_SPI_ENCLK_ENABLE;
+               writel(val, regs + S3C64XX_SPI_CLK_CFG);
+       }
 
        /* Set Polarity and Phase */
        val = readl(regs + S3C64XX_SPI_CH_CFG);
@@ -429,29 +450,39 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
        switch (sdd->cur_bpw) {
        case 32:
                val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD;
+               val |= S3C64XX_SPI_MODE_CH_TSZ_WORD;
                break;
        case 16:
                val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD;
+               val |= S3C64XX_SPI_MODE_CH_TSZ_HALFWORD;
                break;
        default:
                val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE;
+               val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE;
                break;
        }
-       val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE; /* Always 8bits wide */
 
        writel(val, regs + S3C64XX_SPI_MODE_CFG);
 
-       /* Configure Clock */
-       val = readl(regs + S3C64XX_SPI_CLK_CFG);
-       val &= ~S3C64XX_SPI_PSR_MASK;
-       val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
-                       & S3C64XX_SPI_PSR_MASK);
-       writel(val, regs + S3C64XX_SPI_CLK_CFG);
-
-       /* Enable Clock */
-       val = readl(regs + S3C64XX_SPI_CLK_CFG);
-       val |= S3C64XX_SPI_ENCLK_ENABLE;
-       writel(val, regs + S3C64XX_SPI_CLK_CFG);
+       if (sci->clk_from_cmu) {
+               /* Configure Clock */
+               /* There is half-multiplier before the SPI */
+               clk_set_rate(sdd->src_clk, sdd->cur_speed * 2);
+               /* Enable Clock */
+               clk_enable(sdd->src_clk);
+       } else {
+               /* Configure Clock */
+               val = readl(regs + S3C64XX_SPI_CLK_CFG);
+               val &= ~S3C64XX_SPI_PSR_MASK;
+               val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1)
+                               & S3C64XX_SPI_PSR_MASK);
+               writel(val, regs + S3C64XX_SPI_CLK_CFG);
+
+               /* Enable Clock */
+               val = readl(regs + S3C64XX_SPI_CLK_CFG);
+               val |= S3C64XX_SPI_ENCLK_ENABLE;
+               writel(val, regs + S3C64XX_SPI_CLK_CFG);
+       }
 }
 
 static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
@@ -499,6 +530,7 @@ static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id,
 static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
                                                struct spi_message *msg)
 {
+       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        struct device *dev = &sdd->pdev->dev;
        struct spi_transfer *xfer;
 
@@ -514,6 +546,9 @@ static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
        /* Map until end or first fail */
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
 
+               if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1))
+                       continue;
+
                if (xfer->tx_buf != NULL) {
                        xfer->tx_dma = dma_map_single(dev,
                                        (void *)xfer->tx_buf, xfer->len,
@@ -545,6 +580,7 @@ static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
 static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
                                                struct spi_message *msg)
 {
+       struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
        struct device *dev = &sdd->pdev->dev;
        struct spi_transfer *xfer;
 
@@ -553,6 +589,9 @@ static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd,
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
 
+               if (xfer->len <= ((sci->fifo_lvl_mask >> 1) + 1))
+                       continue;
+
                if (xfer->rx_buf != NULL
                                && xfer->rx_dma != XFER_DMAADDR_INVALID)
                        dma_unmap_single(dev, xfer->rx_dma,
@@ -608,6 +647,14 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
                bpw = xfer->bits_per_word ? : spi->bits_per_word;
                speed = xfer->speed_hz ? : spi->max_speed_hz;
 
+               if (xfer->len % (bpw / 8)) {
+                       dev_err(&spi->dev,
+                               "Xfer length(%u) not a multiple of word size(%u)\n",
+                               xfer->len, bpw / 8);
+                       status = -EIO;
+                       goto out;
+               }
+
                if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) {
                        sdd->cur_bpw = bpw;
                        sdd->cur_speed = speed;
@@ -798,7 +845,6 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        struct s3c64xx_spi_driver_data *sdd;
        struct s3c64xx_spi_info *sci;
        struct spi_message *msg;
-       u32 psr, speed;
        unsigned long flags;
        int err = 0;
 
@@ -841,32 +887,37 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
        }
 
        /* Check if we can provide the requested rate */
-       speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); /* Max possible */
-
-       if (spi->max_speed_hz > speed)
-               spi->max_speed_hz = speed;
-
-       psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
-       psr &= S3C64XX_SPI_PSR_MASK;
-       if (psr == S3C64XX_SPI_PSR_MASK)
-               psr--;
+       if (!sci->clk_from_cmu) {
+               u32 psr, speed;
+
+               /* Max possible */
+               speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1);
+
+               if (spi->max_speed_hz > speed)
+                       spi->max_speed_hz = speed;
+
+               psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1;
+               psr &= S3C64XX_SPI_PSR_MASK;
+               if (psr == S3C64XX_SPI_PSR_MASK)
+                       psr--;
+
+               speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
+               if (spi->max_speed_hz < speed) {
+                       if (psr+1 < S3C64XX_SPI_PSR_MASK) {
+                               psr++;
+                       } else {
+                               err = -EINVAL;
+                               goto setup_exit;
+                       }
+               }
 
-       speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
-       if (spi->max_speed_hz < speed) {
-               if (psr+1 < S3C64XX_SPI_PSR_MASK) {
-                       psr++;
-               } else {
+               speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
+               if (spi->max_speed_hz >= speed)
+                       spi->max_speed_hz = speed;
+               else
                        err = -EINVAL;
-                       goto setup_exit;
-               }
        }
 
-       speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1);
-       if (spi->max_speed_hz >= speed)
-               spi->max_speed_hz = speed;
-       else
-               err = -EINVAL;
-
 setup_exit:
 
        /* setup() returns with device de-selected */
@@ -888,7 +939,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
        /* Disable Interrupts - we use Polling if not DMA mode */
        writel(0, regs + S3C64XX_SPI_INT_EN);
 
-       writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
+       if (!sci->clk_from_cmu)
+               writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
                                regs + S3C64XX_SPI_CLK_CFG);
        writel(0, regs + S3C64XX_SPI_MODE_CFG);
        writel(0, regs + S3C64XX_SPI_PACKET_CNT);
diff --git a/drivers/spi/spi_topcliff_pch.c b/drivers/spi/spi_topcliff_pch.c
new file mode 100644 (file)
index 0000000..58e187f
--- /dev/null
@@ -0,0 +1,1303 @@
+/*
+ * SPI bus driver for the Topcliff PCH used by Intel SoCs
+ *
+ * Copyright (C) 2010 OKI SEMICONDUCTOR Co., 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; 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 <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/spi/spidev.h>
+#include <linux/module.h>
+#include <linux/device.h>
+
+/* Register offsets */
+#define PCH_SPCR               0x00    /* SPI control register */
+#define PCH_SPBRR              0x04    /* SPI baud rate register */
+#define PCH_SPSR               0x08    /* SPI status register */
+#define PCH_SPDWR              0x0C    /* SPI write data register */
+#define PCH_SPDRR              0x10    /* SPI read data register */
+#define PCH_SSNXCR             0x18    /* SSN Expand Control Register */
+#define PCH_SRST               0x1C    /* SPI reset register */
+
+#define PCH_SPSR_TFD           0x000007C0
+#define PCH_SPSR_RFD           0x0000F800
+
+#define PCH_READABLE(x)                (((x) & PCH_SPSR_RFD)>>11)
+#define PCH_WRITABLE(x)                (((x) & PCH_SPSR_TFD)>>6)
+
+#define PCH_RX_THOLD           7
+#define PCH_RX_THOLD_MAX       15
+
+#define PCH_MAX_BAUDRATE       5000000
+#define PCH_MAX_FIFO_DEPTH     16
+
+#define STATUS_RUNNING         1
+#define STATUS_EXITING         2
+#define PCH_SLEEP_TIME         10
+
+#define PCH_ADDRESS_SIZE       0x20
+
+#define SSN_LOW                        0x02U
+#define SSN_NO_CONTROL         0x00U
+#define PCH_MAX_CS             0xFF
+#define PCI_DEVICE_ID_GE_SPI   0x8816
+
+#define SPCR_SPE_BIT           (1 << 0)
+#define SPCR_MSTR_BIT          (1 << 1)
+#define SPCR_LSBF_BIT          (1 << 4)
+#define SPCR_CPHA_BIT          (1 << 5)
+#define SPCR_CPOL_BIT          (1 << 6)
+#define SPCR_TFIE_BIT          (1 << 8)
+#define SPCR_RFIE_BIT          (1 << 9)
+#define SPCR_FIE_BIT           (1 << 10)
+#define SPCR_ORIE_BIT          (1 << 11)
+#define SPCR_MDFIE_BIT         (1 << 12)
+#define SPCR_FICLR_BIT         (1 << 24)
+#define SPSR_TFI_BIT           (1 << 0)
+#define SPSR_RFI_BIT           (1 << 1)
+#define SPSR_FI_BIT            (1 << 2)
+#define SPBRR_SIZE_BIT         (1 << 10)
+
+#define PCH_ALL                        (SPCR_TFIE_BIT|SPCR_RFIE_BIT|SPCR_FIE_BIT|SPCR_ORIE_BIT|SPCR_MDFIE_BIT)
+
+#define SPCR_RFIC_FIELD                20
+#define SPCR_TFIC_FIELD                16
+
+#define SPSR_INT_BITS          0x1F
+#define MASK_SPBRR_SPBR_BITS   (~((1 << 10) - 1))
+#define MASK_RFIC_SPCR_BITS    (~(0xf << 20))
+#define MASK_TFIC_SPCR_BITS    (~(0xf000f << 12))
+
+#define PCH_CLOCK_HZ           50000000
+#define PCH_MAX_SPBR           1023
+
+
+/**
+ * struct pch_spi_data - Holds the SPI channel specific details
+ * @io_remap_addr:             The remapped PCI base address
+ * @master:                    Pointer to the SPI master structure
+ * @work:                      Reference to work queue handler
+ * @wk:                                Workqueue for carrying out execution of the
+ *                             requests
+ * @wait:                      Wait queue for waking up upon receiving an
+ *                             interrupt.
+ * @transfer_complete:         Status of SPI Transfer
+ * @bcurrent_msg_processing:   Status flag for message processing
+ * @lock:                      Lock for protecting this structure
+ * @queue:                     SPI Message queue
+ * @status:                    Status of the SPI driver
+ * @bpw_len:                   Length of data to be transferred in bits per
+ *                             word
+ * @transfer_active:           Flag showing active transfer
+ * @tx_index:                  Transmit data count; for bookkeeping during
+ *                             transfer
+ * @rx_index:                  Receive data count; for bookkeeping during
+ *                             transfer
+ * @tx_buff:                   Buffer for data to be transmitted
+ * @rx_index:                  Buffer for Received data
+ * @n_curnt_chip:              The chip number that this SPI driver currently
+ *                             operates on
+ * @current_chip:              Reference to the current chip that this SPI
+ *                             driver currently operates on
+ * @current_msg:               The current message that this SPI driver is
+ *                             handling
+ * @cur_trans:                 The current transfer that this SPI driver is
+ *                             handling
+ * @board_dat:                 Reference to the SPI device data structure
+ */
+struct pch_spi_data {
+       void __iomem *io_remap_addr;
+       struct spi_master *master;
+       struct work_struct work;
+       struct workqueue_struct *wk;
+       wait_queue_head_t wait;
+       u8 transfer_complete;
+       u8 bcurrent_msg_processing;
+       spinlock_t lock;
+       struct list_head queue;
+       u8 status;
+       u32 bpw_len;
+       u8 transfer_active;
+       u32 tx_index;
+       u32 rx_index;
+       u16 *pkt_tx_buff;
+       u16 *pkt_rx_buff;
+       u8 n_curnt_chip;
+       struct spi_device *current_chip;
+       struct spi_message *current_msg;
+       struct spi_transfer *cur_trans;
+       struct pch_spi_board_data *board_dat;
+};
+
+/**
+ * struct pch_spi_board_data - Holds the SPI device specific details
+ * @pdev:              Pointer to the PCI device
+ * @irq_reg_sts:       Status of IRQ registration
+ * @pci_req_sts:       Status of pci_request_regions
+ * @suspend_sts:       Status of suspend
+ * @data:              Pointer to SPI channel data structure
+ */
+struct pch_spi_board_data {
+       struct pci_dev *pdev;
+       u8 irq_reg_sts;
+       u8 pci_req_sts;
+       u8 suspend_sts;
+       struct pch_spi_data *data;
+};
+
+static struct pci_device_id pch_spi_pcidev_id[] = {
+       {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_GE_SPI)},
+       {0,}
+};
+
+/**
+ * pch_spi_writereg() - Performs  register writes
+ * @master:    Pointer to struct spi_master.
+ * @idx:       Register offset.
+ * @val:       Value to be written to register.
+ */
+static inline void pch_spi_writereg(struct spi_master *master, int idx, u32 val)
+{
+       struct pch_spi_data *data = spi_master_get_devdata(master);
+       iowrite32(val, (data->io_remap_addr + idx));
+}
+
+/**
+ * pch_spi_readreg() - Performs register reads
+ * @master:    Pointer to struct spi_master.
+ * @idx:       Register offset.
+ */
+static inline u32 pch_spi_readreg(struct spi_master *master, int idx)
+{
+       struct pch_spi_data *data = spi_master_get_devdata(master);
+       return ioread32(data->io_remap_addr + idx);
+}
+
+static inline void pch_spi_setclr_reg(struct spi_master *master, int idx,
+                                     u32 set, u32 clr)
+{
+       u32 tmp = pch_spi_readreg(master, idx);
+       tmp = (tmp & ~clr) | set;
+       pch_spi_writereg(master, idx, tmp);
+}
+
+static void pch_spi_set_master_mode(struct spi_master *master)
+{
+       pch_spi_setclr_reg(master, PCH_SPCR, SPCR_MSTR_BIT, 0);
+}
+
+/**
+ * pch_spi_clear_fifo() - Clears the Transmit and Receive FIFOs
+ * @master:    Pointer to struct spi_master.
+ */
+static void pch_spi_clear_fifo(struct spi_master *master)
+{
+       pch_spi_setclr_reg(master, PCH_SPCR, SPCR_FICLR_BIT, 0);
+       pch_spi_setclr_reg(master, PCH_SPCR, 0, SPCR_FICLR_BIT);
+}
+
+static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
+                               void __iomem *io_remap_addr)
+{
+       u32 n_read, tx_index, rx_index, bpw_len;
+       u16 *pkt_rx_buffer, *pkt_tx_buff;
+       int read_cnt;
+       u32 reg_spcr_val;
+       void __iomem *spsr;
+       void __iomem *spdrr;
+       void __iomem *spdwr;
+
+       spsr = io_remap_addr + PCH_SPSR;
+       iowrite32(reg_spsr_val, spsr);
+
+       if (data->transfer_active) {
+               rx_index = data->rx_index;
+               tx_index = data->tx_index;
+               bpw_len = data->bpw_len;
+               pkt_rx_buffer = data->pkt_rx_buff;
+               pkt_tx_buff = data->pkt_tx_buff;
+
+               spdrr = io_remap_addr + PCH_SPDRR;
+               spdwr = io_remap_addr + PCH_SPDWR;
+
+               n_read = PCH_READABLE(reg_spsr_val);
+
+               for (read_cnt = 0; (read_cnt < n_read); read_cnt++) {
+                       pkt_rx_buffer[rx_index++] = ioread32(spdrr);
+                       if (tx_index < bpw_len)
+                               iowrite32(pkt_tx_buff[tx_index++], spdwr);
+               }
+
+               /* disable RFI if not needed */
+               if ((bpw_len - rx_index) <= PCH_MAX_FIFO_DEPTH) {
+                       reg_spcr_val = ioread32(io_remap_addr + PCH_SPCR);
+                       reg_spcr_val &= ~SPCR_RFIE_BIT; /* disable RFI */
+
+                       /* reset rx threshold */
+                       reg_spcr_val &= MASK_RFIC_SPCR_BITS;
+                       reg_spcr_val |= (PCH_RX_THOLD_MAX << SPCR_RFIC_FIELD);
+                       iowrite32(((reg_spcr_val) &= (~(SPCR_RFIE_BIT))),
+                                (io_remap_addr + PCH_SPCR));
+               }
+
+               /* update counts */
+               data->tx_index = tx_index;
+               data->rx_index = rx_index;
+
+       }
+
+       /* if transfer complete interrupt */
+       if (reg_spsr_val & SPSR_FI_BIT) {
+               /* disable FI & RFI interrupts */
+               pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
+                                  SPCR_FIE_BIT | SPCR_TFIE_BIT);
+
+               /* transfer is completed;inform pch_spi_process_messages */
+               data->transfer_complete = true;
+               wake_up(&data->wait);
+       }
+}
+
+/**
+ * pch_spi_handler() - Interrupt handler
+ * @irq:       The interrupt number.
+ * @dev_id:    Pointer to struct pch_spi_board_data.
+ */
+static irqreturn_t pch_spi_handler(int irq, void *dev_id)
+{
+       u32 reg_spsr_val;
+       struct pch_spi_data *data;
+       void __iomem *spsr;
+       void __iomem *io_remap_addr;
+       irqreturn_t ret = IRQ_NONE;
+       struct pch_spi_board_data *board_dat = dev_id;
+
+       if (board_dat->suspend_sts) {
+               dev_dbg(&board_dat->pdev->dev,
+                       "%s returning due to suspend\n", __func__);
+               return IRQ_NONE;
+       }
+
+       data = board_dat->data;
+       io_remap_addr = data->io_remap_addr;
+       spsr = io_remap_addr + PCH_SPSR;
+
+       reg_spsr_val = ioread32(spsr);
+
+       /* Check if the interrupt is for SPI device */
+       if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) {
+               pch_spi_handler_sub(data, reg_spsr_val, io_remap_addr);
+               ret = IRQ_HANDLED;
+       }
+
+       dev_dbg(&board_dat->pdev->dev, "%s EXIT return value=%d\n",
+               __func__, ret);
+
+       return ret;
+}
+
+/**
+ * pch_spi_set_baud_rate() - Sets SPBR field in SPBRR
+ * @master:    Pointer to struct spi_master.
+ * @speed_hz:  Baud rate.
+ */
+static void pch_spi_set_baud_rate(struct spi_master *master, u32 speed_hz)
+{
+       u32 n_spbr = PCH_CLOCK_HZ / (speed_hz * 2);
+
+       /* if baud rate is less than we can support limit it */
+       if (n_spbr > PCH_MAX_SPBR)
+               n_spbr = PCH_MAX_SPBR;
+
+       pch_spi_setclr_reg(master, PCH_SPBRR, n_spbr, ~MASK_SPBRR_SPBR_BITS);
+}
+
+/**
+ * pch_spi_set_bits_per_word() - Sets SIZE field in SPBRR
+ * @master:            Pointer to struct spi_master.
+ * @bits_per_word:     Bits per word for SPI transfer.
+ */
+static void pch_spi_set_bits_per_word(struct spi_master *master,
+                                     u8 bits_per_word)
+{
+       if (bits_per_word == 8)
+               pch_spi_setclr_reg(master, PCH_SPBRR, 0, SPBRR_SIZE_BIT);
+       else
+               pch_spi_setclr_reg(master, PCH_SPBRR, SPBRR_SIZE_BIT, 0);
+}
+
+/**
+ * pch_spi_setup_transfer() - Configures the PCH SPI hardware for transfer
+ * @spi:       Pointer to struct spi_device.
+ */
+static void pch_spi_setup_transfer(struct spi_device *spi)
+{
+       u32 flags = 0;
+
+       dev_dbg(&spi->dev, "%s SPBRR content =%x setting baud rate=%d\n",
+               __func__, pch_spi_readreg(spi->master, PCH_SPBRR),
+               spi->max_speed_hz);
+       pch_spi_set_baud_rate(spi->master, spi->max_speed_hz);
+
+       /* set bits per word */
+       pch_spi_set_bits_per_word(spi->master, spi->bits_per_word);
+
+       if (!(spi->mode & SPI_LSB_FIRST))
+               flags |= SPCR_LSBF_BIT;
+       if (spi->mode & SPI_CPOL)
+               flags |= SPCR_CPOL_BIT;
+       if (spi->mode & SPI_CPHA)
+               flags |= SPCR_CPHA_BIT;
+       pch_spi_setclr_reg(spi->master, PCH_SPCR, flags,
+                          (SPCR_LSBF_BIT | SPCR_CPOL_BIT | SPCR_CPHA_BIT));
+
+       /* Clear the FIFO by toggling  FICLR to 1 and back to 0 */
+       pch_spi_clear_fifo(spi->master);
+}
+
+/**
+ * pch_spi_reset() - Clears SPI registers
+ * @master:    Pointer to struct spi_master.
+ */
+static void pch_spi_reset(struct spi_master *master)
+{
+       /* write 1 to reset SPI */
+       pch_spi_writereg(master, PCH_SRST, 0x1);
+
+       /* clear reset */
+       pch_spi_writereg(master, PCH_SRST, 0x0);
+}
+
+static int pch_spi_setup(struct spi_device *pspi)
+{
+       /* check bits per word */
+       if (pspi->bits_per_word == 0) {
+               pspi->bits_per_word = 8;
+               dev_dbg(&pspi->dev, "%s 8 bits per word\n", __func__);
+       }
+
+       if ((pspi->bits_per_word != 8) && (pspi->bits_per_word != 16)) {
+               dev_err(&pspi->dev, "%s Invalid bits per word\n", __func__);
+               return -EINVAL;
+       }
+
+       /* Check baud rate setting */
+       /* if baud rate of chip is greater than
+          max we can support,return error */
+       if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE)
+               pspi->max_speed_hz = PCH_MAX_BAUDRATE;
+
+       dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__,
+               (pspi->mode) & (SPI_CPOL | SPI_CPHA));
+
+       return 0;
+}
+
+static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg)
+{
+
+       struct spi_transfer *transfer;
+       struct pch_spi_data *data = spi_master_get_devdata(pspi->master);
+       int retval;
+       unsigned long flags;
+
+       /* validate spi message and baud rate */
+       if (unlikely(list_empty(&pmsg->transfers) == 1)) {
+               dev_err(&pspi->dev, "%s list empty\n", __func__);
+               retval = -EINVAL;
+               goto err_out;
+       }
+
+       if (unlikely(pspi->max_speed_hz == 0)) {
+               dev_err(&pspi->dev, "%s pch_spi_tranfer maxspeed=%d\n",
+                       __func__, pspi->max_speed_hz);
+               retval = -EINVAL;
+               goto err_out;
+       }
+
+       dev_dbg(&pspi->dev, "%s Transfer List not empty. "
+               "Transfer Speed is set.\n", __func__);
+
+       /* validate Tx/Rx buffers and Transfer length */
+       list_for_each_entry(transfer, &pmsg->transfers, transfer_list) {
+               if (!transfer->tx_buf && !transfer->rx_buf) {
+                       dev_err(&pspi->dev,
+                               "%s Tx and Rx buffer NULL\n", __func__);
+                       retval = -EINVAL;
+                       goto err_out;
+               }
+
+               if (!transfer->len) {
+                       dev_err(&pspi->dev, "%s Transfer length invalid\n",
+                               __func__);
+                       retval = -EINVAL;
+                       goto err_out;
+               }
+
+               dev_dbg(&pspi->dev, "%s Tx/Rx buffer valid. Transfer length"
+                       " valid\n", __func__);
+
+               /* if baud rate hs been specified validate the same */
+               if (transfer->speed_hz > PCH_MAX_BAUDRATE)
+                       transfer->speed_hz = PCH_MAX_BAUDRATE;
+
+               /* if bits per word has been specified validate the same */
+               if (transfer->bits_per_word) {
+                       if ((transfer->bits_per_word != 8)
+                           && (transfer->bits_per_word != 16)) {
+                               retval = -EINVAL;
+                               dev_err(&pspi->dev,
+                                       "%s Invalid bits per word\n", __func__);
+                               goto err_out;
+                       }
+               }
+       }
+
+       spin_lock_irqsave(&data->lock, flags);
+
+       /* We won't process any messages if we have been asked to terminate */
+       if (data->status == STATUS_EXITING) {
+               dev_err(&pspi->dev, "%s status = STATUS_EXITING.\n", __func__);
+               retval = -ESHUTDOWN;
+               goto err_return_spinlock;
+       }
+
+       /* If suspended ,return -EINVAL */
+       if (data->board_dat->suspend_sts) {
+               dev_err(&pspi->dev, "%s suspend; returning EINVAL\n", __func__);
+               retval = -EINVAL;
+               goto err_return_spinlock;
+       }
+
+       /* set status of message */
+       pmsg->actual_length = 0;
+       dev_dbg(&pspi->dev, "%s - pmsg->status =%d\n", __func__, pmsg->status);
+
+       pmsg->status = -EINPROGRESS;
+
+       /* add message to queue */
+       list_add_tail(&pmsg->queue, &data->queue);
+       dev_dbg(&pspi->dev, "%s - Invoked list_add_tail\n", __func__);
+
+       /* schedule work queue to run */
+       queue_work(data->wk, &data->work);
+       dev_dbg(&pspi->dev, "%s - Invoked queue work\n", __func__);
+
+       retval = 0;
+
+err_return_spinlock:
+       spin_unlock_irqrestore(&data->lock, flags);
+err_out:
+       dev_dbg(&pspi->dev, "%s RETURN=%d\n", __func__, retval);
+       return retval;
+}
+
+static inline void pch_spi_select_chip(struct pch_spi_data *data,
+                                      struct spi_device *pspi)
+{
+       if (data->current_chip != NULL) {
+               if (pspi->chip_select != data->n_curnt_chip) {
+                       dev_dbg(&pspi->dev, "%s : different slave\n", __func__);
+                       data->current_chip = NULL;
+               }
+       }
+
+       data->current_chip = pspi;
+
+       data->n_curnt_chip = data->current_chip->chip_select;
+
+       dev_dbg(&pspi->dev, "%s :Invoking pch_spi_setup_transfer\n", __func__);
+       pch_spi_setup_transfer(pspi);
+}
+
+static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw,
+                          struct spi_message **ppmsg)
+{
+       int size;
+       u32 n_writes;
+       int j;
+       struct spi_message *pmsg;
+       const u8 *tx_buf;
+       const u16 *tx_sbuf;
+
+       pmsg = *ppmsg;
+
+       /* set baud rate if needed */
+       if (data->cur_trans->speed_hz) {
+               dev_dbg(&data->master->dev, "%s:setting baud rate\n", __func__);
+               pch_spi_set_baud_rate(data->master, data->cur_trans->speed_hz);
+       }
+
+       /* set bits per word if needed */
+       if (data->cur_trans->bits_per_word &&
+           (data->current_msg->spi->bits_per_word != data->cur_trans->bits_per_word)) {
+               dev_dbg(&data->master->dev, "%s:set bits per word\n", __func__);
+               pch_spi_set_bits_per_word(data->master,
+                                         data->cur_trans->bits_per_word);
+               *bpw = data->cur_trans->bits_per_word;
+       } else {
+               *bpw = data->current_msg->spi->bits_per_word;
+       }
+
+       /* reset Tx/Rx index */
+       data->tx_index = 0;
+       data->rx_index = 0;
+
+       data->bpw_len = data->cur_trans->len / (*bpw / 8);
+
+       /* find alloc size */
+       size = data->cur_trans->len * sizeof(*data->pkt_tx_buff);
+
+       /* allocate memory for pkt_tx_buff & pkt_rx_buffer */
+       data->pkt_tx_buff = kzalloc(size, GFP_KERNEL);
+       if (data->pkt_tx_buff != NULL) {
+               data->pkt_rx_buff = kzalloc(size, GFP_KERNEL);
+               if (!data->pkt_rx_buff)
+                       kfree(data->pkt_tx_buff);
+       }
+
+       if (!data->pkt_rx_buff) {
+               /* flush queue and set status of all transfers to -ENOMEM */
+               dev_err(&data->master->dev, "%s :kzalloc failed\n", __func__);
+               list_for_each_entry(pmsg, data->queue.next, queue) {
+                       pmsg->status = -ENOMEM;
+
+                       if (pmsg->complete != 0)
+                               pmsg->complete(pmsg->context);
+
+                       /* delete from queue */
+                       list_del_init(&pmsg->queue);
+               }
+               return;
+       }
+
+       /* copy Tx Data */
+       if (data->cur_trans->tx_buf != NULL) {
+               if (*bpw == 8) {
+                       tx_buf = data->cur_trans->tx_buf;
+                       for (j = 0; j < data->bpw_len; j++)
+                               data->pkt_tx_buff[j] = *tx_buf++;
+               } else {
+                       tx_sbuf = data->cur_trans->tx_buf;
+                       for (j = 0; j < data->bpw_len; j++)
+                               data->pkt_tx_buff[j] = *tx_sbuf++;
+               }
+       }
+
+       /* if len greater than PCH_MAX_FIFO_DEPTH, write 16,else len bytes */
+       n_writes = data->bpw_len;
+       if (n_writes > PCH_MAX_FIFO_DEPTH)
+               n_writes = PCH_MAX_FIFO_DEPTH;
+
+       dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing "
+               "0x2 to SSNXCR\n", __func__);
+       pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW);
+
+       for (j = 0; j < n_writes; j++)
+               pch_spi_writereg(data->master, PCH_SPDWR, data->pkt_tx_buff[j]);
+
+       /* update tx_index */
+       data->tx_index = j;
+
+       /* reset transfer complete flag */
+       data->transfer_complete = false;
+       data->transfer_active = true;
+}
+
+
+static void pch_spi_nomore_transfer(struct pch_spi_data *data,
+                                               struct spi_message *pmsg)
+{
+       dev_dbg(&data->master->dev, "%s called\n", __func__);
+       /* Invoke complete callback
+        * [To the spi core..indicating end of transfer] */
+       data->current_msg->status = 0;
+
+       if (data->current_msg->complete != 0) {
+               dev_dbg(&data->master->dev,
+                       "%s:Invoking callback of SPI core\n", __func__);
+               data->current_msg->complete(data->current_msg->context);
+       }
+
+       /* update status in global variable */
+       data->bcurrent_msg_processing = false;
+
+       dev_dbg(&data->master->dev,
+               "%s:data->bcurrent_msg_processing = false\n", __func__);
+
+       data->current_msg = NULL;
+       data->cur_trans = NULL;
+
+       /* check if we have items in list and not suspending
+        * return 1 if list empty */
+       if ((list_empty(&data->queue) == 0) &&
+           (!data->board_dat->suspend_sts) &&
+           (data->status != STATUS_EXITING)) {
+               /* We have some more work to do (either there is more tranint
+                * bpw;sfer requests in the current message or there are
+                *more messages)
+                */
+               dev_dbg(&data->master->dev, "%s:Invoke queue_work\n", __func__);
+               queue_work(data->wk, &data->work);
+       } else if (data->board_dat->suspend_sts ||
+                  data->status == STATUS_EXITING) {
+               dev_dbg(&data->master->dev,
+                       "%s suspend/remove initiated, flushing queue\n",
+                       __func__);
+               list_for_each_entry(pmsg, data->queue.next, queue) {
+                       pmsg->status = -EIO;
+
+                       if (pmsg->complete)
+                               pmsg->complete(pmsg->context);
+
+                       /* delete from queue */
+                       list_del_init(&pmsg->queue);
+               }
+       }
+}
+
+static void pch_spi_set_ir(struct pch_spi_data *data)
+{
+       /* enable interrupts */
+       if ((data->bpw_len) > PCH_MAX_FIFO_DEPTH) {
+               /* set receive threhold to PCH_RX_THOLD */
+               pch_spi_setclr_reg(data->master, PCH_SPCR,
+                                  PCH_RX_THOLD << SPCR_TFIC_FIELD,
+                                  ~MASK_TFIC_SPCR_BITS);
+               /* enable FI and RFI interrupts */
+               pch_spi_setclr_reg(data->master, PCH_SPCR,
+                                  SPCR_RFIE_BIT | SPCR_TFIE_BIT, 0);
+       } else {
+               /* set receive threhold to maximum */
+               pch_spi_setclr_reg(data->master, PCH_SPCR,
+                                  PCH_RX_THOLD_MAX << SPCR_TFIC_FIELD,
+                                  ~MASK_TFIC_SPCR_BITS);
+               /* enable FI interrupt */
+               pch_spi_setclr_reg(data->master, PCH_SPCR, SPCR_FIE_BIT, 0);
+       }
+
+       dev_dbg(&data->master->dev,
+               "%s:invoking pch_spi_set_enable to enable SPI\n", __func__);
+
+       /* SPI set enable */
+       pch_spi_setclr_reg(data->current_chip->master, PCH_SPCR, SPCR_SPE_BIT, 0);
+
+       /* Wait until the transfer completes; go to sleep after
+                                initiating the transfer. */
+       dev_dbg(&data->master->dev,
+               "%s:waiting for transfer to get over\n", __func__);
+
+       wait_event_interruptible(data->wait, data->transfer_complete);
+
+       pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL);
+       dev_dbg(&data->master->dev,
+               "%s:no more control over SSN-writing 0 to SSNXCR.", __func__);
+
+       data->transfer_active = false;
+       dev_dbg(&data->master->dev,
+               "%s set data->transfer_active = false\n", __func__);
+
+       /* clear all interrupts */
+       pch_spi_writereg(data->master, PCH_SPSR,
+                        pch_spi_readreg(data->master, PCH_SPSR));
+       /* disable interrupts */
+       pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL);
+}
+
+static void pch_spi_copy_rx_data(struct pch_spi_data *data, int bpw)
+{
+       int j;
+       u8 *rx_buf;
+       u16 *rx_sbuf;
+
+       /* copy Rx Data */
+       if (!data->cur_trans->rx_buf)
+               return;
+
+       if (bpw == 8) {
+               rx_buf = data->cur_trans->rx_buf;
+               for (j = 0; j < data->bpw_len; j++)
+                       *rx_buf++ = data->pkt_rx_buff[j] & 0xFF;
+       } else {
+               rx_sbuf = data->cur_trans->rx_buf;
+               for (j = 0; j < data->bpw_len; j++)
+                       *rx_sbuf++ = data->pkt_rx_buff[j];
+       }
+}
+
+
+static void pch_spi_process_messages(struct work_struct *pwork)
+{
+       struct spi_message *pmsg;
+       struct pch_spi_data *data;
+       int bpw;
+
+       data = container_of(pwork, struct pch_spi_data, work);
+       dev_dbg(&data->master->dev, "%s data initialized\n", __func__);
+
+       spin_lock(&data->lock);
+
+       /* check if suspend has been initiated;if yes flush queue */
+       if (data->board_dat->suspend_sts || (data->status == STATUS_EXITING)) {
+               dev_dbg(&data->master->dev,
+                       "%s suspend/remove initiated,flushing queue\n",
+                       __func__);
+
+               list_for_each_entry(pmsg, data->queue.next, queue) {
+                       pmsg->status = -EIO;
+
+                       if (pmsg->complete != 0) {
+                               spin_unlock(&data->lock);
+                               pmsg->complete(pmsg->context);
+                               spin_lock(&data->lock);
+                       }
+
+                       /* delete from queue */
+                       list_del_init(&pmsg->queue);
+               }
+
+               spin_unlock(&data->lock);
+               return;
+       }
+
+       data->bcurrent_msg_processing = true;
+       dev_dbg(&data->master->dev,
+               "%s Set data->bcurrent_msg_processing= true\n", __func__);
+
+       /* Get the message from the queue and delete it from there. */
+       data->current_msg = list_entry(data->queue.next, struct spi_message,
+                                       queue);
+
+       list_del_init(&data->current_msg->queue);
+
+       data->current_msg->status = 0;
+
+       pch_spi_select_chip(data, data->current_msg->spi);
+
+       spin_unlock(&data->lock);
+
+       do {
+               /* If we are already processing a message get the next
+               transfer structure from the message otherwise retrieve
+               the 1st transfer request from the message. */
+               spin_lock(&data->lock);
+
+               if (data->cur_trans == NULL) {
+                       data->cur_trans =
+                           list_entry(data->current_msg->transfers.
+                                      next, struct spi_transfer,
+                                      transfer_list);
+                       dev_dbg(&data->master->dev,
+                               "%s :Getting 1st transfer message\n", __func__);
+               } else {
+                       data->cur_trans =
+                           list_entry(data->cur_trans->transfer_list.next,
+                                      struct spi_transfer,
+                                      transfer_list);
+                       dev_dbg(&data->master->dev,
+                               "%s :Getting next transfer message\n",
+                               __func__);
+               }
+
+               spin_unlock(&data->lock);
+
+               pch_spi_set_tx(data, &bpw, &pmsg);
+
+               /* Control interrupt*/
+               pch_spi_set_ir(data);
+
+               /* Disable SPI transfer */
+               pch_spi_setclr_reg(data->current_chip->master, PCH_SPCR, 0,
+                                  SPCR_SPE_BIT);
+
+               /* clear FIFO */
+               pch_spi_clear_fifo(data->master);
+
+               /* copy Rx Data */
+               pch_spi_copy_rx_data(data, bpw);
+
+               /* free memory */
+               kfree(data->pkt_rx_buff);
+               data->pkt_rx_buff = NULL;
+
+               kfree(data->pkt_tx_buff);
+               data->pkt_tx_buff = NULL;
+
+               /* increment message count */
+               data->current_msg->actual_length += data->cur_trans->len;
+
+               dev_dbg(&data->master->dev,
+                       "%s:data->current_msg->actual_length=%d\n",
+                       __func__, data->current_msg->actual_length);
+
+               /* check for delay */
+               if (data->cur_trans->delay_usecs) {
+                       dev_dbg(&data->master->dev, "%s:"
+                               "delay in usec=%d\n", __func__,
+                               data->cur_trans->delay_usecs);
+                       udelay(data->cur_trans->delay_usecs);
+               }
+
+               spin_lock(&data->lock);
+
+               /* No more transfer in this message. */
+               if ((data->cur_trans->transfer_list.next) ==
+                   &(data->current_msg->transfers)) {
+                       pch_spi_nomore_transfer(data, pmsg);
+               }
+
+               spin_unlock(&data->lock);
+
+       } while (data->cur_trans != NULL);
+}
+
+static void pch_spi_free_resources(struct pch_spi_board_data *board_dat)
+{
+       dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__);
+
+       /* free workqueue */
+       if (board_dat->data->wk != NULL) {
+               destroy_workqueue(board_dat->data->wk);
+               board_dat->data->wk = NULL;
+               dev_dbg(&board_dat->pdev->dev,
+                       "%s destroy_workqueue invoked successfully\n",
+                       __func__);
+       }
+
+       /* disable interrupts & free IRQ */
+       if (board_dat->irq_reg_sts) {
+               /* disable interrupts */
+               pch_spi_setclr_reg(board_dat->data->master, PCH_SPCR, 0,
+                                  PCH_ALL);
+
+               /* free IRQ */
+               free_irq(board_dat->pdev->irq, board_dat);
+
+               dev_dbg(&board_dat->pdev->dev,
+                       "%s free_irq invoked successfully\n", __func__);
+
+               board_dat->irq_reg_sts = false;
+       }
+
+       /* unmap PCI base address */
+       if (board_dat->data->io_remap_addr != 0) {
+               pci_iounmap(board_dat->pdev, board_dat->data->io_remap_addr);
+
+               board_dat->data->io_remap_addr = 0;
+
+               dev_dbg(&board_dat->pdev->dev,
+                       "%s pci_iounmap invoked successfully\n", __func__);
+       }
+
+       /* release PCI region */
+       if (board_dat->pci_req_sts) {
+               pci_release_regions(board_dat->pdev);
+               dev_dbg(&board_dat->pdev->dev,
+                       "%s pci_release_regions invoked successfully\n",
+                       __func__);
+               board_dat->pci_req_sts = false;
+       }
+}
+
+static int pch_spi_get_resources(struct pch_spi_board_data *board_dat)
+{
+       void __iomem *io_remap_addr;
+       int retval;
+       dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__);
+
+       /* create workqueue */
+       board_dat->data->wk = create_singlethread_workqueue(KBUILD_MODNAME);
+       if (!board_dat->data->wk) {
+               dev_err(&board_dat->pdev->dev,
+                       "%s create_singlet hread_workqueue failed\n", __func__);
+               retval = -EBUSY;
+               goto err_return;
+       }
+
+       dev_dbg(&board_dat->pdev->dev,
+               "%s create_singlethread_workqueue success\n", __func__);
+
+       retval = pci_request_regions(board_dat->pdev, KBUILD_MODNAME);
+       if (retval != 0) {
+               dev_err(&board_dat->pdev->dev,
+                       "%s request_region failed\n", __func__);
+               goto err_return;
+       }
+
+       board_dat->pci_req_sts = true;
+
+       io_remap_addr = pci_iomap(board_dat->pdev, 1, 0);
+       if (io_remap_addr == 0) {
+               dev_err(&board_dat->pdev->dev,
+                       "%s pci_iomap failed\n", __func__);
+               retval = -ENOMEM;
+               goto err_return;
+       }
+
+       /* calculate base address for all channels */
+       board_dat->data->io_remap_addr = io_remap_addr;
+
+       /* reset PCH SPI h/w */
+       pch_spi_reset(board_dat->data->master);
+       dev_dbg(&board_dat->pdev->dev,
+               "%s pch_spi_reset invoked successfully\n", __func__);
+
+       /* register IRQ */
+       retval = request_irq(board_dat->pdev->irq, pch_spi_handler,
+                            IRQF_SHARED, KBUILD_MODNAME, board_dat);
+       if (retval != 0) {
+               dev_err(&board_dat->pdev->dev,
+                       "%s request_irq failed\n", __func__);
+               goto err_return;
+       }
+
+       dev_dbg(&board_dat->pdev->dev, "%s request_irq returned=%d\n",
+               __func__, retval);
+
+       board_dat->irq_reg_sts = true;
+       dev_dbg(&board_dat->pdev->dev, "%s data->irq_reg_sts=true\n", __func__);
+
+err_return:
+       if (retval != 0) {
+               dev_err(&board_dat->pdev->dev,
+                       "%s FAIL:invoking pch_spi_free_resources\n", __func__);
+               pch_spi_free_resources(board_dat);
+       }
+
+       dev_dbg(&board_dat->pdev->dev, "%s Return=%d\n", __func__, retval);
+
+       return retval;
+}
+
+static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+
+       struct spi_master *master;
+
+       struct pch_spi_board_data *board_dat;
+       int retval;
+
+       dev_dbg(&pdev->dev, "%s ENTRY\n", __func__);
+
+       /* allocate memory for private data */
+       board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL);
+       if (board_dat == NULL) {
+               dev_err(&pdev->dev,
+                       " %s memory allocation for private data failed\n",
+                       __func__);
+               retval = -ENOMEM;
+               goto err_kmalloc;
+       }
+
+       dev_dbg(&pdev->dev,
+               "%s memory allocation for private data success\n", __func__);
+
+       /* enable PCI device */
+       retval = pci_enable_device(pdev);
+       if (retval != 0) {
+               dev_err(&pdev->dev, "%s pci_enable_device FAILED\n", __func__);
+
+               goto err_pci_en_device;
+       }
+
+       dev_dbg(&pdev->dev, "%s pci_enable_device returned=%d\n",
+               __func__, retval);
+
+       board_dat->pdev = pdev;
+
+       /* alllocate memory for SPI master */
+       master = spi_alloc_master(&pdev->dev, sizeof(struct pch_spi_data));
+       if (master == NULL) {
+               retval = -ENOMEM;
+               dev_err(&pdev->dev, "%s Fail.\n", __func__);
+               goto err_spi_alloc_master;
+       }
+
+       dev_dbg(&pdev->dev,
+               "%s spi_alloc_master returned non NULL\n", __func__);
+
+       /* initialize members of SPI master */
+       master->bus_num = -1;
+       master->num_chipselect = PCH_MAX_CS;
+       master->setup = pch_spi_setup;
+       master->transfer = pch_spi_transfer;
+       dev_dbg(&pdev->dev,
+               "%s transfer member of SPI master initialized\n", __func__);
+
+       board_dat->data = spi_master_get_devdata(master);
+
+       board_dat->data->master = master;
+       board_dat->data->n_curnt_chip = 255;
+       board_dat->data->board_dat = board_dat;
+       board_dat->data->status = STATUS_RUNNING;
+
+       INIT_LIST_HEAD(&board_dat->data->queue);
+       spin_lock_init(&board_dat->data->lock);
+       INIT_WORK(&board_dat->data->work, pch_spi_process_messages);
+       init_waitqueue_head(&board_dat->data->wait);
+
+       /* allocate resources for PCH SPI */
+       retval = pch_spi_get_resources(board_dat);
+       if (retval) {
+               dev_err(&pdev->dev, "%s fail(retval=%d)\n", __func__, retval);
+               goto err_spi_get_resources;
+       }
+
+       dev_dbg(&pdev->dev, "%s pch_spi_get_resources returned=%d\n",
+               __func__, retval);
+
+       /* save private data in dev */
+       pci_set_drvdata(pdev, board_dat);
+       dev_dbg(&pdev->dev, "%s invoked pci_set_drvdata\n", __func__);
+
+       /* set master mode */
+       pch_spi_set_master_mode(master);
+       dev_dbg(&pdev->dev,
+               "%s invoked pch_spi_set_master_mode\n", __func__);
+
+       /* Register the controller with the SPI core. */
+       retval = spi_register_master(master);
+       if (retval != 0) {
+               dev_err(&pdev->dev,
+                       "%s spi_register_master FAILED\n", __func__);
+               goto err_spi_reg_master;
+       }
+
+       dev_dbg(&pdev->dev, "%s spi_register_master returned=%d\n",
+               __func__, retval);
+
+
+       return 0;
+
+err_spi_reg_master:
+       spi_unregister_master(master);
+err_spi_get_resources:
+err_spi_alloc_master:
+       spi_master_put(master);
+       pci_disable_device(pdev);
+err_pci_en_device:
+       kfree(board_dat);
+err_kmalloc:
+       return retval;
+}
+
+static void pch_spi_remove(struct pci_dev *pdev)
+{
+       struct pch_spi_board_data *board_dat = pci_get_drvdata(pdev);
+       int count;
+
+       dev_dbg(&pdev->dev, "%s ENTRY\n", __func__);
+
+       if (!board_dat) {
+               dev_err(&pdev->dev,
+                       "%s pci_get_drvdata returned NULL\n", __func__);
+               return;
+       }
+
+       /* check for any pending messages; no action is taken if the queue
+        * is still full; but at least we tried.  Unload anyway */
+       count = 500;
+       spin_lock(&board_dat->data->lock);
+       board_dat->data->status = STATUS_EXITING;
+       while ((list_empty(&board_dat->data->queue) == 0) && --count) {
+               dev_dbg(&board_dat->pdev->dev, "%s :queue not empty\n",
+                       __func__);
+               spin_unlock(&board_dat->data->lock);
+               msleep(PCH_SLEEP_TIME);
+               spin_lock(&board_dat->data->lock);
+       }
+       spin_unlock(&board_dat->data->lock);
+
+       /* Free resources allocated for PCH SPI */
+       pch_spi_free_resources(board_dat);
+
+       spi_unregister_master(board_dat->data->master);
+
+       /* free memory for private data */
+       kfree(board_dat);
+
+       pci_set_drvdata(pdev, NULL);
+
+       /* disable PCI device */
+       pci_disable_device(pdev);
+
+       dev_dbg(&pdev->dev, "%s invoked pci_disable_device\n", __func__);
+}
+
+#ifdef CONFIG_PM
+static int pch_spi_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       u8 count;
+       int retval;
+
+       struct pch_spi_board_data *board_dat = pci_get_drvdata(pdev);
+
+       dev_dbg(&pdev->dev, "%s ENTRY\n", __func__);
+
+       if (!board_dat) {
+               dev_err(&pdev->dev,
+                       "%s pci_get_drvdata returned NULL\n", __func__);
+               return -EFAULT;
+       }
+
+       retval = 0;
+       board_dat->suspend_sts = true;
+
+       /* check if the current message is processed:
+          Only after thats done the transfer will be suspended */
+       count = 255;
+       while ((--count) > 0) {
+               if (!(board_dat->data->bcurrent_msg_processing)) {
+                       dev_dbg(&pdev->dev, "%s board_dat->data->bCurrent_"
+                               "msg_processing = false\n", __func__);
+                       break;
+               } else {
+                       dev_dbg(&pdev->dev, "%s board_dat->data->bCurrent_msg_"
+                               "processing = true\n", __func__);
+               }
+               msleep(PCH_SLEEP_TIME);
+       }
+
+       /* Free IRQ */
+       if (board_dat->irq_reg_sts) {
+               /* disable all interrupts */
+               pch_spi_setclr_reg(board_dat->data->master, PCH_SPCR, 0,
+                                  PCH_ALL);
+               pch_spi_reset(board_dat->data->master);
+
+               free_irq(board_dat->pdev->irq, board_dat);
+
+               board_dat->irq_reg_sts = false;
+               dev_dbg(&pdev->dev,
+                       "%s free_irq invoked successfully.\n", __func__);
+       }
+
+       /* save config space */
+       retval = pci_save_state(pdev);
+
+       if (retval == 0) {
+               dev_dbg(&pdev->dev, "%s pci_save_state returned=%d\n",
+                       __func__, retval);
+               /* disable PM notifications */
+               pci_enable_wake(pdev, PCI_D3hot, 0);
+               dev_dbg(&pdev->dev,
+                       "%s pci_enable_wake invoked successfully\n", __func__);
+               /* disable PCI device */
+               pci_disable_device(pdev);
+               dev_dbg(&pdev->dev,
+                       "%s pci_disable_device invoked successfully\n",
+                       __func__);
+               /* move device to D3hot  state */
+               pci_set_power_state(pdev, PCI_D3hot);
+               dev_dbg(&pdev->dev,
+                       "%s pci_set_power_state invoked successfully\n",
+                       __func__);
+       } else {
+               dev_err(&pdev->dev, "%s pci_save_state failed\n", __func__);
+       }
+
+       dev_dbg(&pdev->dev, "%s return=%d\n", __func__, retval);
+
+       return retval;
+}
+
+static int pch_spi_resume(struct pci_dev *pdev)
+{
+       int retval;
+
+       struct pch_spi_board_data *board = pci_get_drvdata(pdev);
+       dev_dbg(&pdev->dev, "%s ENTRY\n", __func__);
+
+       if (!board) {
+               dev_err(&pdev->dev,
+                       "%s pci_get_drvdata returned NULL\n", __func__);
+               return -EFAULT;
+       }
+
+       /* move device to DO power state */
+       pci_set_power_state(pdev, PCI_D0);
+
+       /* restore state */
+       pci_restore_state(pdev);
+
+       retval = pci_enable_device(pdev);
+       if (retval < 0) {
+               dev_err(&pdev->dev,
+                       "%s pci_enable_device failed\n", __func__);
+       } else {
+               /* disable PM notifications */
+               pci_enable_wake(pdev, PCI_D3hot, 0);
+
+               /* register IRQ handler */
+               if (!board->irq_reg_sts) {
+                       /* register IRQ */
+                       retval = request_irq(board->pdev->irq, pch_spi_handler,
+                                            IRQF_SHARED, KBUILD_MODNAME,
+                                            board);
+                       if (retval < 0) {
+                               dev_err(&pdev->dev,
+                                       "%s request_irq failed\n", __func__);
+                               return retval;
+                       }
+                       board->irq_reg_sts = true;
+
+                       /* reset PCH SPI h/w */
+                       pch_spi_reset(board->data->master);
+                       pch_spi_set_master_mode(board->data->master);
+
+                       /* set suspend status to false */
+                       board->suspend_sts = false;
+
+               }
+       }
+
+       dev_dbg(&pdev->dev, "%s returning=%d\n", __func__, retval);
+
+       return retval;
+}
+#else
+#define pch_spi_suspend NULL
+#define pch_spi_resume NULL
+
+#endif
+
+static struct pci_driver pch_spi_pcidev = {
+       .name = "pch_spi",
+       .id_table = pch_spi_pcidev_id,
+       .probe = pch_spi_probe,
+       .remove = pch_spi_remove,
+       .suspend = pch_spi_suspend,
+       .resume = pch_spi_resume,
+};
+
+static int __init pch_spi_init(void)
+{
+       return pci_register_driver(&pch_spi_pcidev);
+}
+module_init(pch_spi_init);
+
+static void __exit pch_spi_exit(void)
+{
+       pci_unregister_driver(&pch_spi_pcidev);
+}
+module_exit(pch_spi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Topcliff PCH SPI PCI Driver");
index 7892ac163522cd0e62f568fbc7cefcea173f298e..c68b3dc19e11d3368cbd2c1dac1dc0a2d451ef48 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/mmc/sdio_func.h>
 #include <linux/slab.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
index 526682d68de8b67247c65703ea1bcff83c1988a7..c7345dbf43fa75228637d914c9d3f153d712c25e 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/io.h>
 #include <linux/etherdevice.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ciscode.h>
 #include <pcmcia/ds.h>
index 9738cad4ba13fb9f269bfa37a451fe307fc3e276..ee079ab9fb2819b3c18a8e49f6ea5c00be340c79 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/pci.h>
 #include <linux/io.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
index f8ede1182ccc5113b657a997b3df20460bf729fa..0345b4caba73c2ae9f093a7e76ceeac6d1ea59ee 100644 (file)
@@ -37,7 +37,6 @@ Status: experimental
 #include <linux/delay.h>
 #include <linux/pci.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -692,10 +691,6 @@ static int das16cs_pcmcia_attach(struct pcmcia_device *link)
        local->link = link;
        link->priv = local;
 
-       /* Initialize the pcmcia_device structure */
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        cur_dev = link;
 
        das16cs_pcmcia_config(link);
@@ -715,37 +710,12 @@ static void das16cs_pcmcia_detach(struct pcmcia_device *link)
 
 
 static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
                                void *priv_data)
 {
-       if (cfg->index == 0)
+       if (p_dev->config_index == 0)
                return -EINVAL;
 
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-               /* This reserves IO space but doesn't actually enable it */
-               return pcmcia_request_io(p_dev);
-       }
-
-       return 0;
+       return pcmcia_request_io(p_dev);
 }
 
 static void das16cs_pcmcia_config(struct pcmcia_device *link)
@@ -754,6 +724,9 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link)
 
        dev_dbg(&link->dev, "das16cs_pcmcia_config\n");
 
+       /* Do we need to allocate an interrupt? */
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+
        ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL);
        if (ret) {
                dev_warn(&link->dev, "no configuration found\n");
@@ -763,25 +736,10 @@ static void das16cs_pcmcia_config(struct pcmcia_device *link)
        if (!link->irq)
                goto failed;
 
-       /*
-          This actually configures the PCMCIA socket -- setting up
-          the I/O windows and the interrupt mapping, and putting the
-          card and host interface into "Memory and IO" mode.
-        */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
-       /* Finally, report what we've done */
-       dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
-       if (link->conf.Attributes & CONF_ENABLE_IRQ)
-               printk(", irq %u", link->irq);
-       if (link->resource[0])
-               printk(", io %pR", link->resource[0]);
-       if (link->resource[1])
-               printk(", io %pR", link->resource[1]);
-       printk("\n");
-
        return;
 
 failed:
@@ -832,9 +790,7 @@ struct pcmcia_driver das16cs_driver = {
        .resume = das16cs_pcmcia_resume,
        .id_table = das16cs_id_table,
        .owner = THIS_MODULE,
-       .drv = {
-               .name = "cb_das16_cs",
-               },
+       .name = "cb_das16_cs",
 };
 
 static int __init init_das16cs_pcmcia_cs(void)
index 48d9fb1227df0d9d9d79c2848cc8615a6c52b837..0b32a2df776829c497274fd8074b3b34e05d726e 100644 (file)
@@ -48,7 +48,6 @@ Command support does not exist, but could be added for this board.
 #include "das08.h"
 
 /* pcmcia includes */
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -115,40 +114,15 @@ static void das08_pcmcia_release(struct pcmcia_device *link);
 static int das08_pcmcia_suspend(struct pcmcia_device *p_dev);
 static int das08_pcmcia_resume(struct pcmcia_device *p_dev);
 
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static int das08_pcmcia_attach(struct pcmcia_device *);
 static void das08_pcmcia_detach(struct pcmcia_device *);
 
-/*
-   You'll also need to prototype all the functions that will actually
-   be used to talk to your device.  See 'memory_cs' for a good example
-   of a fully self-sufficient driver; the other drivers rely more or
-   less on other parts of the kernel.
-*/
-
 struct local_info_t {
        struct pcmcia_device *link;
        int stop;
        struct bus_operations *bus;
 };
 
-/*======================================================================
-
-    das08_pcmcia_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-
-======================================================================*/
-
 static int das08_pcmcia_attach(struct pcmcia_device *link)
 {
        struct local_info_t *local;
@@ -162,16 +136,6 @@ static int das08_pcmcia_attach(struct pcmcia_device *link)
        local->link = link;
        link->priv = local;
 
-       /*
-          General socket configuration defaults can go here.  In this
-          client, we assume very little, and rely on the CIS for almost
-          everything.  In most clients, many details (i.e., number, sizes,
-          and attributes of IO windows) are fixed by the nature of the
-          device, and can be hard-wired here.
-        */
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        cur_dev = link;
 
        das08_pcmcia_config(link);
@@ -179,15 +143,6 @@ static int das08_pcmcia_attach(struct pcmcia_device *link)
        return 0;
 }                              /* das08_pcmcia_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void das08_pcmcia_detach(struct pcmcia_device *link)
 {
 
@@ -203,46 +158,13 @@ static void das08_pcmcia_detach(struct pcmcia_device *link)
 
 
 static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
                                void *priv_data)
 {
-       if (cfg->index == 0)
-               return -ENODEV;
-
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-               /* This reserves IO space but doesn't actually enable it */
-               return pcmcia_request_io(p_dev);
-       }
-       return 0;
-}
-
-
-/*======================================================================
-
-    das08_pcmcia_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    device available to the system.
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-======================================================================*/
+       return pcmcia_request_io(p_dev);
+}
 
 static void das08_pcmcia_config(struct pcmcia_device *link)
 {
@@ -250,6 +172,8 @@ static void das08_pcmcia_config(struct pcmcia_device *link)
 
        dev_dbg(&link->dev, "das08_pcmcia_config\n");
 
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+
        ret = pcmcia_loop_config(link, das08_pcmcia_config_loop, NULL);
        if (ret) {
                dev_warn(&link->dev, "no configuration found\n");
@@ -259,25 +183,10 @@ static void das08_pcmcia_config(struct pcmcia_device *link)
        if (!link->irq)
                goto failed;
 
-       /*
-          This actually configures the PCMCIA socket -- setting up
-          the I/O windows and the interrupt mapping, and putting the
-          card and host interface into "Memory and IO" mode.
-        */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
-       /* Finally, report what we've done */
-       dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
-       if (link->conf.Attributes & CONF_ENABLE_IRQ)
-               printk(", irq %u", link->irq);
-       if (link->resource[0])
-               printk(", io %pR", link->resource[0]);
-       if (link->resource[1])
-               printk(" & %pR", link->resource[1]);
-       printk("\n");
-
        return;
 
 failed:
@@ -285,32 +194,12 @@ failed:
 
 }                              /* das08_pcmcia_config */
 
-/*======================================================================
-
-    After a card is removed, das08_pcmcia_release() will unregister the
-    device, and release the PCMCIA configuration.  If the device is
-    still open, this will be postponed until it is closed.
-
-======================================================================*/
-
 static void das08_pcmcia_release(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "das08_pcmcia_release\n");
        pcmcia_disable_device(link);
 }                              /* das08_pcmcia_release */
 
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.
-
-    When a CARD_REMOVAL event is received, we immediately set a
-    private flag to block future accesses to this device.  All the
-    functions that actually access the device should check this flag
-    to make sure the card is still present.
-
-======================================================================*/
-
 static int das08_pcmcia_suspend(struct pcmcia_device *link)
 {
        struct local_info_t *local = link->priv;
@@ -348,9 +237,7 @@ struct pcmcia_driver das08_cs_driver = {
        .resume = das08_pcmcia_resume,
        .id_table = das08_cs_id_table,
        .owner = THIS_MODULE,
-       .drv = {
-               .name = "pcm-das08",
-               },
+       .name = "pcm-das08",
 };
 
 static int __init init_das08_pcmcia_cs(void)
index cc15666e5cc195391d5fd5093dc90f4c30169943..fc772a8a55c6b068e1ec7315adc7b8109f4ca53c 100644 (file)
@@ -47,7 +47,6 @@ IRQ is assigned but not used.
 
 #include <linux/ioport.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -435,47 +434,20 @@ static int dio700_detach(struct comedi_device *dev)
        return 0;
 };
 
-/* PCMCIA crap -- watch your words, please! */
-
 static void dio700_config(struct pcmcia_device *link);
 static void dio700_release(struct pcmcia_device *link);
 static int dio700_cs_suspend(struct pcmcia_device *p_dev);
 static int dio700_cs_resume(struct pcmcia_device *p_dev);
 
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static int dio700_cs_attach(struct pcmcia_device *);
 static void dio700_cs_detach(struct pcmcia_device *);
 
-/*
-   You'll also need to prototype all the functions that will actually
-   be used to talk to your device.  See 'memory_cs' for a good example
-   of a fully self-sufficient driver; the other drivers rely more or
-   less on other parts of the kernel.
-*/
-
 struct local_info_t {
        struct pcmcia_device *link;
        int stop;
        struct bus_operations *bus;
 };
 
-/*======================================================================
-
-    dio700_cs_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-
-======================================================================*/
-
 static int dio700_cs_attach(struct pcmcia_device *link)
 {
        struct local_info_t *local;
@@ -491,16 +463,6 @@ static int dio700_cs_attach(struct pcmcia_device *link)
        local->link = link;
        link->priv = local;
 
-       /*
-          General socket configuration defaults can go here.  In this
-          client, we assume very little, and rely on the CIS for almost
-          everything.  In most clients, many details (i.e., number, sizes,
-          and attributes of IO windows) are fixed by the nature of the
-          device, and can be hard-wired here.
-        */
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        pcmcia_cur_dev = link;
 
        dio700_config(link);
@@ -508,15 +470,6 @@ static int dio700_cs_attach(struct pcmcia_device *link)
        return 0;
 }                              /* dio700_cs_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void dio700_cs_detach(struct pcmcia_device *link)
 {
 
@@ -532,54 +485,13 @@ static void dio700_cs_detach(struct pcmcia_device *link)
 
 }                              /* dio700_cs_detach */
 
-/*======================================================================
-
-    dio700_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    device available to the system.
-
-======================================================================*/
-
 static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
                                void *priv_data)
 {
-       if (cfg->index == 0)
-               return -ENODEV;
-
-       /* Does this card need audio output? */
-       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
-               p_dev->conf.Status = CCSR_AUDIO_ENA;
-       }
-
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-               /* This reserves IO space but doesn't actually enable it */
-               if (pcmcia_request_io(p_dev) != 0)
-                       return -ENODEV;
-       }
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       /* If we got this far, we're cool! */
-       return 0;
+       return pcmcia_request_io(p_dev);
 }
 
 static void dio700_config(struct pcmcia_device *link)
@@ -591,6 +503,9 @@ static void dio700_config(struct pcmcia_device *link)
 
        dev_dbg(&link->dev, "dio700_config\n");
 
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO |
+               CONF_AUTO_SET_IO;
+
        ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, NULL);
        if (ret) {
                dev_warn(&link->dev, "no configuration found\n");
@@ -600,25 +515,10 @@ static void dio700_config(struct pcmcia_device *link)
        if (!link->irq)
                goto failed;
 
-       /*
-          This actually configures the PCMCIA socket -- setting up
-          the I/O windows and the interrupt mapping, and putting the
-          card and host interface into "Memory and IO" mode.
-        */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret != 0)
                goto failed;
 
-       /* Finally, report what we've done */
-       dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
-       if (link->conf.Attributes & CONF_ENABLE_IRQ)
-               printk(", irq %d", link->irq);
-       if (link->resource[0])
-               printk(", io %pR", link->resource[0]);
-       if (link->resource[1])
-               printk(" & %pR", link->resource[1]);
-       printk("\n");
-
        return;
 
 failed:
@@ -634,18 +534,6 @@ static void dio700_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }                              /* dio700_release */
 
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.
-
-    When a CARD_REMOVAL event is received, we immediately set a
-    private flag to block future accesses to this device.  All the
-    functions that actually access the device should check this flag
-    to make sure the card is still present.
-
-======================================================================*/
-
 static int dio700_cs_suspend(struct pcmcia_device *link)
 {
        struct local_info_t *local = link->priv;
@@ -685,9 +573,7 @@ struct pcmcia_driver dio700_cs_driver = {
        .resume = dio700_cs_resume,
        .id_table = dio700_cs_ids,
        .owner = THIS_MODULE,
-       .drv = {
-               .name = "ni_daq_700",
-               },
+       .name = "ni_daq_700",
 };
 
 static int __init init_dio700_cs(void)
index 773ae2044e0ee8a52435f14879563dd37597d6f4..c9c28584db67dbc910c0c1882a2e071d6198c2e4 100644 (file)
@@ -48,7 +48,6 @@ the PCMCIA interface.
 
 #include "8255.h"
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -187,47 +186,20 @@ static int dio24_detach(struct comedi_device *dev)
        return 0;
 };
 
-/* PCMCIA crap -- watch your words! */
-
 static void dio24_config(struct pcmcia_device *link);
 static void dio24_release(struct pcmcia_device *link);
 static int dio24_cs_suspend(struct pcmcia_device *p_dev);
 static int dio24_cs_resume(struct pcmcia_device *p_dev);
 
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static int dio24_cs_attach(struct pcmcia_device *);
 static void dio24_cs_detach(struct pcmcia_device *);
 
-/*
-   You'll also need to prototype all the functions that will actually
-   be used to talk to your device.  See 'memory_cs' for a good example
-   of a fully self-sufficient driver; the other drivers rely more or
-   less on other parts of the kernel.
-*/
-
 struct local_info_t {
        struct pcmcia_device *link;
        int stop;
        struct bus_operations *bus;
 };
 
-/*======================================================================
-
-    dio24_cs_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-
-======================================================================*/
-
 static int dio24_cs_attach(struct pcmcia_device *link)
 {
        struct local_info_t *local;
@@ -243,16 +215,6 @@ static int dio24_cs_attach(struct pcmcia_device *link)
        local->link = link;
        link->priv = local;
 
-       /*
-          General socket configuration defaults can go here.  In this
-          client, we assume very little, and rely on the CIS for almost
-          everything.  In most clients, many details (i.e., number, sizes,
-          and attributes of IO windows) are fixed by the nature of the
-          device, and can be hard-wired here.
-        */
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        pcmcia_cur_dev = link;
 
        dio24_config(link);
@@ -260,15 +222,6 @@ static int dio24_cs_attach(struct pcmcia_device *link)
        return 0;
 }                              /* dio24_cs_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void dio24_cs_detach(struct pcmcia_device *link)
 {
 
@@ -284,54 +237,13 @@ static void dio24_cs_detach(struct pcmcia_device *link)
 
 }                              /* dio24_cs_detach */
 
-/*======================================================================
-
-    dio24_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    device available to the system.
-
-======================================================================*/
-
 static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
                                void *priv_data)
 {
-       if (cfg->index == 0)
-               return -ENODEV;
-
-       /* Does this card need audio output? */
-       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
-               p_dev->conf.Status = CCSR_AUDIO_ENA;
-       }
-
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-               /* This reserves IO space but doesn't actually enable it */
-               if (pcmcia_request_io(p_dev) != 0)
-                       return -ENODEV;
-       }
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       /* If we got this far, we're cool! */
-       return 0;
+       return pcmcia_request_io(p_dev);
 }
 
 static void dio24_config(struct pcmcia_device *link)
@@ -342,6 +254,9 @@ static void dio24_config(struct pcmcia_device *link)
 
        dev_dbg(&link->dev, "dio24_config\n");
 
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO |
+               CONF_AUTO_SET_IO;
+
        ret = pcmcia_loop_config(link, dio24_pcmcia_config_loop, NULL);
        if (ret) {
                dev_warn(&link->dev, "no configuration found\n");
@@ -351,25 +266,10 @@ static void dio24_config(struct pcmcia_device *link)
        if (!link->irq)
                goto failed;
 
-       /*
-          This actually configures the PCMCIA socket -- setting up
-          the I/O windows and the interrupt mapping, and putting the
-          card and host interface into "Memory and IO" mode.
-        */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
-       /* Finally, report what we've done */
-       dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
-       if (link->conf.Attributes & CONF_ENABLE_IRQ)
-               printk(", irq %d", link->irq);
-       if (link->resource[0])
-               printk(" & %pR", link->resource[0]);
-       if (link->resource[1])
-               printk(" & %pR", link->resource[1]);
-       printk("\n");
-
        return;
 
 failed:
@@ -385,18 +285,6 @@ static void dio24_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }                              /* dio24_release */
 
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.
-
-    When a CARD_REMOVAL event is received, we immediately set a
-    private flag to block future accesses to this device.  All the
-    functions that actually access the device should check this flag
-    to make sure the card is still present.
-
-======================================================================*/
-
 static int dio24_cs_suspend(struct pcmcia_device *link)
 {
        struct local_info_t *local = link->priv;
@@ -435,9 +323,7 @@ struct pcmcia_driver dio24_cs_driver = {
        .resume = dio24_cs_resume,
        .id_table = dio24_cs_ids,
        .owner = THIS_MODULE,
-       .drv = {
-               .name = "ni_daq_dio24",
-               },
+       .name = "ni_daq_dio24",
 };
 
 static int __init init_dio24_cs(void)
index 68c4ecbd93ae83728c422f00da13e273a13d63a1..6facbc8bf77660093b7b504cb65eb08c737589e1 100644 (file)
@@ -71,7 +71,6 @@ NI manuals:
 #include "comedi_fc.h"
 #include "ni_labpc.h"
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -153,59 +152,20 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        return labpc_common_attach(dev, iobase, irq, 0);
 }
 
-/*====================================================================*/
-
-/*
-   The event() function is this driver's Card Services event handler.
-   It will be called by Card Services when an appropriate card status
-   event is received.  The config() and release() entry points are
-   used to configure or release a socket, in response to card
-   insertion and ejection events.  They are invoked from the dummy
-   event handler.
-
-   Kernel version 2.6.16 upwards uses suspend() and resume() functions
-   instead of an event() function.
-*/
-
 static void labpc_config(struct pcmcia_device *link);
 static void labpc_release(struct pcmcia_device *link);
 static int labpc_cs_suspend(struct pcmcia_device *p_dev);
 static int labpc_cs_resume(struct pcmcia_device *p_dev);
 
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static int labpc_cs_attach(struct pcmcia_device *);
 static void labpc_cs_detach(struct pcmcia_device *);
 
-/*
-   You'll also need to prototype all the functions that will actually
-   be used to talk to your device.  See 'memory_cs' for a good example
-   of a fully self-sufficient driver; the other drivers rely more or
-   less on other parts of the kernel.
-*/
-
 struct local_info_t {
        struct pcmcia_device *link;
        int stop;
        struct bus_operations *bus;
 };
 
-/*======================================================================
-
-    labpc_cs_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-
-======================================================================*/
-
 static int labpc_cs_attach(struct pcmcia_device *link)
 {
        struct local_info_t *local;
@@ -219,16 +179,6 @@ static int labpc_cs_attach(struct pcmcia_device *link)
        local->link = link;
        link->priv = local;
 
-       /*
-          General socket configuration defaults can go here.  In this
-          client, we assume very little, and rely on the CIS for almost
-          everything.  In most clients, many details (i.e., number, sizes,
-          and attributes of IO windows) are fixed by the nature of the
-          device, and can be hard-wired here.
-        */
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        pcmcia_cur_dev = link;
 
        labpc_config(link);
@@ -236,15 +186,6 @@ static int labpc_cs_attach(struct pcmcia_device *link)
        return 0;
 }                              /* labpc_cs_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void labpc_cs_detach(struct pcmcia_device *link)
 {
        dev_dbg(&link->dev, "labpc_cs_detach\n");
@@ -263,54 +204,13 @@ static void labpc_cs_detach(struct pcmcia_device *link)
 
 }                              /* labpc_cs_detach */
 
-/*======================================================================
-
-    labpc_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    device available to the system.
-
-======================================================================*/
-
 static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
                                void *priv_data)
 {
-       if (cfg->index == 0)
-               return -ENODEV;
-
-       /* Does this card need audio output? */
-       if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
-               p_dev->conf.Attributes |= CONF_ENABLE_SPKR;
-               p_dev->conf.Status = CCSR_AUDIO_ENA;
-       }
-
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-               /* This reserves IO space but doesn't actually enable it */
-               if (pcmcia_request_io(p_dev) != 0)
-                       return -ENODEV;
-       }
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       /* If we got this far, we're cool! */
-       return 0;
+       return pcmcia_request_io(p_dev);
 }
 
 
@@ -320,6 +220,9 @@ static void labpc_config(struct pcmcia_device *link)
 
        dev_dbg(&link->dev, "labpc_config\n");
 
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ |
+               CONF_AUTO_AUDIO | CONF_AUTO_SET_IO;
+
        ret = pcmcia_loop_config(link, labpc_pcmcia_config_loop, NULL);
        if (ret) {
                dev_warn(&link->dev, "no configuration found\n");
@@ -329,25 +232,10 @@ static void labpc_config(struct pcmcia_device *link)
        if (!link->irq)
                goto failed;
 
-       /*
-          This actually configures the PCMCIA socket -- setting up
-          the I/O windows and the interrupt mapping, and putting the
-          card and host interface into "Memory and IO" mode.
-        */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
-       /* Finally, report what we've done */
-       dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
-       if (link->conf.Attributes & CONF_ENABLE_IRQ)
-               printk(", irq %d", link->irq);
-       if (link->resource[0])
-               printk(" & %pR", link->resource[0]);
-       if (link->resource[1])
-               printk(" & %pR", link->resource[1]);
-       printk("\n");
-
        return;
 
 failed:
@@ -362,18 +250,6 @@ static void labpc_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }                              /* labpc_release */
 
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.
-
-    When a CARD_REMOVAL event is received, we immediately set a
-    private flag to block future accesses to this device.  All the
-    functions that actually access the device should check this flag
-    to make sure the card is still present.
-
-======================================================================*/
-
 static int labpc_cs_suspend(struct pcmcia_device *link)
 {
        struct local_info_t *local = link->priv;
@@ -391,8 +267,6 @@ static int labpc_cs_resume(struct pcmcia_device *link)
        return 0;
 }                              /* labpc_cs_resume */
 
-/*====================================================================*/
-
 static struct pcmcia_device_id labpc_cs_ids[] = {
        /* N.B. These IDs should match those in labpc_cs_boards (ni_labpc.c) */
        PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0103),        /* daqcard-1200 */
@@ -411,9 +285,7 @@ struct pcmcia_driver labpc_cs_driver = {
        .resume = labpc_cs_resume,
        .id_table = labpc_cs_ids,
        .owner = THIS_MODULE,
-       .drv = {
-               .name = "daqcard-1200",
-               },
+       .name = "daqcard-1200",
 };
 
 static int __init init_labpc_cs(void)
index 1f2426352eb57d82cc0c18ba98d738d224fe31cf..49563273f605c659b05467f25d836d912291b796 100644 (file)
@@ -48,7 +48,6 @@ See the notes in the ni_atmio.o driver.
 #include "ni_stc.h"
 #include "8255.h"
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -263,11 +262,6 @@ static struct pcmcia_device *cur_dev = NULL;
 
 static int cs_attach(struct pcmcia_device *link)
 {
-       link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
-       link->resource[0]->end = 16;
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        cur_dev = link;
 
        mio_cs_config(link);
@@ -301,16 +295,12 @@ static int mio_cs_resume(struct pcmcia_device *link)
 }
 
 
-static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
-                               void *priv_data)
+static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data)
 {
        int base, ret;
 
-       p_dev->resource[0]->end = cfg->io.win[0].len;
-       p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
 
        for (base = 0x000; base < 0x400; base += 0x20) {
                p_dev->resource[0]->start = base;
@@ -327,6 +317,7 @@ static void mio_cs_config(struct pcmcia_device *link)
        int ret;
 
        DPRINTK("mio_cs_config(link=%p)\n", link);
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
 
        ret = pcmcia_loop_config(link, mio_pcmcia_config_loop, NULL);
        if (ret) {
@@ -337,7 +328,7 @@ static void mio_cs_config(struct pcmcia_device *link)
        if (!link->irq)
                dev_info(&link->dev, "no IRQ available\n");
 
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
 }
 
 static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it)
@@ -446,9 +437,7 @@ struct pcmcia_driver ni_mio_cs_driver = {
        .resume = &mio_cs_resume,
        .id_table = ni_mio_cs_ids,
        .owner = THIS_MODULE,
-       .drv = {
-               .name = "ni_mio_cs",
-               },
+       .name = "ni_mio_cs",
 };
 
 int init_module(void)
index bf489d7f49909ce75bc9e9b2c3990b1b840218f6..ebba9bb47777cfba6edbe6856ee88840967589b7 100644 (file)
@@ -50,7 +50,6 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308
 #include "../comedidev.h"
 #include <linux/semaphore.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -969,43 +968,14 @@ static int daqp_detach(struct comedi_device *dev)
 
 ======================================================================*/
 
-/*
-   The event() function is this driver's Card Services event handler.
-   It will be called by Card Services when an appropriate card status
-   event is received.  The config() and release() entry points are
-   used to configure or release a socket, in response to card
-   insertion and ejection events.
-
-   Kernel version 2.6.16 upwards uses suspend() and resume() functions
-   instead of an event() function.
-*/
-
 static void daqp_cs_config(struct pcmcia_device *link);
 static void daqp_cs_release(struct pcmcia_device *link);
 static int daqp_cs_suspend(struct pcmcia_device *p_dev);
 static int daqp_cs_resume(struct pcmcia_device *p_dev);
 
-/*
-   The attach() and detach() entry points are used to create and destroy
-   "instances" of the driver, where each instance represents everything
-   needed to manage one actual PCMCIA card.
-*/
-
 static int daqp_cs_attach(struct pcmcia_device *);
 static void daqp_cs_detach(struct pcmcia_device *);
 
-/*======================================================================
-
-    daqp_cs_attach() creates an "instance" of the driver, allocating
-    local data structures for one device.  The device is registered
-    with Card Services.
-
-    The dev_link structure is initialized, but we don't actually
-    configure the card at this point -- we wait until we receive a
-    card insertion event.
-
-======================================================================*/
-
 static int daqp_cs_attach(struct pcmcia_device *link)
 {
        struct local_info_t *local;
@@ -1031,30 +1001,11 @@ static int daqp_cs_attach(struct pcmcia_device *link)
        local->link = link;
        link->priv = local;
 
-       /*
-          General socket configuration defaults can go here.  In this
-          client, we assume very little, and rely on the CIS for almost
-          everything.  In most clients, many details (i.e., number, sizes,
-          and attributes of IO windows) are fixed by the nature of the
-          device, and can be hard-wired here.
-        */
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        daqp_cs_config(link);
 
        return 0;
 }                              /* daqp_cs_attach */
 
-/*======================================================================
-
-    This deletes a driver "instance".  The device is de-registered
-    with Card Services.  If it has been released, all local data
-    structures are freed.  Otherwise, the structures will be freed
-    when the device is released.
-
-======================================================================*/
-
 static void daqp_cs_detach(struct pcmcia_device *link)
 {
        struct local_info_t *dev = link->priv;
@@ -1070,45 +1021,11 @@ static void daqp_cs_detach(struct pcmcia_device *link)
 
 }                              /* daqp_cs_detach */
 
-/*======================================================================
-
-    daqp_cs_config() is scheduled to run after a CARD_INSERTION event
-    is received, to configure the PCMCIA socket, and to make the
-    device available to the system.
-
-======================================================================*/
-
-
-static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev,
-                               cistpl_cftable_entry_t *cfg,
-                               cistpl_cftable_entry_t *dflt,
-                               unsigned int vcc,
-                               void *priv_data)
+static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (cfg->index == 0)
-               return -ENODEV;
+       if (p_dev->config_index == 0)
+               return -EINVAL;
 
-       /* Do we need to allocate an interrupt? */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-               p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
-               p_dev->resource[0]->flags |=
-                       pcmcia_io_cfg_data_width(io->flags);
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               if (io->nwin > 1) {
-                       p_dev->resource[1]->flags = p_dev->resource[0]->flags;
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-       }
-
-       /* This reserves IO space but doesn't actually enable it */
        return pcmcia_request_io(p_dev);
 }
 
@@ -1118,6 +1035,8 @@ static void daqp_cs_config(struct pcmcia_device *link)
 
        dev_dbg(&link->dev, "daqp_cs_config\n");
 
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
+
        ret = pcmcia_loop_config(link, daqp_pcmcia_config_loop, NULL);
        if (ret) {
                dev_warn(&link->dev, "no configuration found\n");
@@ -1128,25 +1047,10 @@ static void daqp_cs_config(struct pcmcia_device *link)
        if (ret)
                goto failed;
 
-       /*
-          This actually configures the PCMCIA socket -- setting up
-          the I/O windows and the interrupt mapping, and putting the
-          card and host interface into "Memory and IO" mode.
-        */
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
-       /* Finally, report what we've done */
-       dev_info(&link->dev, "index 0x%02x", link->conf.ConfigIndex);
-       if (link->conf.Attributes & CONF_ENABLE_IRQ)
-               printk(", irq %u", link->irq);
-       if (link->resource[0])
-               printk(" & %pR", link->resource[0]);
-       if (link->resource[1])
-               printk(" & %pR", link->resource[1]);
-       printk("\n");
-
        return;
 
 failed:
@@ -1161,18 +1065,6 @@ static void daqp_cs_release(struct pcmcia_device *link)
        pcmcia_disable_device(link);
 }                              /* daqp_cs_release */
 
-/*======================================================================
-
-    The card status event handler.  Mostly, this schedules other
-    stuff to run after an event is received.
-
-    When a CARD_REMOVAL event is received, we immediately set a
-    private flag to block future accesses to this device.  All the
-    functions that actually access the device should check this flag
-    to make sure the card is still present.
-
-======================================================================*/
-
 static int daqp_cs_suspend(struct pcmcia_device *link)
 {
        struct local_info_t *local = link->priv;
@@ -1212,9 +1104,7 @@ static struct pcmcia_driver daqp_cs_driver = {
        .resume = daqp_cs_resume,
        .id_table = daqp_cs_id_table,
        .owner = THIS_MODULE,
-       .drv = {
-               .name = "quatech_daqp_cs",
-               },
+       .name = "quatech_daqp_cs",
 };
 
 int __init init_module(void)
index 19c335458653fc1a293c2533017a5d426cdf4805..6555891e149c809c56a014f7f1511a063a3cb8df 100644 (file)
@@ -83,7 +83,6 @@
 #include <linux/if_arp.h>
 #include <linux/ioport.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
@@ -147,10 +146,9 @@ static int wl_adapter_attach(struct pcmcia_device *link)
 
        link->resource[0]->end  = HCF_NUM_IO_PORTS;
        link->resource[0]->flags= IO_DATA_PATH_WIDTH_16;
-       link->conf.Attributes   = CONF_ENABLE_IRQ;
-       link->conf.IntType      = INT_MEMORY_AND_IO;
-       link->conf.ConfigIndex  = 5;
-       link->conf.Present      = PRESENT_OPTION;
+       link->config_flags     |= CONF_ENABLE_IRQ;
+       link->config_index      = 5;
+       link->config_regs       = PRESENT_OPTION;
 
        link->priv = dev;
        lp = wl_priv(dev);
@@ -165,27 +163,6 @@ static int wl_adapter_attach(struct pcmcia_device *link)
 
 
 
-/*******************************************************************************
- *     wl_adapter_detach()
- *******************************************************************************
- *
- *  DESCRIPTION:
- *
- *      This deletes a driver "instance". The device is de-registered with Card
- *  Services. If it has been released, then the net device is unregistered, and
- *  all local data structures are freed. Otherwise, the structures will be
- *  freed when the device is released.
- *
- *  PARAMETERS:
- *
- *      link    - pointer to the dev_link_t structure representing the device to
- *                detach
- *
- *  RETURNS:
- *
- *      N/A
- *
- ******************************************************************************/
 static void wl_adapter_detach(struct pcmcia_device *link)
 {
        struct net_device   *dev = link->priv;
@@ -209,26 +186,6 @@ static void wl_adapter_detach(struct pcmcia_device *link)
 /*============================================================================*/
 
 
-/*******************************************************************************
- *     wl_adapter_release()
- *******************************************************************************
- *
- *  DESCRIPTION:
- *
- *      After a card is removed, this routine will release the PCMCIA
- *  configuration. If the device is still open, this will be postponed until it
- *  is closed.
- *
- *  PARAMETERS:
- *
- *      arg - a u_long representing a pointer to a dev_link_t structure for the
- *            device to be released.
- *
- *  RETURNS:
- *
- *      N/A
- *
- ******************************************************************************/
 void wl_adapter_release(struct pcmcia_device *link)
 {
        DBG_FUNC("wl_adapter_release");
@@ -268,26 +225,6 @@ static int wl_adapter_resume(struct pcmcia_device *link)
        return 0;
 } /* wl_adapter_resume */
 
-/*******************************************************************************
- *     wl_adapter_insert()
- *******************************************************************************
- *
- *  DESCRIPTION:
- *
- *      wl_adapter_insert() is scheduled to run after a CARD_INSERTION event is
- *  received, to configure the PCMCIA socket, and to make the ethernet device
- *  available to the system.
- *
- *  PARAMETERS:
- *
- *      link    - pointer to the dev_link_t structure representing the device to
- *                insert
- *
- *  RETURNS:
- *
- *      N/A
- *
- ******************************************************************************/
 void wl_adapter_insert(struct pcmcia_device *link)
 {
        struct net_device *dev;
@@ -302,7 +239,7 @@ void wl_adapter_insert(struct pcmcia_device *link)
        dev     = link->priv;
 
        /* Do we need to allocate an interrupt? */
-       link->conf.Attributes |= CONF_ENABLE_IRQ;
+       link->config_flags |= CONF_ENABLE_IRQ;
        link->io_lines = 6;
 
        ret = pcmcia_request_io(link);
@@ -313,7 +250,7 @@ void wl_adapter_insert(struct pcmcia_device *link)
        if (ret != 0)
                goto failed;
 
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret != 0)
                goto failed;
 
@@ -457,9 +394,7 @@ MODULE_DEVICE_TABLE(pcmcia, wl_adapter_ids);
 
 static struct pcmcia_driver wlags49_driver = {
        .owner      = THIS_MODULE,
-       .drv        = {
-               .name = DRIVER_NAME,
-       },
+       .name       = DRIVER_NAME,
        .probe      = wl_adapter_attach,
        .remove     = wl_adapter_detach,
        .id_table   = wl_adapter_ids,
index 02f0a20e178a1cbcd72d413ec3e4973afff9794c..cd129b3ee6c0e100312bf5cfca0b98c5ab5bae1e 100644 (file)
@@ -69,7 +69,6 @@
  ******************************************************************************/
 #include <linux/version.h>
 #ifdef BUS_PCMCIA
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
index 88d0d472142fde3334516a2166ce6e80904f945f..8e3536acbf46e1bac00327ff0f6baa0f05f7b916 100644 (file)
@@ -414,25 +414,6 @@ extern memimage fw_image;            // firmware image to be downloaded
 #endif /* HCF_STA */
 
 
-/*******************************************************************************
- *     wl_insert()
- *******************************************************************************
- *
- *  DESCRIPTION:
- *
- *      wl_insert() is scheduled to run after a CARD_INSERTION event is
- *  received, to configure the PCMCIA socket, and to make the ethernet device
- *  available to the system.
- *
- *  PARAMETERS:
- *
- *      dev - a pointer to the net_device struct of the wireless device
- *
- *  RETURNS:
- *
- *      TRUE or FALSE
- *
- ******************************************************************************/
 int wl_insert( struct net_device *dev )
 {
        int                     result = 0;
index a1900e5025184521e0fe1c6f0c39b233e43026fe..d005b9eeebbcc1f751763c7ab039c9dea13333ca 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/errno.h>       /* error codes */
 #include <linux/slab.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
@@ -32,9 +31,6 @@ static int ixj_probe(struct pcmcia_device *p_dev)
 {
        dev_dbg(&p_dev->dev, "ixj_attach()\n");
        /* Create new ixj device */
-       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-       p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
-       p_dev->conf.IntType = INT_MEMORY_AND_IO;
        p_dev->priv = kzalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
        if (!p_dev->priv) {
                return -ENOMEM;
@@ -111,40 +107,31 @@ failed:
        return;
 }
 
-static int ixj_config_check(struct pcmcia_device *p_dev,
-                           cistpl_cftable_entry_t *cfg,
-                           cistpl_cftable_entry_t *dflt,
-                           unsigned int vcc,
-                           void *priv_data)
+static int ixj_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-               p_dev->io_lines = 3;
-               if (io->nwin == 2) {
-                       p_dev->resource[1]->start = io->win[1].base;
-                       p_dev->resource[1]->end = io->win[1].len;
-               }
-               if (!pcmcia_request_io(p_dev))
-                       return 0;
-       }
-       return -ENODEV;
+       p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->resource[1]->flags &= ~IO_DATA_PATH_WIDTH;
+       p_dev->resource[1]->flags |= IO_DATA_PATH_WIDTH_8;
+       p_dev->io_lines = 3;
+
+       return pcmcia_request_io(p_dev);
 }
 
 static int ixj_config(struct pcmcia_device * link)
 {
        IXJ *j;
        ixj_info_t *info;
-       cistpl_cftable_entry_t dflt = { 0 };
 
        info = link->priv;
        dev_dbg(&link->dev, "ixj_config\n");
 
-       if (pcmcia_loop_config(link, ixj_config_check, &dflt))
+       link->config_flags = CONF_AUTO_SET_IO;
+
+       if (pcmcia_loop_config(link, ixj_config_check, NULL))
                goto failed;
 
-       if (pcmcia_request_configuration(link, &link->conf))
+       if (pcmcia_enable_device(link))
                goto failed;
 
        /*
@@ -178,9 +165,7 @@ MODULE_DEVICE_TABLE(pcmcia, ixj_ids);
 
 static struct pcmcia_driver ixj_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "ixj_cs",
-       },
+       .name           = "ixj_cs",
        .probe          = ixj_probe,
        .remove         = ixj_detach,
        .id_table       = ixj_ids,
index 418163894775e36ff129aa96ba107f7e6145ca20..afef7b0a419567ab92643d0809a1da5f1a4f13a9 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <mach/ohci.h>
+#include <mach/pxa3xx-u2d.h>
 
 /*
  * UHC: USB Host Controller (OHCI-like) register definitions
@@ -235,6 +236,9 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev)
        if (retval < 0)
                return retval;
 
+       if (cpu_is_pxa3xx())
+               pxa3xx_u2d_start_hc(&ohci_to_hcd(&ohci->ohci)->self);
+
        uhchr = __raw_readl(ohci->mmio_base + UHCHR) & ~UHCHR_SSE;
        __raw_writel(uhchr, ohci->mmio_base + UHCHR);
        __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, ohci->mmio_base + UHCHIE);
@@ -251,6 +255,9 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev)
 
        inf = dev->platform_data;
 
+       if (cpu_is_pxa3xx())
+               pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self);
+
        if (inf->exit)
                inf->exit(dev);
 
index 0e13a00eb2ed51ea38126fa954a5e3a4723d87c0..3775c035a6c56c994078357e9f1a55c5b2b02312 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -132,49 +131,12 @@ static void sl811_cs_release(struct pcmcia_device * link)
        platform_device_unregister(&platform_dev);
 }
 
-static int sl811_cs_config_check(struct pcmcia_device *p_dev,
-                                cistpl_cftable_entry_t *cfg,
-                                cistpl_cftable_entry_t *dflt,
-                                unsigned int vcc,
-                                void *priv_data)
+static int sl811_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
 {
-       if (cfg->index == 0)
-               return -ENODEV;
-
-       /* Use power settings for Vcc and Vpp if present */
-       /*  Note that the CIS values need to be rescaled */
-       if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-               if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc)
-                       return -ENODEV;
-       } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) {
-               if (dflt->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc)
-                       return -ENODEV;
-               }
-
-       if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
-       else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM))
-               p_dev->conf.Vpp =
-                       dflt->vpp1.param[CISTPL_POWER_VNOM]/10000;
-
-       /* we need an interrupt */
-       p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
-
-       /* IO window settings */
-       p_dev->resource[0]->end = p_dev->resource[1]->end = 0;
-       if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) {
-               cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io;
-               p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK;
-
-               p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
-               p_dev->resource[0]->start = io->win[0].base;
-               p_dev->resource[0]->end = io->win[0].len;
-
-               return pcmcia_request_io(p_dev);
-       }
-       pcmcia_disable_device(p_dev);
-       return -ENODEV;
+       if (p_dev->config_index == 0)
+               return -EINVAL;
+
+       return pcmcia_request_io(p_dev);
 }
 
 
@@ -185,6 +147,9 @@ static int sl811_cs_config(struct pcmcia_device *link)
 
        dev_dbg(&link->dev, "sl811_cs_config\n");
 
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
+               CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO;
+
        if (pcmcia_loop_config(link, sl811_cs_config_check, NULL))
                goto failed;
 
@@ -195,18 +160,10 @@ static int sl811_cs_config(struct pcmcia_device *link)
        if (!link->irq)
                goto failed;
 
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
-       dev_info(&link->dev, "index 0x%02x: ",
-               link->conf.ConfigIndex);
-       if (link->conf.Vpp)
-               printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10);
-       printk(", irq %d", link->irq);
-       printk(", io %pR", link->resource[0]);
-       printk("\n");
-
        if (sl811_hc_init(parent, link->resource[0]->start, link->irq)
                        < 0) {
 failed:
@@ -227,9 +184,6 @@ static int sl811_cs_probe(struct pcmcia_device *link)
        local->p_dev = link;
        link->priv = local;
 
-       link->conf.Attributes = 0;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-
        return sl811_cs_config(link);
 }
 
@@ -241,9 +195,7 @@ MODULE_DEVICE_TABLE(pcmcia, sl811_ids);
 
 static struct pcmcia_driver sl811_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "sl811_cs",
-       },
+       .name           = "sl811_cs",
        .probe          = sl811_cs_probe,
        .remove         = sl811_cs_detach,
        .id_table       = sl811_ids,
index 7c8008225ee3a47ebef2cecaf005c0631fa93da1..17927b1f9334ead1e854ed539dea352f8718c589 100644 (file)
@@ -127,7 +127,10 @@ static void handle_tx(struct vhost_net *net)
        size_t len, total_len = 0;
        int err, wmem;
        size_t hdr_size;
-       struct socket *sock = rcu_dereference(vq->private_data);
+       struct socket *sock;
+
+       sock = rcu_dereference_check(vq->private_data,
+                                    lockdep_is_held(&vq->mutex));
        if (!sock)
                return;
 
@@ -582,7 +585,10 @@ static void vhost_net_disable_vq(struct vhost_net *n,
 static void vhost_net_enable_vq(struct vhost_net *n,
                                struct vhost_virtqueue *vq)
 {
-       struct socket *sock = vq->private_data;
+       struct socket *sock;
+
+       sock = rcu_dereference_protected(vq->private_data,
+                                        lockdep_is_held(&vq->mutex));
        if (!sock)
                return;
        if (vq == n->vqs + VHOST_NET_VQ_TX) {
@@ -598,7 +604,8 @@ static struct socket *vhost_net_stop_vq(struct vhost_net *n,
        struct socket *sock;
 
        mutex_lock(&vq->mutex);
-       sock = vq->private_data;
+       sock = rcu_dereference_protected(vq->private_data,
+                                        lockdep_is_held(&vq->mutex));
        vhost_net_disable_vq(n, vq);
        rcu_assign_pointer(vq->private_data, NULL);
        mutex_unlock(&vq->mutex);
@@ -736,7 +743,8 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
        }
 
        /* start polling new socket */
-       oldsock = vq->private_data;
+       oldsock = rcu_dereference_protected(vq->private_data,
+                                           lockdep_is_held(&vq->mutex));
        if (sock != oldsock) {
                 vhost_net_disable_vq(n, vq);
                 rcu_assign_pointer(vq->private_data, sock);
index dd3d6f7406f80092cdd8843acdd06c313e9cf164..8b5a1b33d0fed906ef6d0873027a3275858e8c2c 100644 (file)
@@ -320,7 +320,7 @@ long vhost_dev_reset_owner(struct vhost_dev *dev)
        vhost_dev_cleanup(dev);
 
        memory->nregions = 0;
-       dev->memory = memory;
+       RCU_INIT_POINTER(dev->memory, memory);
        return 0;
 }
 
@@ -352,8 +352,9 @@ void vhost_dev_cleanup(struct vhost_dev *dev)
                fput(dev->log_file);
        dev->log_file = NULL;
        /* No one will access memory at this point */
-       kfree(dev->memory);
-       dev->memory = NULL;
+       kfree(rcu_dereference_protected(dev->memory,
+                                       lockdep_is_held(&dev->mutex)));
+       RCU_INIT_POINTER(dev->memory, NULL);
        if (dev->mm)
                mmput(dev->mm);
        dev->mm = NULL;
@@ -440,14 +441,22 @@ static int vq_access_ok(unsigned int num,
 /* Caller should have device mutex but not vq mutex */
 int vhost_log_access_ok(struct vhost_dev *dev)
 {
-       return memory_access_ok(dev, dev->memory, 1);
+       struct vhost_memory *mp;
+
+       mp = rcu_dereference_protected(dev->memory,
+                                      lockdep_is_held(&dev->mutex));
+       return memory_access_ok(dev, mp, 1);
 }
 
 /* Verify access for write logging. */
 /* Caller should have vq mutex and device mutex */
 static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base)
 {
-       return vq_memory_access_ok(log_base, vq->dev->memory,
+       struct vhost_memory *mp;
+
+       mp = rcu_dereference_protected(vq->dev->memory,
+                                      lockdep_is_held(&vq->mutex));
+       return vq_memory_access_ok(log_base, mp,
                            vhost_has_feature(vq->dev, VHOST_F_LOG_ALL)) &&
                (!vq->log_used || log_access_ok(log_base, vq->log_addr,
                                        sizeof *vq->used +
@@ -487,7 +496,8 @@ static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
                kfree(newmem);
                return -EFAULT;
        }
-       oldmem = d->memory;
+       oldmem = rcu_dereference_protected(d->memory,
+                                          lockdep_is_held(&d->mutex));
        rcu_assign_pointer(d->memory, newmem);
        synchronize_rcu();
        kfree(oldmem);
index afd77295971ce3044117d0d6e5ea8f4e20f655fe..af3c11ded5fd4910ed0dccea161a801298036731 100644 (file)
@@ -106,7 +106,7 @@ struct vhost_virtqueue {
         * vhost_work execution acts instead of rcu_read_lock() and the end of
         * vhost_work execution acts instead of rcu_read_lock().
         * Writers use virtqueue mutex. */
-       void *private_data;
+       void __rcu *private_data;
        /* Log write descriptors */
        void __user *log_base;
        struct vhost_log log[VHOST_NET_MAX_SG];
@@ -116,7 +116,7 @@ struct vhost_dev {
        /* Readers use RCU to access memory table pointer
         * log base pointer and features.
         * Writers use mutex below.*/
-       struct vhost_memory *memory;
+       struct vhost_memory __rcu *memory;
        struct mm_struct *mm;
        struct mutex mutex;
        unsigned acked_features;
@@ -173,7 +173,11 @@ enum {
 
 static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
 {
-       unsigned acked_features = rcu_dereference(dev->acked_features);
+       unsigned acked_features;
+
+       acked_features =
+               rcu_dereference_index_check(dev->acked_features,
+                                           lockdep_is_held(&dev->mutex));
        return acked_features & (1 << bit);
 }
 
index f6fdc2085f3e20147a4e9b0ae8ab4080c4fa4728..fed2a72bc6b60a1986172298fbb67bc0eca2b3bc 100644 (file)
@@ -554,12 +554,8 @@ void __init omap_vram_reserve_sdram_memblock(void)
        size = PAGE_ALIGN(size);
 
        if (paddr) {
-               struct memblock_property res;
-
-               res.base = paddr;
-               res.size = size;
-               if ((paddr & ~PAGE_MASK) || memblock_find(&res) ||
-                   res.base != paddr || res.size != size) {
+               if ((paddr & ~PAGE_MASK) ||
+                   !memblock_is_region_memory(paddr, size)) {
                        pr_err("Illegal SDRAM region for VRAM\n");
                        return;
                }
index a31a77ff6f3d2a3ac2daa56baeb6ae55430f6177..cea6403ae71c16ffbcded14282db1552244f8833 100644 (file)
@@ -784,12 +784,53 @@ failed:
        return ret;
 }
 
+static int __devexit pxa168fb_remove(struct platform_device *pdev)
+{
+       struct pxa168fb_info *fbi = platform_get_drvdata(pdev);
+       struct fb_info *info;
+       int irq;
+       unsigned int data;
+
+       if (!fbi)
+               return 0;
+
+       /* disable DMA transfer */
+       data = readl(fbi->reg_base + LCD_SPU_DMA_CTRL0);
+       data &= ~CFG_GRA_ENA_MASK;
+       writel(data, fbi->reg_base + LCD_SPU_DMA_CTRL0);
+
+       info = fbi->info;
+
+       unregister_framebuffer(info);
+
+       writel(GRA_FRAME_IRQ0_ENA(0x0), fbi->reg_base + SPU_IRQ_ENA);
+
+       if (info->cmap.len)
+               fb_dealloc_cmap(&info->cmap);
+
+       irq = platform_get_irq(pdev, 0);
+       free_irq(irq, fbi);
+
+       dma_free_writecombine(fbi->dev, PAGE_ALIGN(info->fix.smem_len),
+                               info->screen_base, info->fix.smem_start);
+
+       iounmap(fbi->reg_base);
+
+       clk_disable(fbi->clk);
+       clk_put(fbi->clk);
+
+       framebuffer_release(info);
+
+       return 0;
+}
+
 static struct platform_driver pxa168fb_driver = {
        .driver         = {
                .name   = "pxa168-fb",
                .owner  = THIS_MODULE,
        },
        .probe          = pxa168fb_probe,
+       .remove         = __devexit_p(pxa168fb_remove),
 };
 
 static int __init pxa168fb_init(void)
@@ -798,6 +839,12 @@ static int __init pxa168fb_init(void)
 }
 module_init(pxa168fb_init);
 
+static void __exit pxa168fb_exit(void)
+{
+       platform_driver_unregister(&pxa168fb_driver);
+}
+module_exit(pxa168fb_exit);
+
 MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> "
              "Green Wan <gwan@marvell.com>");
 MODULE_DESCRIPTION("Framebuffer driver for PXA168/910");
index f2d9e667972da120d3c39ab87965566fe5c13506..f885c868a04de186fe917bc01db66d55b2c846fd 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/irq.h>
 
 #include <linux/vlynq.h>
 
index 24efd8ea41bb04bab6830cfddfd2281881ec9ae7..c356146bd712bbe1b7a3af255f0d1f8fd9bd6646 100644 (file)
@@ -957,12 +957,32 @@ config PIKA_WDT
          the Warp platform.
 
 config BOOKE_WDT
-       bool "PowerPC Book-E Watchdog Timer"
+       tristate "PowerPC Book-E Watchdog Timer"
        depends on BOOKE || 4xx
        ---help---
+         Watchdog driver for PowerPC Book-E chips, such as the Freescale
+         MPC85xx SOCs and the IBM PowerPC 440.
+
          Please see Documentation/watchdog/watchdog-api.txt for
          more information.
 
+config BOOKE_WDT_DEFAULT_TIMEOUT
+       int "PowerPC Book-E Watchdog Timer Default Timeout"
+       depends on BOOKE_WDT
+       default 38 if FSL_BOOKE
+       range 0 63 if FSL_BOOKE
+       default 3 if !FSL_BOOKE
+       range 0 3 if !FSL_BOOKE
+       help
+         Select the default watchdog timer period to be used by the PowerPC
+         Book-E watchdog driver.  A watchdog "event" occurs when the bit
+         position represented by this number transitions from zero to one.
+
+         For Freescale Book-E processors, this is a number between 0 and 63.
+         For other Book-E processors, this is a number between 0 and 3.
+
+         The value can be overidden by the wdt_period command-line parameter.
+
 # PPC64 Architecture
 
 config WATCHDOG_RTAS
index 3d49671cdf5aebf1f78e52d0a92a185dd9026a31..d11ffb091b0dfc0fa67edb4422145ce959091182 100644 (file)
@@ -4,7 +4,7 @@
  * Author: Matthew McClintock
  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
  *
- * Copyright 2005, 2008 Freescale Semiconductor Inc.
+ * Copyright 2005, 2008, 2010 Freescale Semiconductor Inc.
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
  * occur, and the final time the board will reset.
  */
 
-#ifdef CONFIG_FSL_BOOKE
-#define WDT_PERIOD_DEFAULT 38  /* Ex. wdt_period=28 bus=333Mhz,reset=~40sec */
-#else
-#define WDT_PERIOD_DEFAULT 3   /* Refer to the PPC40x and PPC4xx manuals */
-#endif                         /* for timing information */
-
 u32 booke_wdt_enabled;
-u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
+u32 booke_wdt_period = CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT;
 
 #ifdef CONFIG_FSL_BOOKE
 #define WDTP(x)                ((((x)&0x3)<<30)|(((x)&0x3c)<<15))
@@ -114,6 +108,27 @@ static void __booke_wdt_enable(void *data)
        mtspr(SPRN_TCR, val);
 }
 
+/**
+ * booke_wdt_disable - disable the watchdog on the given CPU
+ *
+ * This function is called on each CPU.  It disables the watchdog on that CPU.
+ *
+ * TCR[WRC] cannot be changed once it has been set to non-zero, but we can
+ * effectively disable the watchdog by setting its period to the maximum value.
+ */
+static void __booke_wdt_disable(void *data)
+{
+       u32 val;
+
+       val = mfspr(SPRN_TCR);
+       val &= ~(TCR_WIE | WDTP_MASK);
+       mtspr(SPRN_TCR, val);
+
+       /* clear status to make sure nothing is pending */
+       __booke_wdt_ping(NULL);
+
+}
+
 static ssize_t booke_wdt_write(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
 {
@@ -193,12 +208,21 @@ static int booke_wdt_open(struct inode *inode, struct file *file)
        return nonseekable_open(inode, file);
 }
 
+static int booke_wdt_release(struct inode *inode, struct file *file)
+{
+       on_each_cpu(__booke_wdt_disable, NULL, 0);
+       booke_wdt_enabled = 0;
+
+       return 0;
+}
+
 static const struct file_operations booke_wdt_fops = {
        .owner = THIS_MODULE,
        .llseek = no_llseek,
        .write = booke_wdt_write,
        .unlocked_ioctl = booke_wdt_ioctl,
        .open = booke_wdt_open,
+       .release = booke_wdt_release,
 };
 
 static struct miscdevice booke_wdt_miscdev = {
@@ -237,4 +261,9 @@ static int __init booke_wdt_init(void)
 
        return ret;
 }
-device_initcall(booke_wdt_init);
+
+module_init(booke_wdt_init);
+module_exit(booke_wdt_exit);
+
+MODULE_DESCRIPTION("PowerPC Book-E watchdog driver");
+MODULE_LICENSE("GPL");
index 2a410170eca67c93b5472fdfa4c419c3bba2f58e..909923800a02291bee821038ca3b62f6eb0a1ea8 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/cpu.h>
 #include <linux/smp.h>
 #include <linux/fs.h>
+#include <linux/irq.h>
 
 #include <asm/mipsregs.h>
 #include <asm/uasm.h>
index 13365ba3521853eb738f6fa9b8eb68a010c3b04b..7d24b0d94ed4756615ef66b3304b270f66707ba4 100644 (file)
@@ -338,30 +338,29 @@ static void unmask_evtchn(int port)
 
 static int find_unbound_irq(void)
 {
-       int irq;
-       struct irq_desc *desc;
+       struct irq_data *data;
+       int irq, res;
 
        for (irq = 0; irq < nr_irqs; irq++) {
-               desc = irq_to_desc(irq);
+               data = irq_get_irq_data(irq);
                /* only 0->15 have init'd desc; handle irq > 16 */
-               if (desc == NULL)
+               if (!data)
                        break;
-               if (desc->chip == &no_irq_chip)
+               if (data->chip == &no_irq_chip)
                        break;
-               if (desc->chip != &xen_dynamic_chip)
+               if (data->chip != &xen_dynamic_chip)
                        continue;
                if (irq_info[irq].type == IRQT_UNBOUND)
-                       break;
+                       return irq;
        }
 
        if (irq == nr_irqs)
                panic("No available IRQ to bind to: increase nr_irqs!\n");
 
-       desc = irq_to_desc_alloc_node(irq, 0);
-       if (WARN_ON(desc == NULL))
-               return -1;
+       res = irq_alloc_desc_at(irq, 0);
 
-       dynamic_irq_init_keep_chip_data(irq);
+       if (WARN_ON(res != irq))
+               return -1;
 
        return irq;
 }
@@ -495,7 +494,7 @@ static void unbind_from_irq(unsigned int irq)
        if (irq_info[irq].type != IRQT_UNBOUND) {
                irq_info[irq] = mk_unbound_info();
 
-               dynamic_irq_cleanup(irq);
+               irq_free_desc(irq);
        }
 
        spin_unlock(&irq_mapping_update_lock);
index 33c4e7eef470e995246562b774fd88a82ca7f12b..9581ea94d5a146e95ba9533d1a7ac3aba2b83804 100644 (file)
@@ -109,8 +109,8 @@ static void init_once(void *foo)
 {
        struct affs_inode_info *ei = (struct affs_inode_info *) foo;
 
-       init_MUTEX(&ei->i_link_lock);
-       init_MUTEX(&ei->i_ext_lock);
+       sema_init(&ei->i_link_lock, 1);
+       sema_init(&ei->i_ext_lock, 1);
        inode_init_once(&ei->vfs_inode);
 }
 
index 535e763ab1a61e56ef5d25d725dc4f39eb899a49..6884e198e0c70d092192a34089d0b6d828e43f33 100644 (file)
@@ -800,7 +800,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
                         * default mmap base, as well as whatever program they
                         * might try to exec.  This is because the brk will
                         * follow the loader, and is not movable.  */
-#ifdef CONFIG_X86
+#if defined(CONFIG_X86) || defined(CONFIG_ARM)
                        load_bias = 0;
 #else
                        load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr);
index 0fcd2640c23fdda2c7fd99415b730837c591eba8..9eb134ea6eb223a45be745c77f9530b80fcdc082 100644 (file)
@@ -1,9 +1,11 @@
 config CEPH_FS
         tristate "Ceph distributed file system (EXPERIMENTAL)"
        depends on INET && EXPERIMENTAL
+       select CEPH_LIB
        select LIBCRC32C
        select CRYPTO_AES
        select CRYPTO
+       default n
        help
          Choose Y or M here to include support for mounting the
          experimental Ceph distributed file system.  Ceph is an extremely
@@ -14,15 +16,3 @@ config CEPH_FS
 
          If unsure, say N.
 
-config CEPH_FS_PRETTYDEBUG
-       bool "Include file:line in ceph debug output"
-       depends on CEPH_FS
-       default n
-       help
-         If you say Y here, debug output will include a filename and
-         line to aid debugging.  This icnreases kernel size and slows
-         execution slightly when debug call sites are enabled (e.g.,
-         via CONFIG_DYNAMIC_DEBUG).
-
-         If unsure, say N.
-
index 278e1172600dc3a3d5acba3654c53719d6f38697..9e6c4f2e8ff1f3e2712979d791da9e55fa780982 100644 (file)
@@ -8,15 +8,8 @@ obj-$(CONFIG_CEPH_FS) += ceph.o
 
 ceph-objs := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \
        export.o caps.o snap.o xattr.o \
-       messenger.o msgpool.o buffer.o pagelist.o \
-       mds_client.o mdsmap.o \
-       mon_client.o \
-       osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \
-       debugfs.o \
-       auth.o auth_none.o \
-       crypto.o armor.o \
-       auth_x.o \
-       ceph_fs.o ceph_strings.o ceph_hash.o ceph_frag.o
+       mds_client.o mdsmap.o strings.o ceph_frag.o \
+       debugfs.o
 
 else
 #Otherwise we were called directly from the command
diff --git a/fs/ceph/README b/fs/ceph/README
deleted file mode 100644 (file)
index 18352fa..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# The following files are shared by (and manually synchronized
-# between) the Ceph userland and kernel client.
-#
-# userland                  kernel
-src/include/ceph_fs.h      fs/ceph/ceph_fs.h
-src/include/ceph_fs.cc     fs/ceph/ceph_fs.c
-src/include/msgr.h         fs/ceph/msgr.h
-src/include/rados.h        fs/ceph/rados.h
-src/include/ceph_strings.cc fs/ceph/ceph_strings.c
-src/include/ceph_frag.h            fs/ceph/ceph_frag.h
-src/include/ceph_frag.cc    fs/ceph/ceph_frag.c
-src/include/ceph_hash.h            fs/ceph/ceph_hash.h
-src/include/ceph_hash.cc    fs/ceph/ceph_hash.c
-src/crush/crush.c          fs/ceph/crush/crush.c
-src/crush/crush.h          fs/ceph/crush/crush.h
-src/crush/mapper.c         fs/ceph/crush/mapper.c
-src/crush/mapper.h         fs/ceph/crush/mapper.h
-src/crush/hash.h           fs/ceph/crush/hash.h
-src/crush/hash.c           fs/ceph/crush/hash.c
index efbc604001c8bbfa3b96eb107529f0f03256b1a1..51bcc5ce323024a995d300b4a6035ecf8e72e94b 100644 (file)
@@ -1,4 +1,4 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/backing-dev.h>
 #include <linux/fs.h>
@@ -10,7 +10,8 @@
 #include <linux/task_io_accounting_ops.h>
 
 #include "super.h"
-#include "osd_client.h"
+#include "mds_client.h"
+#include <linux/ceph/osd_client.h>
 
 /*
  * Ceph address space ops.
@@ -193,7 +194,8 @@ static int readpage_nounlock(struct file *filp, struct page *page)
 {
        struct inode *inode = filp->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->osdc;
+       struct ceph_osd_client *osdc = 
+               &ceph_inode_to_client(inode)->client->osdc;
        int err = 0;
        u64 len = PAGE_CACHE_SIZE;
 
@@ -265,7 +267,8 @@ static int ceph_readpages(struct file *file, struct address_space *mapping,
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_osd_client *osdc = &ceph_inode_to_client(inode)->osdc;
+       struct ceph_osd_client *osdc =
+               &ceph_inode_to_client(inode)->client->osdc;
        int rc = 0;
        struct page **pages;
        loff_t offset;
@@ -365,7 +368,7 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
 {
        struct inode *inode;
        struct ceph_inode_info *ci;
-       struct ceph_client *client;
+       struct ceph_fs_client *fsc;
        struct ceph_osd_client *osdc;
        loff_t page_off = page->index << PAGE_CACHE_SHIFT;
        int len = PAGE_CACHE_SIZE;
@@ -383,8 +386,8 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
        }
        inode = page->mapping->host;
        ci = ceph_inode(inode);
-       client = ceph_inode_to_client(inode);
-       osdc = &client->osdc;
+       fsc = ceph_inode_to_client(inode);
+       osdc = &fsc->client->osdc;
 
        /* verify this is a writeable snap context */
        snapc = (void *)page->private;
@@ -414,10 +417,10 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
        dout("writepage %p page %p index %lu on %llu~%u snapc %p\n",
             inode, page, page->index, page_off, len, snapc);
 
-       writeback_stat = atomic_long_inc_return(&client->writeback_count);
+       writeback_stat = atomic_long_inc_return(&fsc->writeback_count);
        if (writeback_stat >
-           CONGESTION_ON_THRESH(client->mount_args->congestion_kb))
-               set_bdi_congested(&client->backing_dev_info, BLK_RW_ASYNC);
+           CONGESTION_ON_THRESH(fsc->mount_options->congestion_kb))
+               set_bdi_congested(&fsc->backing_dev_info, BLK_RW_ASYNC);
 
        set_page_writeback(page);
        err = ceph_osdc_writepages(osdc, ceph_vino(inode),
@@ -496,7 +499,7 @@ static void writepages_finish(struct ceph_osd_request *req,
        struct address_space *mapping = inode->i_mapping;
        __s32 rc = -EIO;
        u64 bytes = 0;
-       struct ceph_client *client = ceph_inode_to_client(inode);
+       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
        long writeback_stat;
        unsigned issued = ceph_caps_issued(ci);
 
@@ -529,10 +532,10 @@ static void writepages_finish(struct ceph_osd_request *req,
                WARN_ON(!PageUptodate(page));
 
                writeback_stat =
-                       atomic_long_dec_return(&client->writeback_count);
+                       atomic_long_dec_return(&fsc->writeback_count);
                if (writeback_stat <
-                   CONGESTION_OFF_THRESH(client->mount_args->congestion_kb))
-                       clear_bdi_congested(&client->backing_dev_info,
+                   CONGESTION_OFF_THRESH(fsc->mount_options->congestion_kb))
+                       clear_bdi_congested(&fsc->backing_dev_info,
                                            BLK_RW_ASYNC);
 
                ceph_put_snap_context((void *)page->private);
@@ -569,13 +572,13 @@ static void writepages_finish(struct ceph_osd_request *req,
  * mempool.  we avoid the mempool if we can because req->r_num_pages
  * may be less than the maximum write size.
  */
-static void alloc_page_vec(struct ceph_client *client,
+static void alloc_page_vec(struct ceph_fs_client *fsc,
                           struct ceph_osd_request *req)
 {
        req->r_pages = kmalloc(sizeof(struct page *) * req->r_num_pages,
                               GFP_NOFS);
        if (!req->r_pages) {
-               req->r_pages = mempool_alloc(client->wb_pagevec_pool, GFP_NOFS);
+               req->r_pages = mempool_alloc(fsc->wb_pagevec_pool, GFP_NOFS);
                req->r_pages_from_pool = 1;
                WARN_ON(!req->r_pages);
        }
@@ -590,7 +593,7 @@ static int ceph_writepages_start(struct address_space *mapping,
        struct inode *inode = mapping->host;
        struct backing_dev_info *bdi = mapping->backing_dev_info;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_client *client;
+       struct ceph_fs_client *fsc;
        pgoff_t index, start, end;
        int range_whole = 0;
        int should_loop = 1;
@@ -617,13 +620,13 @@ static int ceph_writepages_start(struct address_space *mapping,
             wbc->sync_mode == WB_SYNC_NONE ? "NONE" :
             (wbc->sync_mode == WB_SYNC_ALL ? "ALL" : "HOLD"));
 
-       client = ceph_inode_to_client(inode);
-       if (client->mount_state == CEPH_MOUNT_SHUTDOWN) {
+       fsc = ceph_inode_to_client(inode);
+       if (fsc->mount_state == CEPH_MOUNT_SHUTDOWN) {
                pr_warning("writepage_start %p on forced umount\n", inode);
                return -EIO; /* we're in a forced umount, don't write! */
        }
-       if (client->mount_args->wsize && client->mount_args->wsize < wsize)
-               wsize = client->mount_args->wsize;
+       if (fsc->mount_options->wsize && fsc->mount_options->wsize < wsize)
+               wsize = fsc->mount_options->wsize;
        if (wsize < PAGE_CACHE_SIZE)
                wsize = PAGE_CACHE_SIZE;
        max_pages_ever = wsize >> PAGE_CACHE_SHIFT;
@@ -769,7 +772,7 @@ get_more_pages:
                                offset = (unsigned long long)page->index
                                        << PAGE_CACHE_SHIFT;
                                len = wsize;
-                               req = ceph_osdc_new_request(&client->osdc,
+                               req = ceph_osdc_new_request(&fsc->client->osdc,
                                            &ci->i_layout,
                                            ceph_vino(inode),
                                            offset, &len,
@@ -782,7 +785,7 @@ get_more_pages:
                                            &inode->i_mtime, true, 1);
                                max_pages = req->r_num_pages;
 
-                               alloc_page_vec(client, req);
+                               alloc_page_vec(fsc, req);
                                req->r_callback = writepages_finish;
                                req->r_inode = inode;
                        }
@@ -794,10 +797,10 @@ get_more_pages:
                             inode, page, page->index);
 
                        writeback_stat =
-                              atomic_long_inc_return(&client->writeback_count);
+                              atomic_long_inc_return(&fsc->writeback_count);
                        if (writeback_stat > CONGESTION_ON_THRESH(
-                                   client->mount_args->congestion_kb)) {
-                               set_bdi_congested(&client->backing_dev_info,
+                                   fsc->mount_options->congestion_kb)) {
+                               set_bdi_congested(&fsc->backing_dev_info,
                                                  BLK_RW_ASYNC);
                        }
 
@@ -846,7 +849,7 @@ get_more_pages:
                op->payload_len = cpu_to_le32(len);
                req->r_request->hdr.data_len = cpu_to_le32(len);
 
-               ceph_osdc_start_request(&client->osdc, req, true);
+               ceph_osdc_start_request(&fsc->client->osdc, req, true);
                req = NULL;
 
                /* continue? */
@@ -915,7 +918,7 @@ static int ceph_update_writeable_page(struct file *file,
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        loff_t page_off = pos & PAGE_CACHE_MASK;
        int pos_in_page = pos & ~PAGE_CACHE_MASK;
        int end_in_page = pos_in_page + len;
@@ -1053,8 +1056,8 @@ static int ceph_write_end(struct file *file, struct address_space *mapping,
                          struct page *page, void *fsdata)
 {
        struct inode *inode = file->f_dentry->d_inode;
-       struct ceph_client *client = ceph_inode_to_client(inode);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        unsigned from = pos & (PAGE_CACHE_SIZE - 1);
        int check_cap = 0;
 
@@ -1123,7 +1126,7 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct inode *inode = vma->vm_file->f_dentry->d_inode;
        struct page *page = vmf->page;
-       struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        loff_t off = page->index << PAGE_CACHE_SHIFT;
        loff_t size, len;
        int ret;
index 5e9da996a1519c42880872267d7609cc82eb2dc2..98ab13e2b71d9d8ebcbf1715da112d78cb0bac17 100644 (file)
@@ -1,4 +1,4 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -9,8 +9,9 @@
 #include <linux/writeback.h>
 
 #include "super.h"
-#include "decode.h"
-#include "messenger.h"
+#include "mds_client.h"
+#include <linux/ceph/decode.h>
+#include <linux/ceph/messenger.h>
 
 /*
  * Capability management
@@ -287,11 +288,11 @@ void ceph_put_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap)
        spin_unlock(&mdsc->caps_list_lock);
 }
 
-void ceph_reservation_status(struct ceph_client *client,
+void ceph_reservation_status(struct ceph_fs_client *fsc,
                             int *total, int *avail, int *used, int *reserved,
                             int *min)
 {
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_client *mdsc = fsc->mdsc;
 
        if (total)
                *total = mdsc->caps_total_count;
@@ -399,7 +400,7 @@ static void __insert_cap_node(struct ceph_inode_info *ci,
 static void __cap_set_timeouts(struct ceph_mds_client *mdsc,
                               struct ceph_inode_info *ci)
 {
-       struct ceph_mount_args *ma = mdsc->client->mount_args;
+       struct ceph_mount_options *ma = mdsc->fsc->mount_options;
 
        ci->i_hold_caps_min = round_jiffies(jiffies +
                                            ma->caps_wanted_delay_min * HZ);
@@ -515,7 +516,7 @@ int ceph_add_cap(struct inode *inode,
                 unsigned seq, unsigned mseq, u64 realmino, int flags,
                 struct ceph_cap_reservation *caps_reservation)
 {
-       struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_cap *new_cap = NULL;
        struct ceph_cap *cap;
@@ -873,7 +874,7 @@ void __ceph_remove_cap(struct ceph_cap *cap)
        struct ceph_mds_session *session = cap->session;
        struct ceph_inode_info *ci = cap->ci;
        struct ceph_mds_client *mdsc =
-               &ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
+               ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
        int removed = 0;
 
        dout("__ceph_remove_cap %p from %p\n", cap, &ci->vfs_inode);
@@ -1210,7 +1211,7 @@ void __ceph_flush_snaps(struct ceph_inode_info *ci,
        int mds;
        struct ceph_cap_snap *capsnap;
        u32 mseq;
-       struct ceph_mds_client *mdsc = &ceph_inode_to_client(inode)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        struct ceph_mds_session *session = NULL; /* if session != NULL, we hold
                                                    session->s_mutex */
        u64 next_follows = 0;  /* keep track of how far we've gotten through the
@@ -1336,7 +1337,7 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci)
 void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
 {
        struct ceph_mds_client *mdsc =
-               &ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
+               ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
        struct inode *inode = &ci->vfs_inode;
        int was = ci->i_dirty_caps;
        int dirty = 0;
@@ -1378,7 +1379,7 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
 static int __mark_caps_flushing(struct inode *inode,
                                 struct ceph_mds_session *session)
 {
-       struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        int flushing;
 
@@ -1416,17 +1417,6 @@ static int __mark_caps_flushing(struct inode *inode,
 /*
  * try to invalidate mapping pages without blocking.
  */
-static int mapping_is_empty(struct address_space *mapping)
-{
-       struct page *page = find_get_page(mapping, 0);
-
-       if (!page)
-               return 1;
-
-       put_page(page);
-       return 0;
-}
-
 static int try_nonblocking_invalidate(struct inode *inode)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
@@ -1436,7 +1426,7 @@ static int try_nonblocking_invalidate(struct inode *inode)
        invalidate_mapping_pages(&inode->i_data, 0, -1);
        spin_lock(&inode->i_lock);
 
-       if (mapping_is_empty(&inode->i_data) &&
+       if (inode->i_data.nrpages == 0 &&
            invalidating_gen == ci->i_rdcache_gen) {
                /* success. */
                dout("try_nonblocking_invalidate %p success\n", inode);
@@ -1462,8 +1452,8 @@ static int try_nonblocking_invalidate(struct inode *inode)
 void ceph_check_caps(struct ceph_inode_info *ci, int flags,
                     struct ceph_mds_session *session)
 {
-       struct ceph_client *client = ceph_inode_to_client(&ci->vfs_inode);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_inode_to_client(&ci->vfs_inode);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct inode *inode = &ci->vfs_inode;
        struct ceph_cap *cap;
        int file_wanted, used;
@@ -1533,7 +1523,7 @@ retry_locked:
         */
        if ((!is_delayed || mdsc->stopping) &&
            ci->i_wrbuffer_ref == 0 &&               /* no dirty pages... */
-           ci->i_rdcache_gen &&                     /* may have cached pages */
+           inode->i_data.nrpages &&                 /* have cached pages */
            (file_wanted == 0 ||                     /* no open files */
             (revoking & (CEPH_CAP_FILE_CACHE|
                          CEPH_CAP_FILE_LAZYIO))) && /*  or revoking cache */
@@ -1706,7 +1696,7 @@ ack:
 static int try_flush_caps(struct inode *inode, struct ceph_mds_session *session,
                          unsigned *flush_tid)
 {
-       struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
        int unlock_session = session ? 0 : 1;
        int flushing = 0;
@@ -1872,7 +1862,7 @@ int ceph_write_inode(struct inode *inode, struct writeback_control *wbc)
                                       caps_are_flushed(inode, flush_tid));
        } else {
                struct ceph_mds_client *mdsc =
-                       &ceph_sb_to_client(inode->i_sb)->mdsc;
+                       ceph_sb_to_client(inode->i_sb)->mdsc;
 
                spin_lock(&inode->i_lock);
                if (__ceph_caps_dirty(ci))
@@ -2465,7 +2455,7 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
        __releases(inode->i_lock)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        unsigned seq = le32_to_cpu(m->seq);
        int dirty = le32_to_cpu(m->dirty);
        int cleaned = 0;
@@ -2713,7 +2703,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                      struct ceph_msg *msg)
 {
        struct ceph_mds_client *mdsc = session->s_mdsc;
-       struct super_block *sb = mdsc->client->sb;
+       struct super_block *sb = mdsc->fsc->sb;
        struct inode *inode;
        struct ceph_cap *cap;
        struct ceph_mds_caps *h;
index ab6cf35c40919843e40f29137500e45a8170e5ab..bdce8b1fbd06794d9de7be918c9ab8aab97bcbd2 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Ceph 'frag' type
  */
-#include "types.h"
+#include <linux/module.h>
+#include <linux/ceph/types.h>
 
 int ceph_frag_compare(__u32 a, __u32 b)
 {
index 6fd8b20a86112c367c788a20c2f134108acc40e8..7ae1b3d55b58a7b70bf55e79a0788f211b90ff3c 100644 (file)
@@ -1,4 +1,4 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/mon_client.h>
+#include <linux/ceph/auth.h>
+#include <linux/ceph/debugfs.h>
+
 #include "super.h"
-#include "mds_client.h"
-#include "mon_client.h"
-#include "auth.h"
 
 #ifdef CONFIG_DEBUG_FS
 
-/*
- * Implement /sys/kernel/debug/ceph fun
- *
- * /sys/kernel/debug/ceph/client*  - an instance of the ceph client
- *      .../osdmap      - current osdmap
- *      .../mdsmap      - current mdsmap
- *      .../monmap      - current monmap
- *      .../osdc        - active osd requests
- *      .../mdsc        - active mds requests
- *      .../monc        - mon client state
- *      .../dentry_lru  - dump contents of dentry lru
- *      .../caps        - expose cap (reservation) stats
- *      .../bdi         - symlink to ../../bdi/something
- */
-
-static struct dentry *ceph_debugfs_dir;
-
-static int monmap_show(struct seq_file *s, void *p)
-{
-       int i;
-       struct ceph_client *client = s->private;
-
-       if (client->monc.monmap == NULL)
-               return 0;
-
-       seq_printf(s, "epoch %d\n", client->monc.monmap->epoch);
-       for (i = 0; i < client->monc.monmap->num_mon; i++) {
-               struct ceph_entity_inst *inst =
-                       &client->monc.monmap->mon_inst[i];
-
-               seq_printf(s, "\t%s%lld\t%s\n",
-                          ENTITY_NAME(inst->name),
-                          pr_addr(&inst->addr.in_addr));
-       }
-       return 0;
-}
+#include "mds_client.h"
 
 static int mdsmap_show(struct seq_file *s, void *p)
 {
        int i;
-       struct ceph_client *client = s->private;
+       struct ceph_fs_client *fsc = s->private;
 
-       if (client->mdsc.mdsmap == NULL)
+       if (fsc->mdsc == NULL || fsc->mdsc->mdsmap == NULL)
                return 0;
-       seq_printf(s, "epoch %d\n", client->mdsc.mdsmap->m_epoch);
-       seq_printf(s, "root %d\n", client->mdsc.mdsmap->m_root);
+       seq_printf(s, "epoch %d\n", fsc->mdsc->mdsmap->m_epoch);
+       seq_printf(s, "root %d\n", fsc->mdsc->mdsmap->m_root);
        seq_printf(s, "session_timeout %d\n",
-                      client->mdsc.mdsmap->m_session_timeout);
+                      fsc->mdsc->mdsmap->m_session_timeout);
        seq_printf(s, "session_autoclose %d\n",
-                      client->mdsc.mdsmap->m_session_autoclose);
-       for (i = 0; i < client->mdsc.mdsmap->m_max_mds; i++) {
+                      fsc->mdsc->mdsmap->m_session_autoclose);
+       for (i = 0; i < fsc->mdsc->mdsmap->m_max_mds; i++) {
                struct ceph_entity_addr *addr =
-                       &client->mdsc.mdsmap->m_info[i].addr;
-               int state = client->mdsc.mdsmap->m_info[i].state;
+                       &fsc->mdsc->mdsmap->m_info[i].addr;
+               int state = fsc->mdsc->mdsmap->m_info[i].state;
 
-               seq_printf(s, "\tmds%d\t%s\t(%s)\n", i, pr_addr(&addr->in_addr),
+               seq_printf(s, "\tmds%d\t%s\t(%s)\n", i,
+                              ceph_pr_addr(&addr->in_addr),
                               ceph_mds_state_name(state));
        }
        return 0;
 }
 
-static int osdmap_show(struct seq_file *s, void *p)
-{
-       int i;
-       struct ceph_client *client = s->private;
-       struct rb_node *n;
-
-       if (client->osdc.osdmap == NULL)
-               return 0;
-       seq_printf(s, "epoch %d\n", client->osdc.osdmap->epoch);
-       seq_printf(s, "flags%s%s\n",
-                  (client->osdc.osdmap->flags & CEPH_OSDMAP_NEARFULL) ?
-                  " NEARFULL" : "",
-                  (client->osdc.osdmap->flags & CEPH_OSDMAP_FULL) ?
-                  " FULL" : "");
-       for (n = rb_first(&client->osdc.osdmap->pg_pools); n; n = rb_next(n)) {
-               struct ceph_pg_pool_info *pool =
-                       rb_entry(n, struct ceph_pg_pool_info, node);
-               seq_printf(s, "pg_pool %d pg_num %d / %d, lpg_num %d / %d\n",
-                          pool->id, pool->v.pg_num, pool->pg_num_mask,
-                          pool->v.lpg_num, pool->lpg_num_mask);
-       }
-       for (i = 0; i < client->osdc.osdmap->max_osd; i++) {
-               struct ceph_entity_addr *addr =
-                       &client->osdc.osdmap->osd_addr[i];
-               int state = client->osdc.osdmap->osd_state[i];
-               char sb[64];
-
-               seq_printf(s, "\tosd%d\t%s\t%3d%%\t(%s)\n",
-                          i, pr_addr(&addr->in_addr),
-                          ((client->osdc.osdmap->osd_weight[i]*100) >> 16),
-                          ceph_osdmap_state_str(sb, sizeof(sb), state));
-       }
-       return 0;
-}
-
-static int monc_show(struct seq_file *s, void *p)
-{
-       struct ceph_client *client = s->private;
-       struct ceph_mon_generic_request *req;
-       struct ceph_mon_client *monc = &client->monc;
-       struct rb_node *rp;
-
-       mutex_lock(&monc->mutex);
-
-       if (monc->have_mdsmap)
-               seq_printf(s, "have mdsmap %u\n", (unsigned)monc->have_mdsmap);
-       if (monc->have_osdmap)
-               seq_printf(s, "have osdmap %u\n", (unsigned)monc->have_osdmap);
-       if (monc->want_next_osdmap)
-               seq_printf(s, "want next osdmap\n");
-
-       for (rp = rb_first(&monc->generic_request_tree); rp; rp = rb_next(rp)) {
-               __u16 op;
-               req = rb_entry(rp, struct ceph_mon_generic_request, node);
-               op = le16_to_cpu(req->request->hdr.type);
-               if (op == CEPH_MSG_STATFS)
-                       seq_printf(s, "%lld statfs\n", req->tid);
-               else
-                       seq_printf(s, "%lld unknown\n", req->tid);
-       }
-
-       mutex_unlock(&monc->mutex);
-       return 0;
-}
-
+/*
+ * mdsc debugfs
+ */
 static int mdsc_show(struct seq_file *s, void *p)
 {
-       struct ceph_client *client = s->private;
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = s->private;
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        struct rb_node *rp;
        int pathlen;
@@ -214,61 +120,12 @@ static int mdsc_show(struct seq_file *s, void *p)
        return 0;
 }
 
-static int osdc_show(struct seq_file *s, void *pp)
-{
-       struct ceph_client *client = s->private;
-       struct ceph_osd_client *osdc = &client->osdc;
-       struct rb_node *p;
-
-       mutex_lock(&osdc->request_mutex);
-       for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
-               struct ceph_osd_request *req;
-               struct ceph_osd_request_head *head;
-               struct ceph_osd_op *op;
-               int num_ops;
-               int opcode, olen;
-               int i;
-
-               req = rb_entry(p, struct ceph_osd_request, r_node);
-
-               seq_printf(s, "%lld\tosd%d\t%d.%x\t", req->r_tid,
-                          req->r_osd ? req->r_osd->o_osd : -1,
-                          le32_to_cpu(req->r_pgid.pool),
-                          le16_to_cpu(req->r_pgid.ps));
-
-               head = req->r_request->front.iov_base;
-               op = (void *)(head + 1);
-
-               num_ops = le16_to_cpu(head->num_ops);
-               olen = le32_to_cpu(head->object_len);
-               seq_printf(s, "%.*s", olen,
-                          (const char *)(head->ops + num_ops));
-
-               if (req->r_reassert_version.epoch)
-                       seq_printf(s, "\t%u'%llu",
-                          (unsigned)le32_to_cpu(req->r_reassert_version.epoch),
-                          le64_to_cpu(req->r_reassert_version.version));
-               else
-                       seq_printf(s, "\t");
-
-               for (i = 0; i < num_ops; i++) {
-                       opcode = le16_to_cpu(op->op);
-                       seq_printf(s, "\t%s", ceph_osd_op_name(opcode));
-                       op++;
-               }
-
-               seq_printf(s, "\n");
-       }
-       mutex_unlock(&osdc->request_mutex);
-       return 0;
-}
-
 static int caps_show(struct seq_file *s, void *p)
 {
-       struct ceph_client *client = s->private;
+       struct ceph_fs_client *fsc = s->private;
        int total, avail, used, reserved, min;
 
-       ceph_reservation_status(client, &total, &avail, &used, &reserved, &min);
+       ceph_reservation_status(fsc, &total, &avail, &used, &reserved, &min);
        seq_printf(s, "total\t\t%d\n"
                   "avail\t\t%d\n"
                   "used\t\t%d\n"
@@ -280,8 +137,8 @@ static int caps_show(struct seq_file *s, void *p)
 
 static int dentry_lru_show(struct seq_file *s, void *ptr)
 {
-       struct ceph_client *client = s->private;
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = s->private;
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_dentry_info *di;
 
        spin_lock(&mdsc->dentry_lru_lock);
@@ -295,199 +152,124 @@ static int dentry_lru_show(struct seq_file *s, void *ptr)
        return 0;
 }
 
-#define DEFINE_SHOW_FUNC(name)                                         \
-static int name##_open(struct inode *inode, struct file *file)         \
-{                                                                      \
-       struct seq_file *sf;                                            \
-       int ret;                                                        \
-                                                                       \
-       ret = single_open(file, name, NULL);                            \
-       sf = file->private_data;                                        \
-       sf->private = inode->i_private;                                 \
-       return ret;                                                     \
-}                                                                      \
-                                                                       \
-static const struct file_operations name##_fops = {                    \
-       .open           = name##_open,                                  \
-       .read           = seq_read,                                     \
-       .llseek         = seq_lseek,                                    \
-       .release        = single_release,                               \
-};
-
-DEFINE_SHOW_FUNC(monmap_show)
-DEFINE_SHOW_FUNC(mdsmap_show)
-DEFINE_SHOW_FUNC(osdmap_show)
-DEFINE_SHOW_FUNC(monc_show)
-DEFINE_SHOW_FUNC(mdsc_show)
-DEFINE_SHOW_FUNC(osdc_show)
-DEFINE_SHOW_FUNC(dentry_lru_show)
-DEFINE_SHOW_FUNC(caps_show)
+CEPH_DEFINE_SHOW_FUNC(mdsmap_show)
+CEPH_DEFINE_SHOW_FUNC(mdsc_show)
+CEPH_DEFINE_SHOW_FUNC(caps_show)
+CEPH_DEFINE_SHOW_FUNC(dentry_lru_show)
+
 
+/*
+ * debugfs
+ */
 static int congestion_kb_set(void *data, u64 val)
 {
-       struct ceph_client *client = (struct ceph_client *)data;
-
-       if (client)
-               client->mount_args->congestion_kb = (int)val;
+       struct ceph_fs_client *fsc = (struct ceph_fs_client *)data;
 
+       fsc->mount_options->congestion_kb = (int)val;
        return 0;
 }
 
 static int congestion_kb_get(void *data, u64 *val)
 {
-       struct ceph_client *client = (struct ceph_client *)data;
-
-       if (client)
-               *val = (u64)client->mount_args->congestion_kb;
+       struct ceph_fs_client *fsc = (struct ceph_fs_client *)data;
 
+       *val = (u64)fsc->mount_options->congestion_kb;
        return 0;
 }
 
-
 DEFINE_SIMPLE_ATTRIBUTE(congestion_kb_fops, congestion_kb_get,
                        congestion_kb_set, "%llu\n");
 
-int __init ceph_debugfs_init(void)
-{
-       ceph_debugfs_dir = debugfs_create_dir("ceph", NULL);
-       if (!ceph_debugfs_dir)
-               return -ENOMEM;
-       return 0;
-}
 
-void ceph_debugfs_cleanup(void)
+void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc)
 {
-       debugfs_remove(ceph_debugfs_dir);
+       dout("ceph_fs_debugfs_cleanup\n");
+       debugfs_remove(fsc->debugfs_bdi);
+       debugfs_remove(fsc->debugfs_congestion_kb);
+       debugfs_remove(fsc->debugfs_mdsmap);
+       debugfs_remove(fsc->debugfs_caps);
+       debugfs_remove(fsc->debugfs_mdsc);
+       debugfs_remove(fsc->debugfs_dentry_lru);
 }
 
-int ceph_debugfs_client_init(struct ceph_client *client)
+int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
 {
-       int ret = 0;
-       char name[80];
-
-       snprintf(name, sizeof(name), "%pU.client%lld", &client->fsid,
-                client->monc.auth->global_id);
+       char name[100];
+       int err = -ENOMEM;
 
-       client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir);
-       if (!client->debugfs_dir)
-               goto out;
-
-       client->monc.debugfs_file = debugfs_create_file("monc",
-                                                     0600,
-                                                     client->debugfs_dir,
-                                                     client,
-                                                     &monc_show_fops);
-       if (!client->monc.debugfs_file)
+       dout("ceph_fs_debugfs_init\n");
+       fsc->debugfs_congestion_kb =
+               debugfs_create_file("writeback_congestion_kb",
+                                   0600,
+                                   fsc->client->debugfs_dir,
+                                   fsc,
+                                   &congestion_kb_fops);
+       if (!fsc->debugfs_congestion_kb)
                goto out;
 
-       client->mdsc.debugfs_file = debugfs_create_file("mdsc",
-                                                     0600,
-                                                     client->debugfs_dir,
-                                                     client,
-                                                     &mdsc_show_fops);
-       if (!client->mdsc.debugfs_file)
-               goto out;
+       dout("a\n");
 
-       client->osdc.debugfs_file = debugfs_create_file("osdc",
-                                                     0600,
-                                                     client->debugfs_dir,
-                                                     client,
-                                                     &osdc_show_fops);
-       if (!client->osdc.debugfs_file)
+       snprintf(name, sizeof(name), "../../bdi/%s",
+                dev_name(fsc->backing_dev_info.dev));
+       fsc->debugfs_bdi =
+               debugfs_create_symlink("bdi",
+                                      fsc->client->debugfs_dir,
+                                      name);
+       if (!fsc->debugfs_bdi)
                goto out;
 
-       client->debugfs_monmap = debugfs_create_file("monmap",
+       dout("b\n");
+       fsc->debugfs_mdsmap = debugfs_create_file("mdsmap",
                                        0600,
-                                       client->debugfs_dir,
-                                       client,
-                                       &monmap_show_fops);
-       if (!client->debugfs_monmap)
-               goto out;
-
-       client->debugfs_mdsmap = debugfs_create_file("mdsmap",
-                                       0600,
-                                       client->debugfs_dir,
-                                       client,
+                                       fsc->client->debugfs_dir,
+                                       fsc,
                                        &mdsmap_show_fops);
-       if (!client->debugfs_mdsmap)
-               goto out;
-
-       client->debugfs_osdmap = debugfs_create_file("osdmap",
-                                       0600,
-                                       client->debugfs_dir,
-                                       client,
-                                       &osdmap_show_fops);
-       if (!client->debugfs_osdmap)
+       if (!fsc->debugfs_mdsmap)
                goto out;
 
-       client->debugfs_dentry_lru = debugfs_create_file("dentry_lru",
-                                       0600,
-                                       client->debugfs_dir,
-                                       client,
-                                       &dentry_lru_show_fops);
-       if (!client->debugfs_dentry_lru)
+       dout("ca\n");
+       fsc->debugfs_mdsc = debugfs_create_file("mdsc",
+                                               0600,
+                                               fsc->client->debugfs_dir,
+                                               fsc,
+                                               &mdsc_show_fops);
+       if (!fsc->debugfs_mdsc)
                goto out;
 
-       client->debugfs_caps = debugfs_create_file("caps",
+       dout("da\n");
+       fsc->debugfs_caps = debugfs_create_file("caps",
                                                   0400,
-                                                  client->debugfs_dir,
-                                                  client,
+                                                  fsc->client->debugfs_dir,
+                                                  fsc,
                                                   &caps_show_fops);
-       if (!client->debugfs_caps)
+       if (!fsc->debugfs_caps)
                goto out;
 
-       client->debugfs_congestion_kb =
-               debugfs_create_file("writeback_congestion_kb",
-                                   0600,
-                                   client->debugfs_dir,
-                                   client,
-                                   &congestion_kb_fops);
-       if (!client->debugfs_congestion_kb)
+       dout("ea\n");
+       fsc->debugfs_dentry_lru = debugfs_create_file("dentry_lru",
+                                       0600,
+                                       fsc->client->debugfs_dir,
+                                       fsc,
+                                       &dentry_lru_show_fops);
+       if (!fsc->debugfs_dentry_lru)
                goto out;
 
-       sprintf(name, "../../bdi/%s", dev_name(client->sb->s_bdi->dev));
-       client->debugfs_bdi = debugfs_create_symlink("bdi", client->debugfs_dir,
-                                                    name);
-
        return 0;
 
 out:
-       ceph_debugfs_client_cleanup(client);
-       return ret;
+       ceph_fs_debugfs_cleanup(fsc);
+       return err;
 }
 
-void ceph_debugfs_client_cleanup(struct ceph_client *client)
-{
-       debugfs_remove(client->debugfs_bdi);
-       debugfs_remove(client->debugfs_caps);
-       debugfs_remove(client->debugfs_dentry_lru);
-       debugfs_remove(client->debugfs_osdmap);
-       debugfs_remove(client->debugfs_mdsmap);
-       debugfs_remove(client->debugfs_monmap);
-       debugfs_remove(client->osdc.debugfs_file);
-       debugfs_remove(client->mdsc.debugfs_file);
-       debugfs_remove(client->monc.debugfs_file);
-       debugfs_remove(client->debugfs_congestion_kb);
-       debugfs_remove(client->debugfs_dir);
-}
 
 #else  /* CONFIG_DEBUG_FS */
 
-int __init ceph_debugfs_init(void)
-{
-       return 0;
-}
-
-void ceph_debugfs_cleanup(void)
-{
-}
-
-int ceph_debugfs_client_init(struct ceph_client *client)
+int ceph_fs_debugfs_init(struct ceph_fs_client *fsc)
 {
        return 0;
 }
 
-void ceph_debugfs_client_cleanup(struct ceph_client *client)
+void ceph_fs_debugfs_cleanup(struct ceph_fs_client *fsc)
 {
 }
 
index a1986eb52045b8184d6ab31e46b8a2497295e9ba..e0a2dc6fcafcb62266909c5ec71329e58083d1d7 100644 (file)
@@ -1,4 +1,4 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/spinlock.h>
 #include <linux/fs_struct.h>
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 
 #include "super.h"
+#include "mds_client.h"
 
 /*
  * Directory operations: readdir, lookup, create, link, unlink,
@@ -94,10 +95,7 @@ static unsigned fpos_off(loff_t p)
  */
 static int __dcache_readdir(struct file *filp,
                            void *dirent, filldir_t filldir)
-               __releases(inode->i_lock)
-               __acquires(inode->i_lock)
 {
-       struct inode *inode = filp->f_dentry->d_inode;
        struct ceph_file_info *fi = filp->private_data;
        struct dentry *parent = filp->f_dentry;
        struct inode *dir = parent->d_inode;
@@ -153,7 +151,6 @@ more:
 
        atomic_inc(&dentry->d_count);
        spin_unlock(&dcache_lock);
-       spin_unlock(&inode->i_lock);
 
        dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos,
             dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
@@ -171,35 +168,30 @@ more:
                } else {
                        dput(last);
                }
-               last = NULL;
        }
-
-       spin_lock(&inode->i_lock);
-       spin_lock(&dcache_lock);
-
        last = dentry;
 
        if (err < 0)
-               goto out_unlock;
+               goto out;
 
-       p = p->prev;
        filp->f_pos++;
 
        /* make sure a dentry wasn't dropped while we didn't have dcache_lock */
-       if ((ceph_inode(dir)->i_ceph_flags & CEPH_I_COMPLETE))
-               goto more;
-       dout(" lost I_COMPLETE on %p; falling back to mds\n", dir);
-       err = -EAGAIN;
+       if (!ceph_i_test(dir, CEPH_I_COMPLETE)) {
+               dout(" lost I_COMPLETE on %p; falling back to mds\n", dir);
+               err = -EAGAIN;
+               goto out;
+       }
+
+       spin_lock(&dcache_lock);
+       p = p->prev;    /* advance to next dentry */
+       goto more;
 
 out_unlock:
        spin_unlock(&dcache_lock);
-
-       if (last) {
-               spin_unlock(&inode->i_lock);
+out:
+       if (last)
                dput(last);
-               spin_lock(&inode->i_lock);
-       }
-
        return err;
 }
 
@@ -227,15 +219,15 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
        struct ceph_file_info *fi = filp->private_data;
        struct inode *inode = filp->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_client *client = ceph_inode_to_client(inode);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        unsigned frag = fpos_frag(filp->f_pos);
        int off = fpos_off(filp->f_pos);
        int err;
        u32 ftype;
        struct ceph_mds_reply_info_parsed *rinfo;
-       const int max_entries = client->mount_args->max_readdir;
-       const int max_bytes = client->mount_args->max_readdir_bytes;
+       const int max_entries = fsc->mount_options->max_readdir;
+       const int max_bytes = fsc->mount_options->max_readdir_bytes;
 
        dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off);
        if (fi->at_end)
@@ -267,17 +259,17 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir)
        /* can we use the dcache? */
        spin_lock(&inode->i_lock);
        if ((filp->f_pos == 2 || fi->dentry) &&
-           !ceph_test_opt(client, NOASYNCREADDIR) &&
+           !ceph_test_mount_opt(fsc, NOASYNCREADDIR) &&
            ceph_snap(inode) != CEPH_SNAPDIR &&
            (ci->i_ceph_flags & CEPH_I_COMPLETE) &&
            __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
+               spin_unlock(&inode->i_lock);
                err = __dcache_readdir(filp, dirent, filldir);
-               if (err != -EAGAIN) {
-                       spin_unlock(&inode->i_lock);
+               if (err != -EAGAIN)
                        return err;
-               }
+       } else {
+               spin_unlock(&inode->i_lock);
        }
-       spin_unlock(&inode->i_lock);
        if (fi->dentry) {
                err = note_last_dentry(fi, fi->dentry->d_name.name,
                                       fi->dentry->d_name.len);
@@ -487,14 +479,13 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int origin)
 struct dentry *ceph_finish_lookup(struct ceph_mds_request *req,
                                  struct dentry *dentry, int err)
 {
-       struct ceph_client *client = ceph_sb_to_client(dentry->d_sb);
+       struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
        struct inode *parent = dentry->d_parent->d_inode;
 
        /* .snap dir? */
        if (err == -ENOENT &&
-           ceph_vino(parent).ino != CEPH_INO_ROOT && /* no .snap in root dir */
            strcmp(dentry->d_name.name,
-                  client->mount_args->snapdir_name) == 0) {
+                  fsc->mount_options->snapdir_name) == 0) {
                struct inode *inode = ceph_get_snapdir(parent);
                dout("ENOENT on snapdir %p '%.*s', linking to snapdir %p\n",
                     dentry, dentry->d_name.len, dentry->d_name.name, inode);
@@ -539,8 +530,8 @@ static int is_root_ceph_dentry(struct inode *inode, struct dentry *dentry)
 static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
                                  struct nameidata *nd)
 {
-       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        int op;
        int err;
@@ -572,7 +563,7 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
                spin_lock(&dir->i_lock);
                dout(" dir %p flags are %d\n", dir, ci->i_ceph_flags);
                if (strncmp(dentry->d_name.name,
-                           client->mount_args->snapdir_name,
+                           fsc->mount_options->snapdir_name,
                            dentry->d_name.len) &&
                    !is_root_ceph_dentry(dir, dentry) &&
                    (ci->i_ceph_flags & CEPH_I_COMPLETE) &&
@@ -629,8 +620,8 @@ int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry)
 static int ceph_mknod(struct inode *dir, struct dentry *dentry,
                      int mode, dev_t rdev)
 {
-       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        int err;
 
@@ -685,8 +676,8 @@ static int ceph_create(struct inode *dir, struct dentry *dentry, int mode,
 static int ceph_symlink(struct inode *dir, struct dentry *dentry,
                            const char *dest)
 {
-       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        int err;
 
@@ -716,8 +707,8 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry,
 
 static int ceph_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
-       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        int err = -EROFS;
        int op;
@@ -758,8 +749,8 @@ out:
 static int ceph_link(struct dentry *old_dentry, struct inode *dir,
                     struct dentry *dentry)
 {
-       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        int err;
 
@@ -813,8 +804,8 @@ static int drop_caps_for_unlink(struct inode *inode)
  */
 static int ceph_unlink(struct inode *dir, struct dentry *dentry)
 {
-       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct inode *inode = dentry->d_inode;
        struct ceph_mds_request *req;
        int err = -EROFS;
@@ -854,8 +845,8 @@ out:
 static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
                       struct inode *new_dir, struct dentry *new_dentry)
 {
-       struct ceph_client *client = ceph_sb_to_client(old_dir->i_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(old_dir->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        int err;
 
@@ -1076,7 +1067,7 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size,
        struct ceph_inode_info *ci = ceph_inode(inode);
        int left;
 
-       if (!ceph_test_opt(ceph_sb_to_client(inode->i_sb), DIRSTAT))
+       if (!ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), DIRSTAT))
                return -EISDIR;
 
        if (!cf->dir_info) {
@@ -1177,7 +1168,7 @@ void ceph_dentry_lru_add(struct dentry *dn)
        dout("dentry_lru_add %p %p '%.*s'\n", di, dn,
             dn->d_name.len, dn->d_name.name);
        if (di) {
-               mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
+               mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
                spin_lock(&mdsc->dentry_lru_lock);
                list_add_tail(&di->lru, &mdsc->dentry_lru);
                mdsc->num_dentry++;
@@ -1193,7 +1184,7 @@ void ceph_dentry_lru_touch(struct dentry *dn)
        dout("dentry_lru_touch %p %p '%.*s' (offset %lld)\n", di, dn,
             dn->d_name.len, dn->d_name.name, di->offset);
        if (di) {
-               mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
+               mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
                spin_lock(&mdsc->dentry_lru_lock);
                list_move_tail(&di->lru, &mdsc->dentry_lru);
                spin_unlock(&mdsc->dentry_lru_lock);
@@ -1208,7 +1199,7 @@ void ceph_dentry_lru_del(struct dentry *dn)
        dout("dentry_lru_del %p %p '%.*s'\n", di, dn,
             dn->d_name.len, dn->d_name.name);
        if (di) {
-               mdsc = &ceph_sb_to_client(dn->d_sb)->mdsc;
+               mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
                spin_lock(&mdsc->dentry_lru_lock);
                list_del_init(&di->lru);
                mdsc->num_dentry--;
index e38423e82f2ebe3f311a3f173964181c5ebe1860..2297d9426992b0132b991e0d4e129982c4ab4a01 100644 (file)
@@ -1,10 +1,11 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/exportfs.h>
 #include <linux/slab.h>
 #include <asm/unaligned.h>
 
 #include "super.h"
+#include "mds_client.h"
 
 /*
  * NFS export support
@@ -120,7 +121,7 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,
 static struct dentry *__cfh_to_dentry(struct super_block *sb,
                                      struct ceph_nfs_confh *cfh)
 {
-       struct ceph_mds_client *mdsc = &ceph_sb_to_client(sb)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
        struct inode *inode;
        struct dentry *dentry;
        struct ceph_vino vino;
index 66e4da6dba229716ff3349fe87f5dfe62fe62db1..e77c28cf369059112dd06ee3b7c78c5146f0ffdc 100644 (file)
@@ -1,5 +1,6 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/file.h>
@@ -38,8 +39,8 @@
 static struct ceph_mds_request *
 prepare_open_request(struct super_block *sb, int flags, int create_mode)
 {
-       struct ceph_client *client = ceph_sb_to_client(sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        int want_auth = USE_ANY_MDS;
        int op = (flags & O_CREAT) ? CEPH_MDS_OP_CREATE : CEPH_MDS_OP_OPEN;
@@ -117,8 +118,8 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
 int ceph_open(struct inode *inode, struct file *file)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_client *client = ceph_sb_to_client(inode->i_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        struct ceph_file_info *cf = file->private_data;
        struct inode *parent_inode = file->f_dentry->d_parent->d_inode;
@@ -216,8 +217,8 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
                                struct nameidata *nd, int mode,
                                int locked_dir)
 {
-       struct ceph_client *client = ceph_sb_to_client(dir->i_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct file *file = nd->intent.open.file;
        struct inode *parent_inode = get_dentry_parent_inode(file->f_dentry);
        struct ceph_mds_request *req;
@@ -269,163 +270,6 @@ int ceph_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-/*
- * build a vector of user pages
- */
-static struct page **get_direct_page_vector(const char __user *data,
-                                           int num_pages,
-                                           loff_t off, size_t len)
-{
-       struct page **pages;
-       int rc;
-
-       pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);
-       if (!pages)
-               return ERR_PTR(-ENOMEM);
-
-       down_read(&current->mm->mmap_sem);
-       rc = get_user_pages(current, current->mm, (unsigned long)data,
-                           num_pages, 0, 0, pages, NULL);
-       up_read(&current->mm->mmap_sem);
-       if (rc < 0)
-               goto fail;
-       return pages;
-
-fail:
-       kfree(pages);
-       return ERR_PTR(rc);
-}
-
-static void put_page_vector(struct page **pages, int num_pages)
-{
-       int i;
-
-       for (i = 0; i < num_pages; i++)
-               put_page(pages[i]);
-       kfree(pages);
-}
-
-void ceph_release_page_vector(struct page **pages, int num_pages)
-{
-       int i;
-
-       for (i = 0; i < num_pages; i++)
-               __free_pages(pages[i], 0);
-       kfree(pages);
-}
-
-/*
- * allocate a vector new pages
- */
-static struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags)
-{
-       struct page **pages;
-       int i;
-
-       pages = kmalloc(sizeof(*pages) * num_pages, flags);
-       if (!pages)
-               return ERR_PTR(-ENOMEM);
-       for (i = 0; i < num_pages; i++) {
-               pages[i] = __page_cache_alloc(flags);
-               if (pages[i] == NULL) {
-                       ceph_release_page_vector(pages, i);
-                       return ERR_PTR(-ENOMEM);
-               }
-       }
-       return pages;
-}
-
-/*
- * copy user data into a page vector
- */
-static int copy_user_to_page_vector(struct page **pages,
-                                   const char __user *data,
-                                   loff_t off, size_t len)
-{
-       int i = 0;
-       int po = off & ~PAGE_CACHE_MASK;
-       int left = len;
-       int l, bad;
-
-       while (left > 0) {
-               l = min_t(int, PAGE_CACHE_SIZE-po, left);
-               bad = copy_from_user(page_address(pages[i]) + po, data, l);
-               if (bad == l)
-                       return -EFAULT;
-               data += l - bad;
-               left -= l - bad;
-               po += l - bad;
-               if (po == PAGE_CACHE_SIZE) {
-                       po = 0;
-                       i++;
-               }
-       }
-       return len;
-}
-
-/*
- * copy user data from a page vector into a user pointer
- */
-static int copy_page_vector_to_user(struct page **pages, char __user *data,
-                                   loff_t off, size_t len)
-{
-       int i = 0;
-       int po = off & ~PAGE_CACHE_MASK;
-       int left = len;
-       int l, bad;
-
-       while (left > 0) {
-               l = min_t(int, left, PAGE_CACHE_SIZE-po);
-               bad = copy_to_user(data, page_address(pages[i]) + po, l);
-               if (bad == l)
-                       return -EFAULT;
-               data += l - bad;
-               left -= l - bad;
-               if (po) {
-                       po += l - bad;
-                       if (po == PAGE_CACHE_SIZE)
-                               po = 0;
-               }
-               i++;
-       }
-       return len;
-}
-
-/*
- * Zero an extent within a page vector.  Offset is relative to the
- * start of the first page.
- */
-static void zero_page_vector_range(int off, int len, struct page **pages)
-{
-       int i = off >> PAGE_CACHE_SHIFT;
-
-       off &= ~PAGE_CACHE_MASK;
-
-       dout("zero_page_vector_page %u~%u\n", off, len);
-
-       /* leading partial page? */
-       if (off) {
-               int end = min((int)PAGE_CACHE_SIZE, off + len);
-               dout("zeroing %d %p head from %d\n", i, pages[i],
-                    (int)off);
-               zero_user_segment(pages[i], off, end);
-               len -= (end - off);
-               i++;
-       }
-       while (len >= PAGE_CACHE_SIZE) {
-               dout("zeroing %d %p len=%d\n", i, pages[i], len);
-               zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE);
-               len -= PAGE_CACHE_SIZE;
-               i++;
-       }
-       /* trailing partial page? */
-       if (len) {
-               dout("zeroing %d %p tail to %d\n", i, pages[i], (int)len);
-               zero_user_segment(pages[i], 0, len);
-       }
-}
-
-
 /*
  * Read a range of bytes striped over one or more objects.  Iterate over
  * objects we stripe over.  (That's not atomic, but good enough for now.)
@@ -438,7 +282,7 @@ static int striped_read(struct inode *inode,
                        struct page **pages, int num_pages,
                        int *checkeof)
 {
-       struct ceph_client *client = ceph_inode_to_client(inode);
+       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
        struct ceph_inode_info *ci = ceph_inode(inode);
        u64 pos, this_len;
        int page_off = off & ~PAGE_CACHE_MASK; /* first byte's offset in page */
@@ -459,7 +303,7 @@ static int striped_read(struct inode *inode,
 
 more:
        this_len = left;
-       ret = ceph_osdc_readpages(&client->osdc, ceph_vino(inode),
+       ret = ceph_osdc_readpages(&fsc->client->osdc, ceph_vino(inode),
                                  &ci->i_layout, pos, &this_len,
                                  ci->i_truncate_seq,
                                  ci->i_truncate_size,
@@ -477,8 +321,8 @@ more:
 
                if (read < pos - off) {
                        dout(" zero gap %llu to %llu\n", off + read, pos);
-                       zero_page_vector_range(page_off + read,
-                                              pos - off - read, pages);
+                       ceph_zero_page_vector_range(page_off + read,
+                                                   pos - off - read, pages);
                }
                pos += ret;
                read = pos - off;
@@ -495,8 +339,8 @@ more:
                /* was original extent fully inside i_size? */
                if (pos + left <= inode->i_size) {
                        dout("zero tail\n");
-                       zero_page_vector_range(page_off + read, len - read,
-                                              pages);
+                       ceph_zero_page_vector_range(page_off + read, len - read,
+                                                   pages);
                        read = len;
                        goto out;
                }
@@ -531,7 +375,7 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data,
             (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
 
        if (file->f_flags & O_DIRECT) {
-               pages = get_direct_page_vector(data, num_pages, off, len);
+               pages = ceph_get_direct_page_vector(data, num_pages, off, len);
 
                /*
                 * flush any page cache pages in this range.  this
@@ -552,13 +396,13 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data,
        ret = striped_read(inode, off, len, pages, num_pages, checkeof);
 
        if (ret >= 0 && (file->f_flags & O_DIRECT) == 0)
-               ret = copy_page_vector_to_user(pages, data, off, ret);
+               ret = ceph_copy_page_vector_to_user(pages, data, off, ret);
        if (ret >= 0)
                *poff = off + ret;
 
 done:
        if (file->f_flags & O_DIRECT)
-               put_page_vector(pages, num_pages);
+               ceph_put_page_vector(pages, num_pages);
        else
                ceph_release_page_vector(pages, num_pages);
        dout("sync_read result %d\n", ret);
@@ -594,7 +438,7 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data,
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_client *client = ceph_inode_to_client(inode);
+       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
        struct ceph_osd_request *req;
        struct page **pages;
        int num_pages;
@@ -642,7 +486,7 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data,
         */
 more:
        len = left;
-       req = ceph_osdc_new_request(&client->osdc, &ci->i_layout,
+       req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
                                    ceph_vino(inode), pos, &len,
                                    CEPH_OSD_OP_WRITE, flags,
                                    ci->i_snap_realm->cached_context,
@@ -655,7 +499,7 @@ more:
        num_pages = calc_pages_for(pos, len);
 
        if (file->f_flags & O_DIRECT) {
-               pages = get_direct_page_vector(data, num_pages, pos, len);
+               pages = ceph_get_direct_page_vector(data, num_pages, pos, len);
                if (IS_ERR(pages)) {
                        ret = PTR_ERR(pages);
                        goto out;
@@ -673,7 +517,7 @@ more:
                        ret = PTR_ERR(pages);
                        goto out;
                }
-               ret = copy_user_to_page_vector(pages, data, pos, len);
+               ret = ceph_copy_user_to_page_vector(pages, data, pos, len);
                if (ret < 0) {
                        ceph_release_page_vector(pages, num_pages);
                        goto out;
@@ -689,7 +533,7 @@ more:
        req->r_num_pages = num_pages;
        req->r_inode = inode;
 
-       ret = ceph_osdc_start_request(&client->osdc, req, false);
+       ret = ceph_osdc_start_request(&fsc->client->osdc, req, false);
        if (!ret) {
                if (req->r_safe_callback) {
                        /*
@@ -701,11 +545,11 @@ more:
                        spin_unlock(&ci->i_unsafe_lock);
                        ceph_get_cap_refs(ci, CEPH_CAP_FILE_WR);
                }
-               ret = ceph_osdc_wait_request(&client->osdc, req);
+               ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
        }
 
        if (file->f_flags & O_DIRECT)
-               put_page_vector(pages, num_pages);
+               ceph_put_page_vector(pages, num_pages);
        else if (file->f_flags & O_SYNC)
                ceph_release_page_vector(pages, num_pages);
 
@@ -814,7 +658,8 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
        struct ceph_file_info *fi = file->private_data;
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->osdc;
+       struct ceph_osd_client *osdc =
+               &ceph_sb_to_client(inode->i_sb)->client->osdc;
        loff_t endoff = pos + iov->iov_len;
        int want, got = 0;
        int ret, err;
index 62377ec37edf05c14cf8567c0d22e19e02762253..1d6a45b5a04c696591879d141165627746d6a476 100644 (file)
@@ -1,4 +1,4 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/module.h>
 #include <linux/fs.h>
@@ -13,7 +13,8 @@
 #include <linux/pagevec.h>
 
 #include "super.h"
-#include "decode.h"
+#include "mds_client.h"
+#include <linux/ceph/decode.h>
 
 /*
  * Ceph inode operations
@@ -384,7 +385,7 @@ void ceph_destroy_inode(struct inode *inode)
         */
        if (ci->i_snap_realm) {
                struct ceph_mds_client *mdsc =
-                       &ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
+                       ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
                struct ceph_snap_realm *realm = ci->i_snap_realm;
 
                dout(" dropping residual ref to snap realm %p\n", realm);
@@ -685,7 +686,7 @@ static int fill_inode(struct inode *inode,
                }
 
                /* it may be better to set st_size in getattr instead? */
-               if (ceph_test_opt(ceph_sb_to_client(inode->i_sb), RBYTES))
+               if (ceph_test_mount_opt(ceph_sb_to_client(inode->i_sb), RBYTES))
                        inode->i_size = ci->i_rbytes;
                break;
        default:
@@ -901,7 +902,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
        struct inode *in = NULL;
        struct ceph_mds_reply_inode *ininfo;
        struct ceph_vino vino;
-       struct ceph_client *client = ceph_sb_to_client(sb);
+       struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
        int i = 0;
        int err = 0;
 
@@ -965,7 +966,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
         */
        if (rinfo->head->is_dentry && !req->r_aborted &&
            (rinfo->head->is_target || strncmp(req->r_dentry->d_name.name,
-                                              client->mount_args->snapdir_name,
+                                              fsc->mount_options->snapdir_name,
                                               req->r_dentry->d_name.len))) {
                /*
                 * lookup link rename   : null -> possibly existing inode
@@ -1533,7 +1534,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
        struct inode *parent_inode = dentry->d_parent->d_inode;
        const unsigned int ia_valid = attr->ia_valid;
        struct ceph_mds_request *req;
-       struct ceph_mds_client *mdsc = &ceph_sb_to_client(dentry->d_sb)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc;
        int issued;
        int release = 0, dirtied = 0;
        int mask = 0;
@@ -1728,8 +1729,8 @@ out:
  */
 int ceph_do_getattr(struct inode *inode, int mask)
 {
-       struct ceph_client *client = ceph_sb_to_client(inode->i_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req;
        int err;
 
index 76e307d2aba16868c9b1e8136496d929e0cd971f..8888c9ba68dbfec194e06f06142547ee2d35c8bc 100644 (file)
@@ -1,8 +1,10 @@
 #include <linux/in.h>
 
-#include "ioctl.h"
 #include "super.h"
-#include "ceph_debug.h"
+#include "mds_client.h"
+#include <linux/ceph/ceph_debug.h>
+
+#include "ioctl.h"
 
 
 /*
@@ -37,7 +39,7 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct inode *parent_inode = file->f_dentry->d_parent->d_inode;
-       struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_mds_request *req;
        struct ceph_ioctl_layout l;
        int err, i;
@@ -89,6 +91,68 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
        return err;
 }
 
+/*
+ * Set a layout policy on a directory inode. All items in the tree
+ * rooted at this inode will inherit this layout on creation,
+ * (It doesn't apply retroactively )
+ * unless a subdirectory has its own layout policy.
+ */
+static long ceph_ioctl_set_layout_policy (struct file *file, void __user *arg)
+{
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_mds_request *req;
+       struct ceph_ioctl_layout l;
+       int err, i;
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
+
+       /* copy and validate */
+       if (copy_from_user(&l, arg, sizeof(l)))
+               return -EFAULT;
+
+       if ((l.object_size & ~PAGE_MASK) ||
+           (l.stripe_unit & ~PAGE_MASK) ||
+           !l.stripe_unit ||
+           (l.object_size &&
+               (unsigned)l.object_size % (unsigned)l.stripe_unit))
+               return -EINVAL;
+
+       /* make sure it's a valid data pool */
+       if (l.data_pool > 0) {
+               mutex_lock(&mdsc->mutex);
+               err = -EINVAL;
+               for (i = 0; i < mdsc->mdsmap->m_num_data_pg_pools; i++)
+                       if (mdsc->mdsmap->m_data_pg_pools[i] == l.data_pool) {
+                               err = 0;
+                               break;
+                       }
+               mutex_unlock(&mdsc->mutex);
+               if (err)
+                       return err;
+       }
+
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETDIRLAYOUT,
+                                      USE_AUTH_MDS);
+
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+       req->r_inode = igrab(inode);
+
+       req->r_args.setlayout.layout.fl_stripe_unit =
+                       cpu_to_le32(l.stripe_unit);
+       req->r_args.setlayout.layout.fl_stripe_count =
+                       cpu_to_le32(l.stripe_count);
+       req->r_args.setlayout.layout.fl_object_size =
+                       cpu_to_le32(l.object_size);
+       req->r_args.setlayout.layout.fl_pg_pool =
+                       cpu_to_le32(l.data_pool);
+       req->r_args.setlayout.layout.fl_pg_preferred =
+                       cpu_to_le32(l.preferred_osd);
+
+       err = ceph_mdsc_do_request(mdsc, inode, req);
+       ceph_mdsc_put_request(req);
+       return err;
+}
+
 /*
  * Return object name, size/offset information, and location (OSD
  * number, network address) for a given file offset.
@@ -98,7 +162,8 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
        struct ceph_ioctl_dataloc dl;
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->osdc;
+       struct ceph_osd_client *osdc =
+               &ceph_sb_to_client(inode->i_sb)->client->osdc;
        u64 len = 1, olen;
        u64 tmp;
        struct ceph_object_layout ol;
@@ -174,11 +239,15 @@ long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case CEPH_IOC_SET_LAYOUT:
                return ceph_ioctl_set_layout(file, (void __user *)arg);
 
+       case CEPH_IOC_SET_LAYOUT_POLICY:
+               return ceph_ioctl_set_layout_policy(file, (void __user *)arg);
+
        case CEPH_IOC_GET_DATALOC:
                return ceph_ioctl_get_dataloc(file, (void __user *)arg);
 
        case CEPH_IOC_LAZYIO:
                return ceph_ioctl_lazyio(file);
        }
+
        return -ENOTTY;
 }
index 88451a3b6857d14bc7b21f418bcd82e56e9fdc64..a6ce54e94eb5ab435670093cd6ad789e72cc627b 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/ioctl.h>
 #include <linux/types.h>
 
-#define CEPH_IOCTL_MAGIC 0x97
+#define CEPH_IOCTL_MAGIC 0x98
 
 /* just use u64 to align sanely on all archs */
 struct ceph_ioctl_layout {
@@ -17,6 +17,8 @@ struct ceph_ioctl_layout {
                                   struct ceph_ioctl_layout)
 #define CEPH_IOC_SET_LAYOUT _IOW(CEPH_IOCTL_MAGIC, 2,          \
                                   struct ceph_ioctl_layout)
+#define CEPH_IOC_SET_LAYOUT_POLICY _IOW(CEPH_IOCTL_MAGIC, 5,   \
+                                  struct ceph_ioctl_layout)
 
 /*
  * Extract identity, address of the OSD and object storing a given
index ff4e753aae929d37d414567d22fd6afef7316c7e..40abde93c345d054279fd51cbca998525c4931c7 100644 (file)
@@ -1,11 +1,11 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/file.h>
 #include <linux/namei.h>
 
 #include "super.h"
 #include "mds_client.h"
-#include "pagelist.h"
+#include <linux/ceph/pagelist.h>
 
 /**
  * Implement fcntl and flock locking functions.
@@ -16,7 +16,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
 {
        struct inode *inode = file->f_dentry->d_inode;
        struct ceph_mds_client *mdsc =
-               &ceph_sb_to_client(inode->i_sb)->mdsc;
+               ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_mds_request *req;
        int err;
 
@@ -181,8 +181,9 @@ void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count)
  * Encode the flock and fcntl locks for the given inode into the pagelist.
  * Format is: #fcntl locks, sequential fcntl locks, #flock locks,
  * sequential flock locks.
- * Must be called with BLK already held, and the lock numbers should have
- * been gathered under the same lock holding window.
+ * Must be called with lock_flocks() already held.
+ * If we encounter more of a specific lock type than expected,
+ * we return the value 1.
  */
 int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist,
                      int num_fcntl_locks, int num_flock_locks)
@@ -190,6 +191,8 @@ int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist,
        struct file_lock *lock;
        struct ceph_filelock cephlock;
        int err = 0;
+       int seen_fcntl = 0;
+       int seen_flock = 0;
 
        dout("encoding %d flock and %d fcntl locks", num_flock_locks,
             num_fcntl_locks);
@@ -198,6 +201,11 @@ int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist,
                goto fail;
        for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
                if (lock->fl_flags & FL_POSIX) {
+                       ++seen_fcntl;
+                       if (seen_fcntl > num_fcntl_locks) {
+                               err = -ENOSPC;
+                               goto fail;
+                       }
                        err = lock_to_ceph_filelock(lock, &cephlock);
                        if (err)
                                goto fail;
@@ -213,6 +221,11 @@ int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist,
                goto fail;
        for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) {
                if (lock->fl_flags & FL_FLOCK) {
+                       ++seen_flock;
+                       if (seen_flock > num_flock_locks) {
+                               err = -ENOSPC;
+                               goto fail;
+                       }
                        err = lock_to_ceph_filelock(lock, &cephlock);
                        if (err)
                                goto fail;
index fad95f8f2608bc4e86c0876bedd81cb5be46a4ef..3142b15940c25656a43ec3a5d72af3e1ee1cece9 100644 (file)
@@ -1,17 +1,21 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
+#include <linux/fs.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/smp_lock.h>
 
-#include "mds_client.h"
-#include "mon_client.h"
 #include "super.h"
-#include "messenger.h"
-#include "decode.h"
-#include "auth.h"
-#include "pagelist.h"
+#include "mds_client.h"
+
+#include <linux/ceph/messenger.h>
+#include <linux/ceph/decode.h>
+#include <linux/ceph/pagelist.h>
+#include <linux/ceph/auth.h>
+#include <linux/ceph/debugfs.h>
 
 /*
  * A cluster of MDS (metadata server) daemons is responsible for
@@ -286,8 +290,9 @@ void ceph_put_mds_session(struct ceph_mds_session *s)
             atomic_read(&s->s_ref), atomic_read(&s->s_ref)-1);
        if (atomic_dec_and_test(&s->s_ref)) {
                if (s->s_authorizer)
-                       s->s_mdsc->client->monc.auth->ops->destroy_authorizer(
-                               s->s_mdsc->client->monc.auth, s->s_authorizer);
+                    s->s_mdsc->fsc->client->monc.auth->ops->destroy_authorizer(
+                            s->s_mdsc->fsc->client->monc.auth,
+                            s->s_authorizer);
                kfree(s);
        }
 }
@@ -344,7 +349,7 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
        s->s_seq = 0;
        mutex_init(&s->s_mutex);
 
-       ceph_con_init(mdsc->client->msgr, &s->s_con);
+       ceph_con_init(mdsc->fsc->client->msgr, &s->s_con);
        s->s_con.private = s;
        s->s_con.ops = &mds_con_ops;
        s->s_con.peer_name.type = CEPH_ENTITY_TYPE_MDS;
@@ -599,7 +604,7 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
        } else if (req->r_dentry) {
                struct inode *dir = req->r_dentry->d_parent->d_inode;
 
-               if (dir->i_sb != mdsc->client->sb) {
+               if (dir->i_sb != mdsc->fsc->sb) {
                        /* not this fs! */
                        inode = req->r_dentry->d_inode;
                } else if (ceph_snap(dir) != CEPH_NOSNAP) {
@@ -884,7 +889,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
        __ceph_remove_cap(cap);
        if (!__ceph_is_any_real_caps(ci)) {
                struct ceph_mds_client *mdsc =
-                       &ceph_sb_to_client(inode->i_sb)->mdsc;
+                       ceph_sb_to_client(inode->i_sb)->mdsc;
 
                spin_lock(&mdsc->cap_dirty_lock);
                if (!list_empty(&ci->i_dirty_item)) {
@@ -1146,7 +1151,7 @@ int ceph_add_cap_releases(struct ceph_mds_client *mdsc,
        struct ceph_msg *msg, *partial = NULL;
        struct ceph_mds_cap_release *head;
        int err = -ENOMEM;
-       int extra = mdsc->client->mount_args->cap_release_safety;
+       int extra = mdsc->fsc->mount_options->cap_release_safety;
        int num;
 
        dout("add_cap_releases %p mds%d extra %d\n", session, session->s_mds,
@@ -2085,7 +2090,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
 
        /* insert trace into our cache */
        mutex_lock(&req->r_fill_mutex);
-       err = ceph_fill_trace(mdsc->client->sb, req, req->r_session);
+       err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session);
        if (err == 0) {
                if (result == 0 && rinfo->dir_nr)
                        ceph_readdir_prepopulate(req, req->r_session);
@@ -2361,19 +2366,35 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap,
 
        if (recon_state->flock) {
                int num_fcntl_locks, num_flock_locks;
-
-               lock_kernel();
-               ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks);
-               rec.v2.flock_len = (2*sizeof(u32) +
-                                   (num_fcntl_locks+num_flock_locks) *
-                                   sizeof(struct ceph_filelock));
-
-               err = ceph_pagelist_append(pagelist, &rec, reclen);
-               if (!err)
-                       err = ceph_encode_locks(inode, pagelist,
-                                               num_fcntl_locks,
-                                               num_flock_locks);
-               unlock_kernel();
+               struct ceph_pagelist_cursor trunc_point;
+
+               ceph_pagelist_set_cursor(pagelist, &trunc_point);
+               do {
+                       lock_flocks();
+                       ceph_count_locks(inode, &num_fcntl_locks,
+                                        &num_flock_locks);
+                       rec.v2.flock_len = (2*sizeof(u32) +
+                                           (num_fcntl_locks+num_flock_locks) *
+                                           sizeof(struct ceph_filelock));
+                       unlock_flocks();
+
+                       /* pre-alloc pagelist */
+                       ceph_pagelist_truncate(pagelist, &trunc_point);
+                       err = ceph_pagelist_append(pagelist, &rec, reclen);
+                       if (!err)
+                               err = ceph_pagelist_reserve(pagelist,
+                                                           rec.v2.flock_len);
+
+                       /* encode locks */
+                       if (!err) {
+                               lock_flocks();
+                               err = ceph_encode_locks(inode,
+                                                       pagelist,
+                                                       num_fcntl_locks,
+                                                       num_flock_locks);
+                               unlock_flocks();
+                       }
+               } while (err == -ENOSPC);
        } else {
                err = ceph_pagelist_append(pagelist, &rec, reclen);
        }
@@ -2613,7 +2634,7 @@ static void handle_lease(struct ceph_mds_client *mdsc,
                         struct ceph_mds_session *session,
                         struct ceph_msg *msg)
 {
-       struct super_block *sb = mdsc->client->sb;
+       struct super_block *sb = mdsc->fsc->sb;
        struct inode *inode;
        struct ceph_inode_info *ci;
        struct dentry *parent, *dentry;
@@ -2891,10 +2912,16 @@ static void delayed_work(struct work_struct *work)
        schedule_delayed(mdsc);
 }
 
+int ceph_mdsc_init(struct ceph_fs_client *fsc)
 
-int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
 {
-       mdsc->client = client;
+       struct ceph_mds_client *mdsc;
+
+       mdsc = kzalloc(sizeof(struct ceph_mds_client), GFP_NOFS);
+       if (!mdsc)
+               return -ENOMEM;
+       mdsc->fsc = fsc;
+       fsc->mdsc = mdsc;
        mutex_init(&mdsc->mutex);
        mdsc->mdsmap = kzalloc(sizeof(*mdsc->mdsmap), GFP_NOFS);
        if (mdsc->mdsmap == NULL)
@@ -2927,7 +2954,7 @@ int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
        INIT_LIST_HEAD(&mdsc->dentry_lru);
 
        ceph_caps_init(mdsc);
-       ceph_adjust_min_caps(mdsc, client->min_caps);
+       ceph_adjust_min_caps(mdsc, fsc->min_caps);
 
        return 0;
 }
@@ -2939,7 +2966,7 @@ int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client)
 static void wait_requests(struct ceph_mds_client *mdsc)
 {
        struct ceph_mds_request *req;
-       struct ceph_client *client = mdsc->client;
+       struct ceph_fs_client *fsc = mdsc->fsc;
 
        mutex_lock(&mdsc->mutex);
        if (__get_oldest_req(mdsc)) {
@@ -2947,7 +2974,7 @@ static void wait_requests(struct ceph_mds_client *mdsc)
 
                dout("wait_requests waiting for requests\n");
                wait_for_completion_timeout(&mdsc->safe_umount_waiters,
-                                   client->mount_args->mount_timeout * HZ);
+                                   fsc->client->options->mount_timeout * HZ);
 
                /* tear down remaining requests */
                mutex_lock(&mdsc->mutex);
@@ -3030,7 +3057,7 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc)
 {
        u64 want_tid, want_flush;
 
-       if (mdsc->client->mount_state == CEPH_MOUNT_SHUTDOWN)
+       if (mdsc->fsc->mount_state == CEPH_MOUNT_SHUTDOWN)
                return;
 
        dout("sync\n");
@@ -3053,7 +3080,7 @@ bool done_closing_sessions(struct ceph_mds_client *mdsc)
 {
        int i, n = 0;
 
-       if (mdsc->client->mount_state == CEPH_MOUNT_SHUTDOWN)
+       if (mdsc->fsc->mount_state == CEPH_MOUNT_SHUTDOWN)
                return true;
 
        mutex_lock(&mdsc->mutex);
@@ -3071,8 +3098,8 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
 {
        struct ceph_mds_session *session;
        int i;
-       struct ceph_client *client = mdsc->client;
-       unsigned long timeout = client->mount_args->mount_timeout * HZ;
+       struct ceph_fs_client *fsc = mdsc->fsc;
+       unsigned long timeout = fsc->client->options->mount_timeout * HZ;
 
        dout("close_sessions\n");
 
@@ -3119,7 +3146,7 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc)
        dout("stopped\n");
 }
 
-void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
+static void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
 {
        dout("stop\n");
        cancel_delayed_work_sync(&mdsc->delayed_work); /* cancel timer */
@@ -3129,6 +3156,15 @@ void ceph_mdsc_stop(struct ceph_mds_client *mdsc)
        ceph_caps_finalize(mdsc);
 }
 
+void ceph_mdsc_destroy(struct ceph_fs_client *fsc)
+{
+       struct ceph_mds_client *mdsc = fsc->mdsc;
+
+       ceph_mdsc_stop(mdsc);
+       fsc->mdsc = NULL;
+       kfree(mdsc);
+}
+
 
 /*
  * handle mds map update.
@@ -3145,14 +3181,14 @@ void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
 
        ceph_decode_need(&p, end, sizeof(fsid)+2*sizeof(u32), bad);
        ceph_decode_copy(&p, &fsid, sizeof(fsid));
-       if (ceph_check_fsid(mdsc->client, &fsid) < 0)
+       if (ceph_check_fsid(mdsc->fsc->client, &fsid) < 0)
                return;
        epoch = ceph_decode_32(&p);
        maplen = ceph_decode_32(&p);
        dout("handle_map epoch %u len %d\n", epoch, (int)maplen);
 
        /* do we need it? */
-       ceph_monc_got_mdsmap(&mdsc->client->monc, epoch);
+       ceph_monc_got_mdsmap(&mdsc->fsc->client->monc, epoch);
        mutex_lock(&mdsc->mutex);
        if (mdsc->mdsmap && epoch <= mdsc->mdsmap->m_epoch) {
                dout("handle_map epoch %u <= our %u\n",
@@ -3176,7 +3212,7 @@ void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, struct ceph_msg *msg)
        } else {
                mdsc->mdsmap = newmap;  /* first mds map */
        }
-       mdsc->client->sb->s_maxbytes = mdsc->mdsmap->m_max_file_size;
+       mdsc->fsc->sb->s_maxbytes = mdsc->mdsmap->m_max_file_size;
 
        __wake_requests(mdsc, &mdsc->waiting_for_map);
 
@@ -3277,7 +3313,7 @@ static int get_authorizer(struct ceph_connection *con,
 {
        struct ceph_mds_session *s = con->private;
        struct ceph_mds_client *mdsc = s->s_mdsc;
-       struct ceph_auth_client *ac = mdsc->client->monc.auth;
+       struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth;
        int ret = 0;
 
        if (force_new && s->s_authorizer) {
@@ -3311,7 +3347,7 @@ static int verify_authorizer_reply(struct ceph_connection *con, int len)
 {
        struct ceph_mds_session *s = con->private;
        struct ceph_mds_client *mdsc = s->s_mdsc;
-       struct ceph_auth_client *ac = mdsc->client->monc.auth;
+       struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth;
 
        return ac->ops->verify_authorizer_reply(ac, s->s_authorizer, len);
 }
@@ -3320,12 +3356,12 @@ static int invalidate_authorizer(struct ceph_connection *con)
 {
        struct ceph_mds_session *s = con->private;
        struct ceph_mds_client *mdsc = s->s_mdsc;
-       struct ceph_auth_client *ac = mdsc->client->monc.auth;
+       struct ceph_auth_client *ac = mdsc->fsc->client->monc.auth;
 
        if (ac->ops->invalidate_authorizer)
                ac->ops->invalidate_authorizer(ac, CEPH_ENTITY_TYPE_MDS);
 
-       return ceph_monc_validate_auth(&mdsc->client->monc);
+       return ceph_monc_validate_auth(&mdsc->fsc->client->monc);
 }
 
 static const struct ceph_connection_operations mds_con_ops = {
@@ -3338,7 +3374,4 @@ static const struct ceph_connection_operations mds_con_ops = {
        .peer_reset = peer_reset,
 };
 
-
-
-
 /* eof */
index c98267ce6d2ad97e1d9c86bc0660e2d82d39366c..d66d63c7235526ef63d16ff0ea1e9ba3899df586 100644 (file)
@@ -8,9 +8,9 @@
 #include <linux/rbtree.h>
 #include <linux/spinlock.h>
 
-#include "types.h"
-#include "messenger.h"
-#include "mdsmap.h"
+#include <linux/ceph/types.h>
+#include <linux/ceph/messenger.h>
+#include <linux/ceph/mdsmap.h>
 
 /*
  * Some lock dependencies:
@@ -26,7 +26,7 @@
  *
  */
 
-struct ceph_client;
+struct ceph_fs_client;
 struct ceph_cap;
 
 /*
@@ -230,7 +230,7 @@ struct ceph_mds_request {
  * mds client state
  */
 struct ceph_mds_client {
-       struct ceph_client      *client;
+       struct ceph_fs_client  *fsc;
        struct mutex            mutex;         /* all nested structures */
 
        struct ceph_mdsmap      *mdsmap;
@@ -289,11 +289,6 @@ struct ceph_mds_client {
        int             caps_avail_count;    /* unused, unreserved */
        int             caps_min_count;      /* keep at least this many
                                                (unreserved) */
-
-#ifdef CONFIG_DEBUG_FS
-       struct dentry     *debugfs_file;
-#endif
-
        spinlock_t        dentry_lru_lock;
        struct list_head  dentry_lru;
        int               num_dentry;
@@ -316,10 +311,9 @@ extern void ceph_put_mds_session(struct ceph_mds_session *s);
 extern int ceph_send_msg_mds(struct ceph_mds_client *mdsc,
                             struct ceph_msg *msg, int mds);
 
-extern int ceph_mdsc_init(struct ceph_mds_client *mdsc,
-                          struct ceph_client *client);
+extern int ceph_mdsc_init(struct ceph_fs_client *fsc);
 extern void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc);
-extern void ceph_mdsc_stop(struct ceph_mds_client *mdsc);
+extern void ceph_mdsc_destroy(struct ceph_fs_client *fsc);
 
 extern void ceph_mdsc_sync(struct ceph_mds_client *mdsc);
 
index 040be6d1150be5ace2be71e955ac3b3525b8fd76..73b7d44e8a354264e3f08f66e8cb788851328029 100644 (file)
@@ -1,4 +1,4 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/bug.h>
 #include <linux/err.h>
@@ -6,9 +6,9 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 
-#include "mdsmap.h"
-#include "messenger.h"
-#include "decode.h"
+#include <linux/ceph/mdsmap.h>
+#include <linux/ceph/messenger.h>
+#include <linux/ceph/decode.h>
 
 #include "super.h"
 
@@ -117,7 +117,8 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end)
                }
 
                dout("mdsmap_decode %d/%d %lld mds%d.%d %s %s\n",
-                    i+1, n, global_id, mds, inc, pr_addr(&addr.in_addr),
+                    i+1, n, global_id, mds, inc,
+                    ceph_pr_addr(&addr.in_addr),
                     ceph_mds_state_name(state));
                if (mds >= 0 && mds < m->m_max_mds && state > 0) {
                        m->m_info[mds].global_id = global_id;
diff --git a/fs/ceph/pagelist.c b/fs/ceph/pagelist.c
deleted file mode 100644 (file)
index 46a368b..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-
-#include <linux/gfp.h>
-#include <linux/pagemap.h>
-#include <linux/highmem.h>
-
-#include "pagelist.h"
-
-static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl)
-{
-       struct page *page = list_entry(pl->head.prev, struct page,
-                                      lru);
-       kunmap(page);
-}
-
-int ceph_pagelist_release(struct ceph_pagelist *pl)
-{
-       if (pl->mapped_tail)
-               ceph_pagelist_unmap_tail(pl);
-
-       while (!list_empty(&pl->head)) {
-               struct page *page = list_first_entry(&pl->head, struct page,
-                                                    lru);
-               list_del(&page->lru);
-               __free_page(page);
-       }
-       return 0;
-}
-
-static int ceph_pagelist_addpage(struct ceph_pagelist *pl)
-{
-       struct page *page = __page_cache_alloc(GFP_NOFS);
-       if (!page)
-               return -ENOMEM;
-       pl->room += PAGE_SIZE;
-       list_add_tail(&page->lru, &pl->head);
-       if (pl->mapped_tail)
-               ceph_pagelist_unmap_tail(pl);
-       pl->mapped_tail = kmap(page);
-       return 0;
-}
-
-int ceph_pagelist_append(struct ceph_pagelist *pl, void *buf, size_t len)
-{
-       while (pl->room < len) {
-               size_t bit = pl->room;
-               int ret;
-
-               memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK),
-                      buf, bit);
-               pl->length += bit;
-               pl->room -= bit;
-               buf += bit;
-               len -= bit;
-               ret = ceph_pagelist_addpage(pl);
-               if (ret)
-                       return ret;
-       }
-
-       memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK), buf, len);
-       pl->length += len;
-       pl->room -= len;
-       return 0;
-}
index 190b6c4a6f2b91aace658f8de7664f75cc0bdcc4..39c243acd062c810d33e60da27af51cbcfe058e8 100644 (file)
@@ -1,10 +1,12 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/sort.h>
 #include <linux/slab.h>
 
 #include "super.h"
-#include "decode.h"
+#include "mds_client.h"
+
+#include <linux/ceph/decode.h>
 
 /*
  * Snapshots in ceph are driven in large part by cooperation from the
@@ -526,7 +528,7 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
                            struct ceph_cap_snap *capsnap)
 {
        struct inode *inode = &ci->vfs_inode;
-       struct ceph_mds_client *mdsc = &ceph_sb_to_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
 
        BUG_ON(capsnap->writing);
        capsnap->size = inode->i_size;
@@ -747,7 +749,7 @@ void ceph_handle_snap(struct ceph_mds_client *mdsc,
                      struct ceph_mds_session *session,
                      struct ceph_msg *msg)
 {
-       struct super_block *sb = mdsc->client->sb;
+       struct super_block *sb = mdsc->fsc->sb;
        int mds = session->s_mds;
        u64 split;
        int op;
similarity index 59%
rename from fs/ceph/ceph_strings.c
rename to fs/ceph/strings.c
index c6179d3a26a216cb7b8f6ee0119884162887c778..cd5097d7c804e5897eeed60716c962d1bbd59b5c 100644 (file)
@@ -1,71 +1,9 @@
 /*
- * Ceph string constants
+ * Ceph fs string constants
  */
-#include "types.h"
+#include <linux/module.h>
+#include <linux/ceph/types.h>
 
-const char *ceph_entity_type_name(int type)
-{
-       switch (type) {
-       case CEPH_ENTITY_TYPE_MDS: return "mds";
-       case CEPH_ENTITY_TYPE_OSD: return "osd";
-       case CEPH_ENTITY_TYPE_MON: return "mon";
-       case CEPH_ENTITY_TYPE_CLIENT: return "client";
-       case CEPH_ENTITY_TYPE_AUTH: return "auth";
-       default: return "unknown";
-       }
-}
-
-const char *ceph_osd_op_name(int op)
-{
-       switch (op) {
-       case CEPH_OSD_OP_READ: return "read";
-       case CEPH_OSD_OP_STAT: return "stat";
-
-       case CEPH_OSD_OP_MASKTRUNC: return "masktrunc";
-
-       case CEPH_OSD_OP_WRITE: return "write";
-       case CEPH_OSD_OP_DELETE: return "delete";
-       case CEPH_OSD_OP_TRUNCATE: return "truncate";
-       case CEPH_OSD_OP_ZERO: return "zero";
-       case CEPH_OSD_OP_WRITEFULL: return "writefull";
-       case CEPH_OSD_OP_ROLLBACK: return "rollback";
-
-       case CEPH_OSD_OP_APPEND: return "append";
-       case CEPH_OSD_OP_STARTSYNC: return "startsync";
-       case CEPH_OSD_OP_SETTRUNC: return "settrunc";
-       case CEPH_OSD_OP_TRIMTRUNC: return "trimtrunc";
-
-       case CEPH_OSD_OP_TMAPUP: return "tmapup";
-       case CEPH_OSD_OP_TMAPGET: return "tmapget";
-       case CEPH_OSD_OP_TMAPPUT: return "tmapput";
-
-       case CEPH_OSD_OP_GETXATTR: return "getxattr";
-       case CEPH_OSD_OP_GETXATTRS: return "getxattrs";
-       case CEPH_OSD_OP_SETXATTR: return "setxattr";
-       case CEPH_OSD_OP_SETXATTRS: return "setxattrs";
-       case CEPH_OSD_OP_RESETXATTRS: return "resetxattrs";
-       case CEPH_OSD_OP_RMXATTR: return "rmxattr";
-       case CEPH_OSD_OP_CMPXATTR: return "cmpxattr";
-
-       case CEPH_OSD_OP_PULL: return "pull";
-       case CEPH_OSD_OP_PUSH: return "push";
-       case CEPH_OSD_OP_BALANCEREADS: return "balance-reads";
-       case CEPH_OSD_OP_UNBALANCEREADS: return "unbalance-reads";
-       case CEPH_OSD_OP_SCRUB: return "scrub";
-
-       case CEPH_OSD_OP_WRLOCK: return "wrlock";
-       case CEPH_OSD_OP_WRUNLOCK: return "wrunlock";
-       case CEPH_OSD_OP_RDLOCK: return "rdlock";
-       case CEPH_OSD_OP_RDUNLOCK: return "rdunlock";
-       case CEPH_OSD_OP_UPLOCK: return "uplock";
-       case CEPH_OSD_OP_DNLOCK: return "dnlock";
-
-       case CEPH_OSD_OP_CALL: return "call";
-
-       case CEPH_OSD_OP_PGLS: return "pgls";
-       }
-       return "???";
-}
 
 const char *ceph_mds_state_name(int s)
 {
@@ -177,17 +115,3 @@ const char *ceph_snap_op_name(int o)
        }
        return "???";
 }
-
-const char *ceph_pool_op_name(int op)
-{
-       switch (op) {
-       case POOL_OP_CREATE: return "create";
-       case POOL_OP_DELETE: return "delete";
-       case POOL_OP_AUID_CHANGE: return "auid change";
-       case POOL_OP_CREATE_SNAP: return "create snap";
-       case POOL_OP_DELETE_SNAP: return "delete snap";
-       case POOL_OP_CREATE_UNMANAGED_SNAP: return "create unmanaged snap";
-       case POOL_OP_DELETE_UNMANAGED_SNAP: return "delete unmanaged snap";
-       }
-       return "???";
-}
index 9922628532b2c649dee6761710405adc552ca248..d6e0e042189184183b4ccf82da8787622e7f7d11 100644 (file)
@@ -1,5 +1,5 @@
 
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/backing-dev.h>
 #include <linux/ctype.h>
 #include <linux/statfs.h>
 #include <linux/string.h>
 
-#include "decode.h"
 #include "super.h"
-#include "mon_client.h"
-#include "auth.h"
+#include "mds_client.h"
+
+#include <linux/ceph/decode.h>
+#include <linux/ceph/mon_client.h>
+#include <linux/ceph/auth.h>
+#include <linux/ceph/debugfs.h>
 
 /*
  * Ceph superblock operations
  * Handle the basics of mounting, unmounting.
  */
 
-
-/*
- * find filename portion of a path (/foo/bar/baz -> baz)
- */
-const char *ceph_file_part(const char *s, int len)
-{
-       const char *e = s + len;
-
-       while (e != s && *(e-1) != '/')
-               e--;
-       return e;
-}
-
-
 /*
  * super ops
  */
 static void ceph_put_super(struct super_block *s)
 {
-       struct ceph_client *client = ceph_sb_to_client(s);
+       struct ceph_fs_client *fsc = ceph_sb_to_client(s);
 
        dout("put_super\n");
-       ceph_mdsc_close_sessions(&client->mdsc);
+       ceph_mdsc_close_sessions(fsc->mdsc);
 
        /*
         * ensure we release the bdi before put_anon_super releases
         * the device name.
         */
-       if (s->s_bdi == &client->backing_dev_info) {
-               bdi_unregister(&client->backing_dev_info);
+       if (s->s_bdi == &fsc->backing_dev_info) {
+               bdi_unregister(&fsc->backing_dev_info);
                s->s_bdi = NULL;
        }
 
@@ -64,14 +53,14 @@ static void ceph_put_super(struct super_block *s)
 
 static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
-       struct ceph_client *client = ceph_inode_to_client(dentry->d_inode);
-       struct ceph_monmap *monmap = client->monc.monmap;
+       struct ceph_fs_client *fsc = ceph_inode_to_client(dentry->d_inode);
+       struct ceph_monmap *monmap = fsc->client->monc.monmap;
        struct ceph_statfs st;
        u64 fsid;
        int err;
 
        dout("statfs\n");
-       err = ceph_monc_do_statfs(&client->monc, &st);
+       err = ceph_monc_do_statfs(&fsc->client->monc, &st);
        if (err < 0)
                return err;
 
@@ -104,238 +93,28 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
 
 static int ceph_sync_fs(struct super_block *sb, int wait)
 {
-       struct ceph_client *client = ceph_sb_to_client(sb);
+       struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
 
        if (!wait) {
                dout("sync_fs (non-blocking)\n");
-               ceph_flush_dirty_caps(&client->mdsc);
+               ceph_flush_dirty_caps(fsc->mdsc);
                dout("sync_fs (non-blocking) done\n");
                return 0;
        }
 
        dout("sync_fs (blocking)\n");
-       ceph_osdc_sync(&ceph_sb_to_client(sb)->osdc);
-       ceph_mdsc_sync(&ceph_sb_to_client(sb)->mdsc);
+       ceph_osdc_sync(&fsc->client->osdc);
+       ceph_mdsc_sync(fsc->mdsc);
        dout("sync_fs (blocking) done\n");
        return 0;
 }
 
-static int default_congestion_kb(void)
-{
-       int congestion_kb;
-
-       /*
-        * Copied from NFS
-        *
-        * congestion size, scale with available memory.
-        *
-        *  64MB:    8192k
-        * 128MB:   11585k
-        * 256MB:   16384k
-        * 512MB:   23170k
-        *   1GB:   32768k
-        *   2GB:   46340k
-        *   4GB:   65536k
-        *   8GB:   92681k
-        *  16GB:  131072k
-        *
-        * This allows larger machines to have larger/more transfers.
-        * Limit the default to 256M
-        */
-       congestion_kb = (16*int_sqrt(totalram_pages)) << (PAGE_SHIFT-10);
-       if (congestion_kb > 256*1024)
-               congestion_kb = 256*1024;
-
-       return congestion_kb;
-}
-
-/**
- * ceph_show_options - Show mount options in /proc/mounts
- * @m: seq_file to write to
- * @mnt: mount descriptor
- */
-static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt)
-{
-       struct ceph_client *client = ceph_sb_to_client(mnt->mnt_sb);
-       struct ceph_mount_args *args = client->mount_args;
-
-       if (args->flags & CEPH_OPT_FSID)
-               seq_printf(m, ",fsid=%pU", &args->fsid);
-       if (args->flags & CEPH_OPT_NOSHARE)
-               seq_puts(m, ",noshare");
-       if (args->flags & CEPH_OPT_DIRSTAT)
-               seq_puts(m, ",dirstat");
-       if ((args->flags & CEPH_OPT_RBYTES) == 0)
-               seq_puts(m, ",norbytes");
-       if (args->flags & CEPH_OPT_NOCRC)
-               seq_puts(m, ",nocrc");
-       if (args->flags & CEPH_OPT_NOASYNCREADDIR)
-               seq_puts(m, ",noasyncreaddir");
-
-       if (args->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
-               seq_printf(m, ",mount_timeout=%d", args->mount_timeout);
-       if (args->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT)
-               seq_printf(m, ",osd_idle_ttl=%d", args->osd_idle_ttl);
-       if (args->osd_timeout != CEPH_OSD_TIMEOUT_DEFAULT)
-               seq_printf(m, ",osdtimeout=%d", args->osd_timeout);
-       if (args->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT)
-               seq_printf(m, ",osdkeepalivetimeout=%d",
-                        args->osd_keepalive_timeout);
-       if (args->wsize)
-               seq_printf(m, ",wsize=%d", args->wsize);
-       if (args->rsize != CEPH_MOUNT_RSIZE_DEFAULT)
-               seq_printf(m, ",rsize=%d", args->rsize);
-       if (args->congestion_kb != default_congestion_kb())
-               seq_printf(m, ",write_congestion_kb=%d", args->congestion_kb);
-       if (args->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT)
-               seq_printf(m, ",caps_wanted_delay_min=%d",
-                        args->caps_wanted_delay_min);
-       if (args->caps_wanted_delay_max != CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT)
-               seq_printf(m, ",caps_wanted_delay_max=%d",
-                          args->caps_wanted_delay_max);
-       if (args->cap_release_safety != CEPH_CAP_RELEASE_SAFETY_DEFAULT)
-               seq_printf(m, ",cap_release_safety=%d",
-                          args->cap_release_safety);
-       if (args->max_readdir != CEPH_MAX_READDIR_DEFAULT)
-               seq_printf(m, ",readdir_max_entries=%d", args->max_readdir);
-       if (args->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT)
-               seq_printf(m, ",readdir_max_bytes=%d", args->max_readdir_bytes);
-       if (strcmp(args->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
-               seq_printf(m, ",snapdirname=%s", args->snapdir_name);
-       if (args->name)
-               seq_printf(m, ",name=%s", args->name);
-       if (args->secret)
-               seq_puts(m, ",secret=<hidden>");
-       return 0;
-}
-
-/*
- * caches
- */
-struct kmem_cache *ceph_inode_cachep;
-struct kmem_cache *ceph_cap_cachep;
-struct kmem_cache *ceph_dentry_cachep;
-struct kmem_cache *ceph_file_cachep;
-
-static void ceph_inode_init_once(void *foo)
-{
-       struct ceph_inode_info *ci = foo;
-       inode_init_once(&ci->vfs_inode);
-}
-
-static int __init init_caches(void)
-{
-       ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
-                                     sizeof(struct ceph_inode_info),
-                                     __alignof__(struct ceph_inode_info),
-                                     (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
-                                     ceph_inode_init_once);
-       if (ceph_inode_cachep == NULL)
-               return -ENOMEM;
-
-       ceph_cap_cachep = KMEM_CACHE(ceph_cap,
-                                    SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
-       if (ceph_cap_cachep == NULL)
-               goto bad_cap;
-
-       ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info,
-                                       SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
-       if (ceph_dentry_cachep == NULL)
-               goto bad_dentry;
-
-       ceph_file_cachep = KMEM_CACHE(ceph_file_info,
-                                     SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
-       if (ceph_file_cachep == NULL)
-               goto bad_file;
-
-       return 0;
-
-bad_file:
-       kmem_cache_destroy(ceph_dentry_cachep);
-bad_dentry:
-       kmem_cache_destroy(ceph_cap_cachep);
-bad_cap:
-       kmem_cache_destroy(ceph_inode_cachep);
-       return -ENOMEM;
-}
-
-static void destroy_caches(void)
-{
-       kmem_cache_destroy(ceph_inode_cachep);
-       kmem_cache_destroy(ceph_cap_cachep);
-       kmem_cache_destroy(ceph_dentry_cachep);
-       kmem_cache_destroy(ceph_file_cachep);
-}
-
-
-/*
- * ceph_umount_begin - initiate forced umount.  Tear down down the
- * mount, skipping steps that may hang while waiting for server(s).
- */
-static void ceph_umount_begin(struct super_block *sb)
-{
-       struct ceph_client *client = ceph_sb_to_client(sb);
-
-       dout("ceph_umount_begin - starting forced umount\n");
-       if (!client)
-               return;
-       client->mount_state = CEPH_MOUNT_SHUTDOWN;
-       return;
-}
-
-static const struct super_operations ceph_super_ops = {
-       .alloc_inode    = ceph_alloc_inode,
-       .destroy_inode  = ceph_destroy_inode,
-       .write_inode    = ceph_write_inode,
-       .sync_fs        = ceph_sync_fs,
-       .put_super      = ceph_put_super,
-       .show_options   = ceph_show_options,
-       .statfs         = ceph_statfs,
-       .umount_begin   = ceph_umount_begin,
-};
-
-
-const char *ceph_msg_type_name(int type)
-{
-       switch (type) {
-       case CEPH_MSG_SHUTDOWN: return "shutdown";
-       case CEPH_MSG_PING: return "ping";
-       case CEPH_MSG_AUTH: return "auth";
-       case CEPH_MSG_AUTH_REPLY: return "auth_reply";
-       case CEPH_MSG_MON_MAP: return "mon_map";
-       case CEPH_MSG_MON_GET_MAP: return "mon_get_map";
-       case CEPH_MSG_MON_SUBSCRIBE: return "mon_subscribe";
-       case CEPH_MSG_MON_SUBSCRIBE_ACK: return "mon_subscribe_ack";
-       case CEPH_MSG_STATFS: return "statfs";
-       case CEPH_MSG_STATFS_REPLY: return "statfs_reply";
-       case CEPH_MSG_MDS_MAP: return "mds_map";
-       case CEPH_MSG_CLIENT_SESSION: return "client_session";
-       case CEPH_MSG_CLIENT_RECONNECT: return "client_reconnect";
-       case CEPH_MSG_CLIENT_REQUEST: return "client_request";
-       case CEPH_MSG_CLIENT_REQUEST_FORWARD: return "client_request_forward";
-       case CEPH_MSG_CLIENT_REPLY: return "client_reply";
-       case CEPH_MSG_CLIENT_CAPS: return "client_caps";
-       case CEPH_MSG_CLIENT_CAPRELEASE: return "client_cap_release";
-       case CEPH_MSG_CLIENT_SNAP: return "client_snap";
-       case CEPH_MSG_CLIENT_LEASE: return "client_lease";
-       case CEPH_MSG_OSD_MAP: return "osd_map";
-       case CEPH_MSG_OSD_OP: return "osd_op";
-       case CEPH_MSG_OSD_OPREPLY: return "osd_opreply";
-       default: return "unknown";
-       }
-}
-
-
 /*
  * mount options
  */
 enum {
        Opt_wsize,
        Opt_rsize,
-       Opt_osdtimeout,
-       Opt_osdkeepalivetimeout,
-       Opt_mount_timeout,
-       Opt_osd_idle_ttl,
        Opt_caps_wanted_delay_min,
        Opt_caps_wanted_delay_max,
        Opt_cap_release_safety,
@@ -344,29 +123,19 @@ enum {
        Opt_congestion_kb,
        Opt_last_int,
        /* int args above */
-       Opt_fsid,
        Opt_snapdirname,
-       Opt_name,
-       Opt_secret,
        Opt_last_string,
        /* string args above */
-       Opt_ip,
-       Opt_noshare,
        Opt_dirstat,
        Opt_nodirstat,
        Opt_rbytes,
        Opt_norbytes,
-       Opt_nocrc,
        Opt_noasyncreaddir,
 };
 
-static match_table_t arg_tokens = {
+static match_table_t fsopt_tokens = {
        {Opt_wsize, "wsize=%d"},
        {Opt_rsize, "rsize=%d"},
-       {Opt_osdtimeout, "osdtimeout=%d"},
-       {Opt_osdkeepalivetimeout, "osdkeepalive=%d"},
-       {Opt_mount_timeout, "mount_timeout=%d"},
-       {Opt_osd_idle_ttl, "osd_idle_ttl=%d"},
        {Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"},
        {Opt_caps_wanted_delay_max, "caps_wanted_delay_max=%d"},
        {Opt_cap_release_safety, "cap_release_safety=%d"},
@@ -374,403 +143,459 @@ static match_table_t arg_tokens = {
        {Opt_readdir_max_bytes, "readdir_max_bytes=%d"},
        {Opt_congestion_kb, "write_congestion_kb=%d"},
        /* int args above */
-       {Opt_fsid, "fsid=%s"},
        {Opt_snapdirname, "snapdirname=%s"},
-       {Opt_name, "name=%s"},
-       {Opt_secret, "secret=%s"},
        /* string args above */
-       {Opt_ip, "ip=%s"},
-       {Opt_noshare, "noshare"},
        {Opt_dirstat, "dirstat"},
        {Opt_nodirstat, "nodirstat"},
        {Opt_rbytes, "rbytes"},
        {Opt_norbytes, "norbytes"},
-       {Opt_nocrc, "nocrc"},
        {Opt_noasyncreaddir, "noasyncreaddir"},
        {-1, NULL}
 };
 
-static int parse_fsid(const char *str, struct ceph_fsid *fsid)
+static int parse_fsopt_token(char *c, void *private)
 {
-       int i = 0;
-       char tmp[3];
-       int err = -EINVAL;
-       int d;
-
-       dout("parse_fsid '%s'\n", str);
-       tmp[2] = 0;
-       while (*str && i < 16) {
-               if (ispunct(*str)) {
-                       str++;
-                       continue;
+       struct ceph_mount_options *fsopt = private;
+       substring_t argstr[MAX_OPT_ARGS];
+       int token, intval, ret;
+
+       token = match_token((char *)c, fsopt_tokens, argstr);
+       if (token < 0)
+               return -EINVAL;
+
+       if (token < Opt_last_int) {
+               ret = match_int(&argstr[0], &intval);
+               if (ret < 0) {
+                       pr_err("bad mount option arg (not int) "
+                              "at '%s'\n", c);
+                       return ret;
                }
-               if (!isxdigit(str[0]) || !isxdigit(str[1]))
-                       break;
-               tmp[0] = str[0];
-               tmp[1] = str[1];
-               if (sscanf(tmp, "%x", &d) < 1)
-                       break;
-               fsid->fsid[i] = d & 0xff;
-               i++;
-               str += 2;
+               dout("got int token %d val %d\n", token, intval);
+       } else if (token > Opt_last_int && token < Opt_last_string) {
+               dout("got string token %d val %s\n", token,
+                    argstr[0].from);
+       } else {
+               dout("got token %d\n", token);
        }
 
-       if (i == 16)
-               err = 0;
-       dout("parse_fsid ret %d got fsid %pU", err, fsid);
-       return err;
+       switch (token) {
+       case Opt_snapdirname:
+               kfree(fsopt->snapdir_name);
+               fsopt->snapdir_name = kstrndup(argstr[0].from,
+                                              argstr[0].to-argstr[0].from,
+                                              GFP_KERNEL);
+               if (!fsopt->snapdir_name)
+                       return -ENOMEM;
+               break;
+
+               /* misc */
+       case Opt_wsize:
+               fsopt->wsize = intval;
+               break;
+       case Opt_rsize:
+               fsopt->rsize = intval;
+               break;
+       case Opt_caps_wanted_delay_min:
+               fsopt->caps_wanted_delay_min = intval;
+               break;
+       case Opt_caps_wanted_delay_max:
+               fsopt->caps_wanted_delay_max = intval;
+               break;
+       case Opt_readdir_max_entries:
+               fsopt->max_readdir = intval;
+               break;
+       case Opt_readdir_max_bytes:
+               fsopt->max_readdir_bytes = intval;
+               break;
+       case Opt_congestion_kb:
+               fsopt->congestion_kb = intval;
+               break;
+       case Opt_dirstat:
+               fsopt->flags |= CEPH_MOUNT_OPT_DIRSTAT;
+               break;
+       case Opt_nodirstat:
+               fsopt->flags &= ~CEPH_MOUNT_OPT_DIRSTAT;
+               break;
+       case Opt_rbytes:
+               fsopt->flags |= CEPH_MOUNT_OPT_RBYTES;
+               break;
+       case Opt_norbytes:
+               fsopt->flags &= ~CEPH_MOUNT_OPT_RBYTES;
+               break;
+       case Opt_noasyncreaddir:
+               fsopt->flags |= CEPH_MOUNT_OPT_NOASYNCREADDIR;
+               break;
+       default:
+               BUG_ON(token);
+       }
+       return 0;
 }
 
-static struct ceph_mount_args *parse_mount_args(int flags, char *options,
-                                               const char *dev_name,
-                                               const char **path)
+static void destroy_mount_options(struct ceph_mount_options *args)
 {
-       struct ceph_mount_args *args;
-       const char *c;
-       int err = -ENOMEM;
-       substring_t argstr[MAX_OPT_ARGS];
+       dout("destroy_mount_options %p\n", args);
+       kfree(args->snapdir_name);
+       kfree(args);
+}
 
-       args = kzalloc(sizeof(*args), GFP_KERNEL);
-       if (!args)
-               return ERR_PTR(-ENOMEM);
-       args->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*args->mon_addr),
-                                GFP_KERNEL);
-       if (!args->mon_addr)
-               goto out;
+static int strcmp_null(const char *s1, const char *s2)
+{
+       if (!s1 && !s2)
+               return 0;
+       if (s1 && !s2)
+               return -1;
+       if (!s1 && s2)
+               return 1;
+       return strcmp(s1, s2);
+}
 
-       dout("parse_mount_args %p, dev_name '%s'\n", args, dev_name);
-
-       /* start with defaults */
-       args->sb_flags = flags;
-       args->flags = CEPH_OPT_DEFAULT;
-       args->osd_timeout = CEPH_OSD_TIMEOUT_DEFAULT;
-       args->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
-       args->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */
-       args->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;   /* seconds */
-       args->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
-       args->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;
-       args->rsize = CEPH_MOUNT_RSIZE_DEFAULT;
-       args->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
-       args->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT;
-       args->max_readdir = CEPH_MAX_READDIR_DEFAULT;
-       args->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
-       args->congestion_kb = default_congestion_kb();
-
-       /* ip1[:port1][,ip2[:port2]...]:/subdir/in/fs */
-       err = -EINVAL;
-       if (!dev_name)
-               goto out;
-       *path = strstr(dev_name, ":/");
-       if (*path == NULL) {
-               pr_err("device name is missing path (no :/ in %s)\n",
-                      dev_name);
-               goto out;
-       }
+static int compare_mount_options(struct ceph_mount_options *new_fsopt,
+                                struct ceph_options *new_opt,
+                                struct ceph_fs_client *fsc)
+{
+       struct ceph_mount_options *fsopt1 = new_fsopt;
+       struct ceph_mount_options *fsopt2 = fsc->mount_options;
+       int ofs = offsetof(struct ceph_mount_options, snapdir_name);
+       int ret;
 
-       /* get mon ip(s) */
-       err = ceph_parse_ips(dev_name, *path, args->mon_addr,
-                            CEPH_MAX_MON, &args->num_mon);
-       if (err < 0)
-               goto out;
+       ret = memcmp(fsopt1, fsopt2, ofs);
+       if (ret)
+               return ret;
+
+       ret = strcmp_null(fsopt1->snapdir_name, fsopt2->snapdir_name);
+       if (ret)
+               return ret;
+
+       return ceph_compare_options(new_opt, fsc->client);
+}
+
+static int parse_mount_options(struct ceph_mount_options **pfsopt,
+                              struct ceph_options **popt,
+                              int flags, char *options,
+                              const char *dev_name,
+                              const char **path)
+{
+       struct ceph_mount_options *fsopt;
+       const char *dev_name_end;
+       int err = -ENOMEM;
+
+       fsopt = kzalloc(sizeof(*fsopt), GFP_KERNEL);
+       if (!fsopt)
+               return -ENOMEM;
+
+       dout("parse_mount_options %p, dev_name '%s'\n", fsopt, dev_name);
+
+        fsopt->sb_flags = flags;
+        fsopt->flags = CEPH_MOUNT_OPT_DEFAULT;
+
+        fsopt->rsize = CEPH_MOUNT_RSIZE_DEFAULT;
+        fsopt->snapdir_name = kstrdup(CEPH_SNAPDIRNAME_DEFAULT, GFP_KERNEL);
+        fsopt->cap_release_safety = CEPH_CAP_RELEASE_SAFETY_DEFAULT;
+        fsopt->max_readdir = CEPH_MAX_READDIR_DEFAULT;
+        fsopt->max_readdir_bytes = CEPH_MAX_READDIR_BYTES_DEFAULT;
+        fsopt->congestion_kb = default_congestion_kb();
+       
+        /* ip1[:port1][,ip2[:port2]...]:/subdir/in/fs */
+        err = -EINVAL;
+        if (!dev_name)
+                goto out;
+        *path = strstr(dev_name, ":/");
+        if (*path == NULL) {
+                pr_err("device name is missing path (no :/ in %s)\n",
+                       dev_name);
+                goto out;
+        }
+       dev_name_end = *path;
+       dout("device name '%.*s'\n", (int)(dev_name_end - dev_name), dev_name);
 
        /* path on server */
        *path += 2;
        dout("server path '%s'\n", *path);
 
-       /* parse mount options */
-       while ((c = strsep(&options, ",")) != NULL) {
-               int token, intval, ret;
-               if (!*c)
-                       continue;
-               err = -EINVAL;
-               token = match_token((char *)c, arg_tokens, argstr);
-               if (token < 0) {
-                       pr_err("bad mount option at '%s'\n", c);
-                       goto out;
-               }
-               if (token < Opt_last_int) {
-                       ret = match_int(&argstr[0], &intval);
-                       if (ret < 0) {
-                               pr_err("bad mount option arg (not int) "
-                                      "at '%s'\n", c);
-                               continue;
-                       }
-                       dout("got int token %d val %d\n", token, intval);
-               } else if (token > Opt_last_int && token < Opt_last_string) {
-                       dout("got string token %d val %s\n", token,
-                            argstr[0].from);
-               } else {
-                       dout("got token %d\n", token);
-               }
-               switch (token) {
-               case Opt_ip:
-                       err = ceph_parse_ips(argstr[0].from,
-                                            argstr[0].to,
-                                            &args->my_addr,
-                                            1, NULL);
-                       if (err < 0)
-                               goto out;
-                       args->flags |= CEPH_OPT_MYIP;
-                       break;
-
-               case Opt_fsid:
-                       err = parse_fsid(argstr[0].from, &args->fsid);
-                       if (err == 0)
-                               args->flags |= CEPH_OPT_FSID;
-                       break;
-               case Opt_snapdirname:
-                       kfree(args->snapdir_name);
-                       args->snapdir_name = kstrndup(argstr[0].from,
-                                             argstr[0].to-argstr[0].from,
-                                             GFP_KERNEL);
-                       break;
-               case Opt_name:
-                       args->name = kstrndup(argstr[0].from,
-                                             argstr[0].to-argstr[0].from,
-                                             GFP_KERNEL);
-                       break;
-               case Opt_secret:
-                       args->secret = kstrndup(argstr[0].from,
-                                               argstr[0].to-argstr[0].from,
-                                               GFP_KERNEL);
-                       break;
-
-                       /* misc */
-               case Opt_wsize:
-                       args->wsize = intval;
-                       break;
-               case Opt_rsize:
-                       args->rsize = intval;
-                       break;
-               case Opt_osdtimeout:
-                       args->osd_timeout = intval;
-                       break;
-               case Opt_osdkeepalivetimeout:
-                       args->osd_keepalive_timeout = intval;
-                       break;
-               case Opt_osd_idle_ttl:
-                       args->osd_idle_ttl = intval;
-                       break;
-               case Opt_mount_timeout:
-                       args->mount_timeout = intval;
-                       break;
-               case Opt_caps_wanted_delay_min:
-                       args->caps_wanted_delay_min = intval;
-                       break;
-               case Opt_caps_wanted_delay_max:
-                       args->caps_wanted_delay_max = intval;
-                       break;
-               case Opt_readdir_max_entries:
-                       args->max_readdir = intval;
-                       break;
-               case Opt_readdir_max_bytes:
-                       args->max_readdir_bytes = intval;
-                       break;
-               case Opt_congestion_kb:
-                       args->congestion_kb = intval;
-                       break;
-
-               case Opt_noshare:
-                       args->flags |= CEPH_OPT_NOSHARE;
-                       break;
-
-               case Opt_dirstat:
-                       args->flags |= CEPH_OPT_DIRSTAT;
-                       break;
-               case Opt_nodirstat:
-                       args->flags &= ~CEPH_OPT_DIRSTAT;
-                       break;
-               case Opt_rbytes:
-                       args->flags |= CEPH_OPT_RBYTES;
-                       break;
-               case Opt_norbytes:
-                       args->flags &= ~CEPH_OPT_RBYTES;
-                       break;
-               case Opt_nocrc:
-                       args->flags |= CEPH_OPT_NOCRC;
-                       break;
-               case Opt_noasyncreaddir:
-                       args->flags |= CEPH_OPT_NOASYNCREADDIR;
-                       break;
-
-               default:
-                       BUG_ON(token);
-               }
-       }
-       return args;
+       err = ceph_parse_options(popt, options, dev_name, dev_name_end,
+                                parse_fsopt_token, (void *)fsopt);
+       if (err)
+               goto out;
+
+       /* success */
+       *pfsopt = fsopt;
+       return 0;
 
 out:
-       kfree(args->mon_addr);
-       kfree(args);
-       return ERR_PTR(err);
+       destroy_mount_options(fsopt);
+       return err;
 }
 
-static void destroy_mount_args(struct ceph_mount_args *args)
+/**
+ * ceph_show_options - Show mount options in /proc/mounts
+ * @m: seq_file to write to
+ * @mnt: mount descriptor
+ */
+static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt)
 {
-       dout("destroy_mount_args %p\n", args);
-       kfree(args->snapdir_name);
-       args->snapdir_name = NULL;
-       kfree(args->name);
-       args->name = NULL;
-       kfree(args->secret);
-       args->secret = NULL;
-       kfree(args);
+       struct ceph_fs_client *fsc = ceph_sb_to_client(mnt->mnt_sb);
+       struct ceph_mount_options *fsopt = fsc->mount_options;
+       struct ceph_options *opt = fsc->client->options;
+
+       if (opt->flags & CEPH_OPT_FSID)
+               seq_printf(m, ",fsid=%pU", &opt->fsid);
+       if (opt->flags & CEPH_OPT_NOSHARE)
+               seq_puts(m, ",noshare");
+       if (opt->flags & CEPH_OPT_NOCRC)
+               seq_puts(m, ",nocrc");
+
+       if (opt->name)
+               seq_printf(m, ",name=%s", opt->name);
+       if (opt->secret)
+               seq_puts(m, ",secret=<hidden>");
+
+       if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
+               seq_printf(m, ",mount_timeout=%d", opt->mount_timeout);
+       if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT)
+               seq_printf(m, ",osd_idle_ttl=%d", opt->osd_idle_ttl);
+       if (opt->osd_timeout != CEPH_OSD_TIMEOUT_DEFAULT)
+               seq_printf(m, ",osdtimeout=%d", opt->osd_timeout);
+       if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT)
+               seq_printf(m, ",osdkeepalivetimeout=%d",
+                          opt->osd_keepalive_timeout);
+
+       if (fsopt->flags & CEPH_MOUNT_OPT_DIRSTAT)
+               seq_puts(m, ",dirstat");
+       if ((fsopt->flags & CEPH_MOUNT_OPT_RBYTES) == 0)
+               seq_puts(m, ",norbytes");
+       if (fsopt->flags & CEPH_MOUNT_OPT_NOASYNCREADDIR)
+               seq_puts(m, ",noasyncreaddir");
+
+       if (fsopt->wsize)
+               seq_printf(m, ",wsize=%d", fsopt->wsize);
+       if (fsopt->rsize != CEPH_MOUNT_RSIZE_DEFAULT)
+               seq_printf(m, ",rsize=%d", fsopt->rsize);
+       if (fsopt->congestion_kb != default_congestion_kb())
+               seq_printf(m, ",write_congestion_kb=%d", fsopt->congestion_kb);
+       if (fsopt->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT)
+               seq_printf(m, ",caps_wanted_delay_min=%d",
+                        fsopt->caps_wanted_delay_min);
+       if (fsopt->caps_wanted_delay_max != CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT)
+               seq_printf(m, ",caps_wanted_delay_max=%d",
+                          fsopt->caps_wanted_delay_max);
+       if (fsopt->cap_release_safety != CEPH_CAP_RELEASE_SAFETY_DEFAULT)
+               seq_printf(m, ",cap_release_safety=%d",
+                          fsopt->cap_release_safety);
+       if (fsopt->max_readdir != CEPH_MAX_READDIR_DEFAULT)
+               seq_printf(m, ",readdir_max_entries=%d", fsopt->max_readdir);
+       if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT)
+               seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes);
+       if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT))
+               seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name);
+       return 0;
 }
 
 /*
- * create a fresh client instance
+ * handle any mon messages the standard library doesn't understand.
+ * return error if we don't either.
  */
-static struct ceph_client *ceph_create_client(struct ceph_mount_args *args)
+static int extra_mon_dispatch(struct ceph_client *client, struct ceph_msg *msg)
 {
-       struct ceph_client *client;
+       struct ceph_fs_client *fsc = client->private;
+       int type = le16_to_cpu(msg->hdr.type);
+
+       switch (type) {
+       case CEPH_MSG_MDS_MAP:
+               ceph_mdsc_handle_map(fsc->mdsc, msg);
+               return 0;
+
+       default:
+               return -1;
+       }
+}
+
+/*
+ * create a new fs client
+ */
+struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
+                                       struct ceph_options *opt)
+{
+       struct ceph_fs_client *fsc;
        int err = -ENOMEM;
 
-       client = kzalloc(sizeof(*client), GFP_KERNEL);
-       if (client == NULL)
+       fsc = kzalloc(sizeof(*fsc), GFP_KERNEL);
+       if (!fsc)
                return ERR_PTR(-ENOMEM);
 
-       mutex_init(&client->mount_mutex);
-
-       init_waitqueue_head(&client->auth_wq);
+       fsc->client = ceph_create_client(opt, fsc);
+       if (IS_ERR(fsc->client)) {
+               err = PTR_ERR(fsc->client);
+               goto fail;
+       }
+       fsc->client->extra_mon_dispatch = extra_mon_dispatch;
+       fsc->client->supported_features |= CEPH_FEATURE_FLOCK;
+       fsc->client->monc.want_mdsmap = 1;
 
-       client->sb = NULL;
-       client->mount_state = CEPH_MOUNT_MOUNTING;
-       client->mount_args = args;
+       fsc->mount_options = fsopt;
 
-       client->msgr = NULL;
+       fsc->sb = NULL;
+       fsc->mount_state = CEPH_MOUNT_MOUNTING;
 
-       client->auth_err = 0;
-       atomic_long_set(&client->writeback_count, 0);
+       atomic_long_set(&fsc->writeback_count, 0);
 
-       err = bdi_init(&client->backing_dev_info);
+       err = bdi_init(&fsc->backing_dev_info);
        if (err < 0)
-               goto fail;
+               goto fail_client;
 
        err = -ENOMEM;
-       client->wb_wq = create_workqueue("ceph-writeback");
-       if (client->wb_wq == NULL)
+       fsc->wb_wq = create_workqueue("ceph-writeback");
+       if (fsc->wb_wq == NULL)
                goto fail_bdi;
-       client->pg_inv_wq = create_singlethread_workqueue("ceph-pg-invalid");
-       if (client->pg_inv_wq == NULL)
+       fsc->pg_inv_wq = create_singlethread_workqueue("ceph-pg-invalid");
+       if (fsc->pg_inv_wq == NULL)
                goto fail_wb_wq;
-       client->trunc_wq = create_singlethread_workqueue("ceph-trunc");
-       if (client->trunc_wq == NULL)
+       fsc->trunc_wq = create_singlethread_workqueue("ceph-trunc");
+       if (fsc->trunc_wq == NULL)
                goto fail_pg_inv_wq;
 
        /* set up mempools */
        err = -ENOMEM;
-       client->wb_pagevec_pool = mempool_create_kmalloc_pool(10,
-                             client->mount_args->wsize >> PAGE_CACHE_SHIFT);
-       if (!client->wb_pagevec_pool)
+       fsc->wb_pagevec_pool = mempool_create_kmalloc_pool(10,
+                             fsc->mount_options->wsize >> PAGE_CACHE_SHIFT);
+       if (!fsc->wb_pagevec_pool)
                goto fail_trunc_wq;
 
        /* caps */
-       client->min_caps = args->max_readdir;
+       fsc->min_caps = fsopt->max_readdir;
+
+       return fsc;
 
-       /* subsystems */
-       err = ceph_monc_init(&client->monc, client);
-       if (err < 0)
-               goto fail_mempool;
-       err = ceph_osdc_init(&client->osdc, client);
-       if (err < 0)
-               goto fail_monc;
-       err = ceph_mdsc_init(&client->mdsc, client);
-       if (err < 0)
-               goto fail_osdc;
-       return client;
-
-fail_osdc:
-       ceph_osdc_stop(&client->osdc);
-fail_monc:
-       ceph_monc_stop(&client->monc);
-fail_mempool:
-       mempool_destroy(client->wb_pagevec_pool);
 fail_trunc_wq:
-       destroy_workqueue(client->trunc_wq);
+       destroy_workqueue(fsc->trunc_wq);
 fail_pg_inv_wq:
-       destroy_workqueue(client->pg_inv_wq);
+       destroy_workqueue(fsc->pg_inv_wq);
 fail_wb_wq:
-       destroy_workqueue(client->wb_wq);
+       destroy_workqueue(fsc->wb_wq);
 fail_bdi:
-       bdi_destroy(&client->backing_dev_info);
+       bdi_destroy(&fsc->backing_dev_info);
+fail_client:
+       ceph_destroy_client(fsc->client);
 fail:
-       kfree(client);
+       kfree(fsc);
        return ERR_PTR(err);
 }
 
-static void ceph_destroy_client(struct ceph_client *client)
+void destroy_fs_client(struct ceph_fs_client *fsc)
 {
-       dout("destroy_client %p\n", client);
+       dout("destroy_fs_client %p\n", fsc);
 
-       /* unmount */
-       ceph_mdsc_stop(&client->mdsc);
-       ceph_osdc_stop(&client->osdc);
+       destroy_workqueue(fsc->wb_wq);
+       destroy_workqueue(fsc->pg_inv_wq);
+       destroy_workqueue(fsc->trunc_wq);
 
-       /*
-        * make sure mds and osd connections close out before destroying
-        * the auth module, which is needed to free those connections'
-        * ceph_authorizers.
-        */
-       ceph_msgr_flush();
-
-       ceph_monc_stop(&client->monc);
+       bdi_destroy(&fsc->backing_dev_info);
 
-       ceph_debugfs_client_cleanup(client);
-       destroy_workqueue(client->wb_wq);
-       destroy_workqueue(client->pg_inv_wq);
-       destroy_workqueue(client->trunc_wq);
+       mempool_destroy(fsc->wb_pagevec_pool);
 
-       bdi_destroy(&client->backing_dev_info);
+       destroy_mount_options(fsc->mount_options);
 
-       if (client->msgr)
-               ceph_messenger_destroy(client->msgr);
-       mempool_destroy(client->wb_pagevec_pool);
+       ceph_fs_debugfs_cleanup(fsc);
 
-       destroy_mount_args(client->mount_args);
+       ceph_destroy_client(fsc->client);
 
-       kfree(client);
-       dout("destroy_client %p done\n", client);
+       kfree(fsc);
+       dout("destroy_fs_client %p done\n", fsc);
 }
 
 /*
- * Initially learn our fsid, or verify an fsid matches.
+ * caches
  */
-int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid)
+struct kmem_cache *ceph_inode_cachep;
+struct kmem_cache *ceph_cap_cachep;
+struct kmem_cache *ceph_dentry_cachep;
+struct kmem_cache *ceph_file_cachep;
+
+static void ceph_inode_init_once(void *foo)
 {
-       if (client->have_fsid) {
-               if (ceph_fsid_compare(&client->fsid, fsid)) {
-                       pr_err("bad fsid, had %pU got %pU",
-                              &client->fsid, fsid);
-                       return -1;
-               }
-       } else {
-               pr_info("client%lld fsid %pU\n", client->monc.auth->global_id,
-                       fsid);
-               memcpy(&client->fsid, fsid, sizeof(*fsid));
-               ceph_debugfs_client_init(client);
-               client->have_fsid = true;
-       }
+       struct ceph_inode_info *ci = foo;
+       inode_init_once(&ci->vfs_inode);
+}
+
+static int __init init_caches(void)
+{
+       ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
+                                     sizeof(struct ceph_inode_info),
+                                     __alignof__(struct ceph_inode_info),
+                                     (SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD),
+                                     ceph_inode_init_once);
+       if (ceph_inode_cachep == NULL)
+               return -ENOMEM;
+
+       ceph_cap_cachep = KMEM_CACHE(ceph_cap,
+                                    SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+       if (ceph_cap_cachep == NULL)
+               goto bad_cap;
+
+       ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info,
+                                       SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+       if (ceph_dentry_cachep == NULL)
+               goto bad_dentry;
+
+       ceph_file_cachep = KMEM_CACHE(ceph_file_info,
+                                     SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
+       if (ceph_file_cachep == NULL)
+               goto bad_file;
+
        return 0;
+
+bad_file:
+       kmem_cache_destroy(ceph_dentry_cachep);
+bad_dentry:
+       kmem_cache_destroy(ceph_cap_cachep);
+bad_cap:
+       kmem_cache_destroy(ceph_inode_cachep);
+       return -ENOMEM;
 }
 
+static void destroy_caches(void)
+{
+       kmem_cache_destroy(ceph_inode_cachep);
+       kmem_cache_destroy(ceph_cap_cachep);
+       kmem_cache_destroy(ceph_dentry_cachep);
+       kmem_cache_destroy(ceph_file_cachep);
+}
+
+
 /*
- * true if we have the mon map (and have thus joined the cluster)
+ * ceph_umount_begin - initiate forced umount.  Tear down down the
+ * mount, skipping steps that may hang while waiting for server(s).
  */
-static int have_mon_and_osd_map(struct ceph_client *client)
+static void ceph_umount_begin(struct super_block *sb)
 {
-       return client->monc.monmap && client->monc.monmap->epoch &&
-              client->osdc.osdmap && client->osdc.osdmap->epoch;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
+
+       dout("ceph_umount_begin - starting forced umount\n");
+       if (!fsc)
+               return;
+       fsc->mount_state = CEPH_MOUNT_SHUTDOWN;
+       return;
 }
 
+static const struct super_operations ceph_super_ops = {
+       .alloc_inode    = ceph_alloc_inode,
+       .destroy_inode  = ceph_destroy_inode,
+       .write_inode    = ceph_write_inode,
+       .sync_fs        = ceph_sync_fs,
+       .put_super      = ceph_put_super,
+       .show_options   = ceph_show_options,
+       .statfs         = ceph_statfs,
+       .umount_begin   = ceph_umount_begin,
+};
+
 /*
  * Bootstrap mount by opening the root directory.  Note the mount
  * @started time from caller, and time out if this takes too long.
  */
-static struct dentry *open_root_dentry(struct ceph_client *client,
+static struct dentry *open_root_dentry(struct ceph_fs_client *fsc,
                                       const char *path,
                                       unsigned long started)
 {
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct ceph_mds_request *req = NULL;
        int err;
        struct dentry *root;
@@ -784,14 +609,14 @@ static struct dentry *open_root_dentry(struct ceph_client *client,
        req->r_ino1.ino = CEPH_INO_ROOT;
        req->r_ino1.snap = CEPH_NOSNAP;
        req->r_started = started;
-       req->r_timeout = client->mount_args->mount_timeout * HZ;
+       req->r_timeout = fsc->client->options->mount_timeout * HZ;
        req->r_args.getattr.mask = cpu_to_le32(CEPH_STAT_CAP_INODE);
        req->r_num_caps = 2;
        err = ceph_mdsc_do_request(mdsc, NULL, req);
        if (err == 0) {
                dout("open_root_inode success\n");
                if (ceph_ino(req->r_target_inode) == CEPH_INO_ROOT &&
-                   client->sb->s_root == NULL)
+                   fsc->sb->s_root == NULL)
                        root = d_alloc_root(req->r_target_inode);
                else
                        root = d_obtain_alias(req->r_target_inode);
@@ -804,105 +629,86 @@ static struct dentry *open_root_dentry(struct ceph_client *client,
        return root;
 }
 
+
+
+
 /*
  * mount: join the ceph cluster, and open root directory.
  */
-static int ceph_mount(struct ceph_client *client, struct vfsmount *mnt,
+static int ceph_mount(struct ceph_fs_client *fsc, struct vfsmount *mnt,
                      const char *path)
 {
-       struct ceph_entity_addr *myaddr = NULL;
        int err;
-       unsigned long timeout = client->mount_args->mount_timeout * HZ;
        unsigned long started = jiffies;  /* note the start time */
        struct dentry *root;
+       int first = 0;   /* first vfsmount for this super_block */
 
        dout("mount start\n");
-       mutex_lock(&client->mount_mutex);
-
-       /* initialize the messenger */
-       if (client->msgr == NULL) {
-               if (ceph_test_opt(client, MYIP))
-                       myaddr = &client->mount_args->my_addr;
-               client->msgr = ceph_messenger_create(myaddr);
-               if (IS_ERR(client->msgr)) {
-                       err = PTR_ERR(client->msgr);
-                       client->msgr = NULL;
-                       goto out;
-               }
-               client->msgr->nocrc = ceph_test_opt(client, NOCRC);
-       }
+       mutex_lock(&fsc->client->mount_mutex);
 
-       /* open session, and wait for mon, mds, and osd maps */
-       err = ceph_monc_open_session(&client->monc);
+       err = __ceph_open_session(fsc->client, started);
        if (err < 0)
                goto out;
 
-       while (!have_mon_and_osd_map(client)) {
-               err = -EIO;
-               if (timeout && time_after_eq(jiffies, started + timeout))
-                       goto out;
-
-               /* wait */
-               dout("mount waiting for mon_map\n");
-               err = wait_event_interruptible_timeout(client->auth_wq,
-                      have_mon_and_osd_map(client) || (client->auth_err < 0),
-                      timeout);
-               if (err == -EINTR || err == -ERESTARTSYS)
-                       goto out;
-               if (client->auth_err < 0) {
-                       err = client->auth_err;
-                       goto out;
-               }
-       }
-
        dout("mount opening root\n");
-       root = open_root_dentry(client, "", started);
+       root = open_root_dentry(fsc, "", started);
        if (IS_ERR(root)) {
                err = PTR_ERR(root);
                goto out;
        }
-       if (client->sb->s_root)
+       if (fsc->sb->s_root) {
                dput(root);
-       else
-               client->sb->s_root = root;
+       } else {
+               fsc->sb->s_root = root;
+               first = 1;
+
+               err = ceph_fs_debugfs_init(fsc);
+               if (err < 0)
+                       goto fail;
+       }
 
        if (path[0] == 0) {
                dget(root);
        } else {
                dout("mount opening base mountpoint\n");
-               root = open_root_dentry(client, path, started);
+               root = open_root_dentry(fsc, path, started);
                if (IS_ERR(root)) {
                        err = PTR_ERR(root);
-                       dput(client->sb->s_root);
-                       client->sb->s_root = NULL;
-                       goto out;
+                       goto fail;
                }
        }
 
        mnt->mnt_root = root;
-       mnt->mnt_sb = client->sb;
+       mnt->mnt_sb = fsc->sb;
 
-       client->mount_state = CEPH_MOUNT_MOUNTED;
+       fsc->mount_state = CEPH_MOUNT_MOUNTED;
        dout("mount success\n");
        err = 0;
 
 out:
-       mutex_unlock(&client->mount_mutex);
+       mutex_unlock(&fsc->client->mount_mutex);
        return err;
+
+fail:
+       if (first) {
+               dput(fsc->sb->s_root);
+               fsc->sb->s_root = NULL;
+       }
+       goto out;
 }
 
 static int ceph_set_super(struct super_block *s, void *data)
 {
-       struct ceph_client *client = data;
+       struct ceph_fs_client *fsc = data;
        int ret;
 
        dout("set_super %p data %p\n", s, data);
 
-       s->s_flags = client->mount_args->sb_flags;
+       s->s_flags = fsc->mount_options->sb_flags;
        s->s_maxbytes = 1ULL << 40;  /* temp value until we get mdsmap */
 
-       s->s_fs_info = client;
-       client->sb = s;
+       s->s_fs_info = fsc;
+       fsc->sb = s;
 
        s->s_op = &ceph_super_ops;
        s->s_export_op = &ceph_export_ops;
@@ -917,7 +723,7 @@ static int ceph_set_super(struct super_block *s, void *data)
 
 fail:
        s->s_fs_info = NULL;
-       client->sb = NULL;
+       fsc->sb = NULL;
        return ret;
 }
 
@@ -926,30 +732,23 @@ fail:
  */
 static int ceph_compare_super(struct super_block *sb, void *data)
 {
-       struct ceph_client *new = data;
-       struct ceph_mount_args *args = new->mount_args;
-       struct ceph_client *other = ceph_sb_to_client(sb);
-       int i;
+       struct ceph_fs_client *new = data;
+       struct ceph_mount_options *fsopt = new->mount_options;
+       struct ceph_options *opt = new->client->options;
+       struct ceph_fs_client *other = ceph_sb_to_client(sb);
 
        dout("ceph_compare_super %p\n", sb);
-       if (args->flags & CEPH_OPT_FSID) {
-               if (ceph_fsid_compare(&args->fsid, &other->fsid)) {
-                       dout("fsid doesn't match\n");
-                       return 0;
-               }
-       } else {
-               /* do we share (a) monitor? */
-               for (i = 0; i < new->monc.monmap->num_mon; i++)
-                       if (ceph_monmap_contains(other->monc.monmap,
-                                        &new->monc.monmap->mon_inst[i].addr))
-                               break;
-               if (i == new->monc.monmap->num_mon) {
-                       dout("mon ip not part of monmap\n");
-                       return 0;
-               }
-               dout("mon ip matches existing sb %p\n", sb);
+
+       if (compare_mount_options(fsopt, opt, other)) {
+               dout("monitor(s)/mount options don't match\n");
+               return 0;
        }
-       if (args->sb_flags != other->mount_args->sb_flags) {
+       if ((opt->flags & CEPH_OPT_FSID) &&
+           ceph_fsid_compare(&opt->fsid, &other->client->fsid)) {
+               dout("fsid doesn't match\n");
+               return 0;
+       }
+       if (fsopt->sb_flags != other->mount_options->sb_flags) {
                dout("flags differ\n");
                return 0;
        }
@@ -961,19 +760,20 @@ static int ceph_compare_super(struct super_block *sb, void *data)
  */
 static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0);
 
-static int ceph_register_bdi(struct super_block *sb, struct ceph_client *client)
+static int ceph_register_bdi(struct super_block *sb,
+                            struct ceph_fs_client *fsc)
 {
        int err;
 
        /* set ra_pages based on rsize mount option? */
-       if (client->mount_args->rsize >= PAGE_CACHE_SIZE)
-               client->backing_dev_info.ra_pages =
-                       (client->mount_args->rsize + PAGE_CACHE_SIZE - 1)
+       if (fsc->mount_options->rsize >= PAGE_CACHE_SIZE)
+               fsc->backing_dev_info.ra_pages =
+                       (fsc->mount_options->rsize + PAGE_CACHE_SIZE - 1)
                        >> PAGE_SHIFT;
-       err = bdi_register(&client->backing_dev_info, NULL, "ceph-%d",
+       err = bdi_register(&fsc->backing_dev_info, NULL, "ceph-%d",
                           atomic_long_inc_return(&bdi_seq));
        if (!err)
-               sb->s_bdi = &client->backing_dev_info;
+               sb->s_bdi = &fsc->backing_dev_info;
        return err;
 }
 
@@ -982,46 +782,52 @@ static int ceph_get_sb(struct file_system_type *fs_type,
                       struct vfsmount *mnt)
 {
        struct super_block *sb;
-       struct ceph_client *client;
+       struct ceph_fs_client *fsc;
        int err;
        int (*compare_super)(struct super_block *, void *) = ceph_compare_super;
        const char *path = NULL;
-       struct ceph_mount_args *args;
+       struct ceph_mount_options *fsopt = NULL;
+       struct ceph_options *opt = NULL;
 
        dout("ceph_get_sb\n");
-       args = parse_mount_args(flags, data, dev_name, &path);
-       if (IS_ERR(args)) {
-               err = PTR_ERR(args);
+       err = parse_mount_options(&fsopt, &opt, flags, data, dev_name, &path);
+       if (err < 0)
                goto out_final;
-       }
 
        /* create client (which we may/may not use) */
-       client = ceph_create_client(args);
-       if (IS_ERR(client)) {
-               err = PTR_ERR(client);
+       fsc = create_fs_client(fsopt, opt);
+       if (IS_ERR(fsc)) {
+               err = PTR_ERR(fsc);
+               kfree(fsopt);
+               kfree(opt);
                goto out_final;
        }
 
-       if (client->mount_args->flags & CEPH_OPT_NOSHARE)
+       err = ceph_mdsc_init(fsc);
+       if (err < 0)
+               goto out;
+
+       if (ceph_test_opt(fsc->client, NOSHARE))
                compare_super = NULL;
-       sb = sget(fs_type, compare_super, ceph_set_super, client);
+       sb = sget(fs_type, compare_super, ceph_set_super, fsc);
        if (IS_ERR(sb)) {
                err = PTR_ERR(sb);
                goto out;
        }
 
-       if (ceph_sb_to_client(sb) != client) {
-               ceph_destroy_client(client);
-               client = ceph_sb_to_client(sb);
-               dout("get_sb got existing client %p\n", client);
+       if (ceph_sb_to_client(sb) != fsc) {
+               ceph_mdsc_destroy(fsc);
+               destroy_fs_client(fsc);
+               fsc = ceph_sb_to_client(sb);
+               dout("get_sb got existing client %p\n", fsc);
        } else {
-               dout("get_sb using new client %p\n", client);
-               err = ceph_register_bdi(sb, client);
+               dout("get_sb using new client %p\n", fsc);
+               err = ceph_register_bdi(sb, fsc);
                if (err < 0)
                        goto out_splat;
        }
 
-       err = ceph_mount(client, mnt, path);
+       err = ceph_mount(fsc, mnt, path);
        if (err < 0)
                goto out_splat;
        dout("root %p inode %p ino %llx.%llx\n", mnt->mnt_root,
@@ -1029,12 +835,13 @@ static int ceph_get_sb(struct file_system_type *fs_type,
        return 0;
 
 out_splat:
-       ceph_mdsc_close_sessions(&client->mdsc);
+       ceph_mdsc_close_sessions(fsc->mdsc);
        deactivate_locked_super(sb);
        goto out_final;
 
 out:
-       ceph_destroy_client(client);
+       ceph_mdsc_destroy(fsc);
+       destroy_fs_client(fsc);
 out_final:
        dout("ceph_get_sb fail %d\n", err);
        return err;
@@ -1042,11 +849,12 @@ out_final:
 
 static void ceph_kill_sb(struct super_block *s)
 {
-       struct ceph_client *client = ceph_sb_to_client(s);
+       struct ceph_fs_client *fsc = ceph_sb_to_client(s);
        dout("kill_sb %p\n", s);
-       ceph_mdsc_pre_umount(&client->mdsc);
+       ceph_mdsc_pre_umount(fsc->mdsc);
        kill_anon_super(s);    /* will call put_super after sb is r/o */
-       ceph_destroy_client(client);
+       ceph_mdsc_destroy(fsc);
+       destroy_fs_client(fsc);
 }
 
 static struct file_system_type ceph_fs_type = {
@@ -1062,36 +870,20 @@ static struct file_system_type ceph_fs_type = {
 
 static int __init init_ceph(void)
 {
-       int ret = 0;
-
-       ret = ceph_debugfs_init();
-       if (ret < 0)
-               goto out;
-
-       ret = ceph_msgr_init();
-       if (ret < 0)
-               goto out_debugfs;
-
-       ret = init_caches();
+       int ret = init_caches();
        if (ret)
-               goto out_msgr;
+               goto out;
 
        ret = register_filesystem(&ceph_fs_type);
        if (ret)
                goto out_icache;
 
-       pr_info("loaded (mon/mds/osd proto %d/%d/%d, osdmap %d/%d %d/%d)\n",
-               CEPH_MONC_PROTOCOL, CEPH_MDSC_PROTOCOL, CEPH_OSDC_PROTOCOL,
-               CEPH_OSDMAP_VERSION, CEPH_OSDMAP_VERSION_EXT,
-               CEPH_OSDMAP_INC_VERSION, CEPH_OSDMAP_INC_VERSION_EXT);
+       pr_info("loaded (mds proto %d)\n", CEPH_MDSC_PROTOCOL);
+
        return 0;
 
 out_icache:
        destroy_caches();
-out_msgr:
-       ceph_msgr_exit();
-out_debugfs:
-       ceph_debugfs_cleanup();
 out:
        return ret;
 }
@@ -1101,8 +893,6 @@ static void __exit exit_ceph(void)
        dout("exit_ceph\n");
        unregister_filesystem(&ceph_fs_type);
        destroy_caches();
-       ceph_msgr_exit();
-       ceph_debugfs_cleanup();
 }
 
 module_init(init_ceph);
index b87638e84c4bc266e9b325f12e7fb98fc78e8986..1886294e12f7a3106c00f3376d92e43330514081 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef _FS_CEPH_SUPER_H
 #define _FS_CEPH_SUPER_H
 
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <asm/unaligned.h>
 #include <linux/backing-dev.h>
 #include <linux/writeback.h>
 #include <linux/slab.h>
 
-#include "types.h"
-#include "messenger.h"
-#include "msgpool.h"
-#include "mon_client.h"
-#include "mds_client.h"
-#include "osd_client.h"
-#include "ceph_fs.h"
+#include <linux/ceph/libceph.h>
 
 /* f_type in struct statfs */
 #define CEPH_SUPER_MAGIC 0x00c36400
 #define CEPH_BLOCK_SHIFT   20  /* 1 MB */
 #define CEPH_BLOCK         (1 << CEPH_BLOCK_SHIFT)
 
-/*
- * Supported features
- */
-#define CEPH_FEATURE_SUPPORTED CEPH_FEATURE_NOSRCADDR | CEPH_FEATURE_FLOCK
-#define CEPH_FEATURE_REQUIRED  CEPH_FEATURE_NOSRCADDR
+#define CEPH_MOUNT_OPT_DIRSTAT         (1<<4) /* `cat dirname` for stats */
+#define CEPH_MOUNT_OPT_RBYTES          (1<<5) /* dir st_bytes = rbytes */
+#define CEPH_MOUNT_OPT_NOASYNCREADDIR  (1<<7) /* no dcache readdir */
 
-/*
- * mount options
- */
-#define CEPH_OPT_FSID             (1<<0)
-#define CEPH_OPT_NOSHARE          (1<<1) /* don't share client with other sbs */
-#define CEPH_OPT_MYIP             (1<<2) /* specified my ip */
-#define CEPH_OPT_DIRSTAT          (1<<4) /* funky `cat dirname` for stats */
-#define CEPH_OPT_RBYTES           (1<<5) /* dir st_bytes = rbytes */
-#define CEPH_OPT_NOCRC            (1<<6) /* no data crc on writes */
-#define CEPH_OPT_NOASYNCREADDIR   (1<<7) /* no dcache readdir */
+#define CEPH_MOUNT_OPT_DEFAULT    (CEPH_MOUNT_OPT_RBYTES)
 
-#define CEPH_OPT_DEFAULT   (CEPH_OPT_RBYTES)
+#define ceph_set_mount_opt(fsc, opt) \
+       (fsc)->mount_options->flags |= CEPH_MOUNT_OPT_##opt;
+#define ceph_test_mount_opt(fsc, opt) \
+       (!!((fsc)->mount_options->flags & CEPH_MOUNT_OPT_##opt))
 
-#define ceph_set_opt(client, opt) \
-       (client)->mount_args->flags |= CEPH_OPT_##opt;
-#define ceph_test_opt(client, opt) \
-       (!!((client)->mount_args->flags & CEPH_OPT_##opt))
+#define CEPH_MAX_READDIR_DEFAULT        1024
+#define CEPH_MAX_READDIR_BYTES_DEFAULT  (512*1024)
+#define CEPH_SNAPDIRNAME_DEFAULT        ".snap"
 
-
-struct ceph_mount_args {
-       int sb_flags;
+struct ceph_mount_options {
        int flags;
-       struct ceph_fsid fsid;
-       struct ceph_entity_addr my_addr;
-       int num_mon;
-       struct ceph_entity_addr *mon_addr;
-       int mount_timeout;
-       int osd_idle_ttl;
-       int osd_timeout;
-       int osd_keepalive_timeout;
+       int sb_flags;
+
        int wsize;
        int rsize;            /* max readahead */
        int congestion_kb;    /* max writeback in flight */
@@ -73,82 +50,25 @@ struct ceph_mount_args {
        int cap_release_safety;
        int max_readdir;       /* max readdir result (entires) */
        int max_readdir_bytes; /* max readdir result (bytes) */
-       char *snapdir_name;   /* default ".snap" */
-       char *name;
-       char *secret;
-};
 
-/*
- * defaults
- */
-#define CEPH_MOUNT_TIMEOUT_DEFAULT  60
-#define CEPH_OSD_TIMEOUT_DEFAULT    60  /* seconds */
-#define CEPH_OSD_KEEPALIVE_DEFAULT  5
-#define CEPH_OSD_IDLE_TTL_DEFAULT    60
-#define CEPH_MOUNT_RSIZE_DEFAULT    (512*1024) /* readahead */
-#define CEPH_MAX_READDIR_DEFAULT    1024
-#define CEPH_MAX_READDIR_BYTES_DEFAULT    (512*1024)
-
-#define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024)
-#define CEPH_MSG_MAX_DATA_LEN  (16*1024*1024)
-
-#define CEPH_SNAPDIRNAME_DEFAULT ".snap"
-#define CEPH_AUTH_NAME_DEFAULT   "guest"
-/*
- * Delay telling the MDS we no longer want caps, in case we reopen
- * the file.  Delay a minimum amount of time, even if we send a cap
- * message for some other reason.  Otherwise, take the oppotunity to
- * update the mds to avoid sending another message later.
- */
-#define CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT      5  /* cap release delay */
-#define CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT     60  /* cap release delay */
-
-#define CEPH_CAP_RELEASE_SAFETY_DEFAULT        (CEPH_CAPS_PER_RELEASE * 4)
-
-/* mount state */
-enum {
-       CEPH_MOUNT_MOUNTING,
-       CEPH_MOUNT_MOUNTED,
-       CEPH_MOUNT_UNMOUNTING,
-       CEPH_MOUNT_UNMOUNTED,
-       CEPH_MOUNT_SHUTDOWN,
-};
-
-/*
- * subtract jiffies
- */
-static inline unsigned long time_sub(unsigned long a, unsigned long b)
-{
-       BUG_ON(time_after(b, a));
-       return (long)a - (long)b;
-}
-
-/*
- * per-filesystem client state
- *
- * possibly shared by multiple mount points, if they are
- * mounting the same ceph filesystem/cluster.
- */
-struct ceph_client {
-       struct ceph_fsid fsid;
-       bool have_fsid;
+       /*
+        * everything above this point can be memcmp'd; everything below
+        * is handled in compare_mount_options()
+        */
 
-       struct mutex mount_mutex;       /* serialize mount attempts */
-       struct ceph_mount_args *mount_args;
+       char *snapdir_name;   /* default ".snap" */
+};
 
+struct ceph_fs_client {
        struct super_block *sb;
 
-       unsigned long mount_state;
-       wait_queue_head_t auth_wq;
-
-       int auth_err;
+       struct ceph_mount_options *mount_options;
+       struct ceph_client *client;
 
+       unsigned long mount_state;
        int min_caps;                  /* min caps i added */
 
-       struct ceph_messenger *msgr;   /* messenger instance */
-       struct ceph_mon_client monc;
-       struct ceph_mds_client mdsc;
-       struct ceph_osd_client osdc;
+       struct ceph_mds_client *mdsc;
 
        /* writeback */
        mempool_t *wb_pagevec_pool;
@@ -160,14 +80,14 @@ struct ceph_client {
        struct backing_dev_info backing_dev_info;
 
 #ifdef CONFIG_DEBUG_FS
-       struct dentry *debugfs_monmap;
-       struct dentry *debugfs_mdsmap, *debugfs_osdmap;
-       struct dentry *debugfs_dir, *debugfs_dentry_lru, *debugfs_caps;
+       struct dentry *debugfs_dentry_lru, *debugfs_caps;
        struct dentry *debugfs_congestion_kb;
        struct dentry *debugfs_bdi;
+       struct dentry *debugfs_mdsc, *debugfs_mdsmap;
 #endif
 };
 
+
 /*
  * File i/o capability.  This tracks shared state with the metadata
  * server that allows us to cache or writeback attributes or to read
@@ -275,6 +195,20 @@ struct ceph_inode_xattr {
        int should_free_val;
 };
 
+/*
+ * Ceph dentry state
+ */
+struct ceph_dentry_info {
+       struct ceph_mds_session *lease_session;
+       u32 lease_gen, lease_shared_gen;
+       u32 lease_seq;
+       unsigned long lease_renew_after, lease_renew_from;
+       struct list_head lru;
+       struct dentry *dentry;
+       u64 time;
+       u64 offset;
+};
+
 struct ceph_inode_xattrs_info {
        /*
         * (still encoded) xattr blob. we avoid the overhead of parsing
@@ -296,11 +230,6 @@ struct ceph_inode_xattrs_info {
 /*
  * Ceph inode.
  */
-#define CEPH_I_COMPLETE  1  /* we have complete directory cached */
-#define CEPH_I_NODELAY   4  /* do not delay cap release */
-#define CEPH_I_FLUSH     8  /* do not delay flush of dirty metadata */
-#define CEPH_I_NOFLUSH  16  /* do not flush dirty caps */
-
 struct ceph_inode_info {
        struct ceph_vino i_vino;   /* ceph ino + snap */
 
@@ -391,6 +320,63 @@ static inline struct ceph_inode_info *ceph_inode(struct inode *inode)
        return container_of(inode, struct ceph_inode_info, vfs_inode);
 }
 
+static inline struct ceph_vino ceph_vino(struct inode *inode)
+{
+       return ceph_inode(inode)->i_vino;
+}
+
+/*
+ * ino_t is <64 bits on many architectures, blech.
+ *
+ * don't include snap in ino hash, at least for now.
+ */
+static inline ino_t ceph_vino_to_ino(struct ceph_vino vino)
+{
+       ino_t ino = (ino_t)vino.ino;  /* ^ (vino.snap << 20); */
+#if BITS_PER_LONG == 32
+       ino ^= vino.ino >> (sizeof(u64)-sizeof(ino_t)) * 8;
+       if (!ino)
+               ino = 1;
+#endif
+       return ino;
+}
+
+/* for printf-style formatting */
+#define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap
+
+static inline u64 ceph_ino(struct inode *inode)
+{
+       return ceph_inode(inode)->i_vino.ino;
+}
+static inline u64 ceph_snap(struct inode *inode)
+{
+       return ceph_inode(inode)->i_vino.snap;
+}
+
+static inline int ceph_ino_compare(struct inode *inode, void *data)
+{
+       struct ceph_vino *pvino = (struct ceph_vino *)data;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       return ci->i_vino.ino == pvino->ino &&
+               ci->i_vino.snap == pvino->snap;
+}
+
+static inline struct inode *ceph_find_inode(struct super_block *sb,
+                                           struct ceph_vino vino)
+{
+       ino_t t = ceph_vino_to_ino(vino);
+       return ilookup5(sb, t, ceph_ino_compare, &vino);
+}
+
+
+/*
+ * Ceph inode.
+ */
+#define CEPH_I_COMPLETE  1  /* we have complete directory cached */
+#define CEPH_I_NODELAY   4  /* do not delay cap release */
+#define CEPH_I_FLUSH     8  /* do not delay flush of dirty metadata */
+#define CEPH_I_NOFLUSH  16  /* do not flush dirty caps */
+
 static inline void ceph_i_clear(struct inode *inode, unsigned mask)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
@@ -414,8 +400,9 @@ static inline bool ceph_i_test(struct inode *inode, unsigned mask)
        struct ceph_inode_info *ci = ceph_inode(inode);
        bool r;
 
-       smp_mb();
+       spin_lock(&inode->i_lock);
        r = (ci->i_ceph_flags & mask) == mask;
+       spin_unlock(&inode->i_lock);
        return r;
 }
 
@@ -432,20 +419,6 @@ extern u32 ceph_choose_frag(struct ceph_inode_info *ci, u32 v,
                            struct ceph_inode_frag *pfrag,
                            int *found);
 
-/*
- * Ceph dentry state
- */
-struct ceph_dentry_info {
-       struct ceph_mds_session *lease_session;
-       u32 lease_gen, lease_shared_gen;
-       u32 lease_seq;
-       unsigned long lease_renew_after, lease_renew_from;
-       struct list_head lru;
-       struct dentry *dentry;
-       u64 time;
-       u64 offset;
-};
-
 static inline struct ceph_dentry_info *ceph_dentry(struct dentry *dentry)
 {
        return (struct ceph_dentry_info *)dentry->d_fsdata;
@@ -456,22 +429,6 @@ static inline loff_t ceph_make_fpos(unsigned frag, unsigned off)
        return ((loff_t)frag << 32) | (loff_t)off;
 }
 
-/*
- * ino_t is <64 bits on many architectures, blech.
- *
- * don't include snap in ino hash, at least for now.
- */
-static inline ino_t ceph_vino_to_ino(struct ceph_vino vino)
-{
-       ino_t ino = (ino_t)vino.ino;  /* ^ (vino.snap << 20); */
-#if BITS_PER_LONG == 32
-       ino ^= vino.ino >> (sizeof(u64)-sizeof(ino_t)) * 8;
-       if (!ino)
-               ino = 1;
-#endif
-       return ino;
-}
-
 static inline int ceph_set_ino_cb(struct inode *inode, void *data)
 {
        ceph_inode(inode)->i_vino = *(struct ceph_vino *)data;
@@ -479,39 +436,6 @@ static inline int ceph_set_ino_cb(struct inode *inode, void *data)
        return 0;
 }
 
-static inline struct ceph_vino ceph_vino(struct inode *inode)
-{
-       return ceph_inode(inode)->i_vino;
-}
-
-/* for printf-style formatting */
-#define ceph_vinop(i) ceph_inode(i)->i_vino.ino, ceph_inode(i)->i_vino.snap
-
-static inline u64 ceph_ino(struct inode *inode)
-{
-       return ceph_inode(inode)->i_vino.ino;
-}
-static inline u64 ceph_snap(struct inode *inode)
-{
-       return ceph_inode(inode)->i_vino.snap;
-}
-
-static inline int ceph_ino_compare(struct inode *inode, void *data)
-{
-       struct ceph_vino *pvino = (struct ceph_vino *)data;
-       struct ceph_inode_info *ci = ceph_inode(inode);
-       return ci->i_vino.ino == pvino->ino &&
-               ci->i_vino.snap == pvino->snap;
-}
-
-static inline struct inode *ceph_find_inode(struct super_block *sb,
-                                           struct ceph_vino vino)
-{
-       ino_t t = ceph_vino_to_ino(vino);
-       return ilookup5(sb, t, ceph_ino_compare, &vino);
-}
-
-
 /*
  * caps helpers
  */
@@ -576,18 +500,18 @@ extern int ceph_reserve_caps(struct ceph_mds_client *mdsc,
                             struct ceph_cap_reservation *ctx, int need);
 extern int ceph_unreserve_caps(struct ceph_mds_client *mdsc,
                               struct ceph_cap_reservation *ctx);
-extern void ceph_reservation_status(struct ceph_client *client,
+extern void ceph_reservation_status(struct ceph_fs_client *client,
                                    int *total, int *avail, int *used,
                                    int *reserved, int *min);
 
-static inline struct ceph_client *ceph_inode_to_client(struct inode *inode)
+static inline struct ceph_fs_client *ceph_inode_to_client(struct inode *inode)
 {
-       return (struct ceph_client *)inode->i_sb->s_fs_info;
+       return (struct ceph_fs_client *)inode->i_sb->s_fs_info;
 }
 
-static inline struct ceph_client *ceph_sb_to_client(struct super_block *sb)
+static inline struct ceph_fs_client *ceph_sb_to_client(struct super_block *sb)
 {
-       return (struct ceph_client *)sb->s_fs_info;
+       return (struct ceph_fs_client *)sb->s_fs_info;
 }
 
 
@@ -616,51 +540,6 @@ struct ceph_file_info {
 
 
 
-/*
- * snapshots
- */
-
-/*
- * A "snap context" is the set of existing snapshots when we
- * write data.  It is used by the OSD to guide its COW behavior.
- *
- * The ceph_snap_context is refcounted, and attached to each dirty
- * page, indicating which context the dirty data belonged when it was
- * dirtied.
- */
-struct ceph_snap_context {
-       atomic_t nref;
-       u64 seq;
-       int num_snaps;
-       u64 snaps[];
-};
-
-static inline struct ceph_snap_context *
-ceph_get_snap_context(struct ceph_snap_context *sc)
-{
-       /*
-       printk("get_snap_context %p %d -> %d\n", sc, atomic_read(&sc->nref),
-              atomic_read(&sc->nref)+1);
-       */
-       if (sc)
-               atomic_inc(&sc->nref);
-       return sc;
-}
-
-static inline void ceph_put_snap_context(struct ceph_snap_context *sc)
-{
-       if (!sc)
-               return;
-       /*
-       printk("put_snap_context %p %d -> %d\n", sc, atomic_read(&sc->nref),
-              atomic_read(&sc->nref)-1);
-       */
-       if (atomic_dec_and_test(&sc->nref)) {
-               /*printk(" deleting snap_context %p\n", sc);*/
-               kfree(sc);
-       }
-}
-
 /*
  * A "snap realm" describes a subset of the file hierarchy sharing
  * the same set of snapshots that apply to it.  The realms themselves
@@ -699,16 +578,33 @@ struct ceph_snap_realm {
        spinlock_t inodes_with_caps_lock;
 };
 
-
-
-/*
- * calculate the number of pages a given length and offset map onto,
- * if we align the data.
- */
-static inline int calc_pages_for(u64 off, u64 len)
+static inline int default_congestion_kb(void)
 {
-       return ((off+len+PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT) -
-               (off >> PAGE_CACHE_SHIFT);
+       int congestion_kb;
+
+       /*
+        * Copied from NFS
+        *
+        * congestion size, scale with available memory.
+        *
+        *  64MB:    8192k
+        * 128MB:   11585k
+        * 256MB:   16384k
+        * 512MB:   23170k
+        *   1GB:   32768k
+        *   2GB:   46340k
+        *   4GB:   65536k
+        *   8GB:   92681k
+        *  16GB:  131072k
+        *
+        * This allows larger machines to have larger/more transfers.
+        * Limit the default to 256M
+        */
+       congestion_kb = (16*int_sqrt(totalram_pages)) << (PAGE_SHIFT-10);
+       if (congestion_kb > 256*1024)
+               congestion_kb = 256*1024;
+
+       return congestion_kb;
 }
 
 
@@ -741,16 +637,6 @@ static inline bool __ceph_have_pending_cap_snap(struct ceph_inode_info *ci)
                           ci_item)->writing;
 }
 
-
-/* super.c */
-extern struct kmem_cache *ceph_inode_cachep;
-extern struct kmem_cache *ceph_cap_cachep;
-extern struct kmem_cache *ceph_dentry_cachep;
-extern struct kmem_cache *ceph_file_cachep;
-
-extern const char *ceph_msg_type_name(int type);
-extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid);
-
 /* inode.c */
 extern const struct inode_operations ceph_file_iops;
 
@@ -857,12 +743,18 @@ extern int ceph_mmap(struct file *file, struct vm_area_struct *vma);
 /* file.c */
 extern const struct file_operations ceph_file_fops;
 extern const struct address_space_operations ceph_aops;
+extern int ceph_copy_to_page_vector(struct page **pages,
+                                   const char *data,
+                                   loff_t off, size_t len);
+extern int ceph_copy_from_page_vector(struct page **pages,
+                                   char *data,
+                                   loff_t off, size_t len);
+extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
 extern int ceph_open(struct inode *inode, struct file *file);
 extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
                                       struct nameidata *nd, int mode,
                                       int locked_dir);
 extern int ceph_release(struct inode *inode, struct file *filp);
-extern void ceph_release_page_vector(struct page **pages, int num_pages);
 
 /* dir.c */
 extern const struct file_operations ceph_dir_fops;
@@ -892,12 +784,6 @@ extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 /* export.c */
 extern const struct export_operations ceph_export_ops;
 
-/* debugfs.c */
-extern int ceph_debugfs_init(void);
-extern void ceph_debugfs_cleanup(void);
-extern int ceph_debugfs_client_init(struct ceph_client *client);
-extern void ceph_debugfs_client_cleanup(struct ceph_client *client);
-
 /* locks.c */
 extern int ceph_lock(struct file *file, int cmd, struct file_lock *fl);
 extern int ceph_flock(struct file *file, int cmd, struct file_lock *fl);
@@ -914,4 +800,8 @@ static inline struct inode *get_dentry_parent_inode(struct dentry *dentry)
        return NULL;
 }
 
+/* debugfs.c */
+extern int ceph_fs_debugfs_init(struct ceph_fs_client *client);
+extern void ceph_fs_debugfs_cleanup(struct ceph_fs_client *client);
+
 #endif /* _FS_CEPH_SUPER_H */
index 9578af610b73fb48b69872ddeed222e58c8340f0..6e12a6ba5f79daabc1bc455a3a4db464b240c00a 100644 (file)
@@ -1,6 +1,9 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
+
 #include "super.h"
-#include "decode.h"
+#include "mds_client.h"
+
+#include <linux/ceph/decode.h>
 
 #include <linux/xattr.h>
 #include <linux/slab.h>
@@ -620,12 +623,12 @@ out:
 static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
                              const char *value, size_t size, int flags)
 {
-       struct ceph_client *client = ceph_sb_to_client(dentry->d_sb);
+       struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
        struct inode *inode = dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct inode *parent_inode = dentry->d_parent->d_inode;
        struct ceph_mds_request *req;
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        int err;
        int i, nr_pages;
        struct page **pages = NULL;
@@ -713,10 +716,9 @@ int ceph_setxattr(struct dentry *dentry, const char *name,
 
        /* preallocate memory for xattr name, value, index node */
        err = -ENOMEM;
-       newname = kmalloc(name_len + 1, GFP_NOFS);
+       newname = kmemdup(name, name_len + 1, GFP_NOFS);
        if (!newname)
                goto out;
-       memcpy(newname, name, name_len + 1);
 
        if (val_len) {
                newval = kmalloc(val_len + 1, GFP_NOFS);
@@ -777,8 +779,8 @@ out:
 
 static int ceph_send_removexattr(struct dentry *dentry, const char *name)
 {
-       struct ceph_client *client = ceph_sb_to_client(dentry->d_sb);
-       struct ceph_mds_client *mdsc = &client->mdsc;
+       struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
        struct inode *inode = dentry->d_inode;
        struct inode *parent_inode = dentry->d_parent->d_inode;
        struct ceph_mds_request *req;
index 5dbf4dba03c4d99240edd76de5e9a0a2bba4bd04..a367dd04428070cde6fbf7c70bbd64754ce498db 100644 (file)
@@ -1849,8 +1849,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
 
-       if (le32_to_cpu(es->s_blocks_count) >
-                   (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+       if (generic_check_addressable(sb->s_blocksize_bits,
+                                     le32_to_cpu(es->s_blocks_count))) {
                ext3_msg(sb, KERN_ERR,
                        "error: filesystem is too large to mount safely");
                if (sizeof(sector_t) < 8)
index 26147746c272c2112b7067aa6415800434586b50..7f47c366bf1576fbbdf3cbe6441fc04afd9ca198 100644 (file)
@@ -2831,15 +2831,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
         * Test whether we have more sectors than will fit in sector_t,
         * and whether the max offset is addressable by the page cache.
         */
-       if ((ext4_blocks_count(es) >
-            (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) ||
-           (ext4_blocks_count(es) >
-            (pgoff_t)(~0ULL) >> (PAGE_CACHE_SHIFT - sb->s_blocksize_bits))) {
+       ret = generic_check_addressable(sb->s_blocksize_bits,
+                                       ext4_blocks_count(es));
+       if (ret) {
                ext4_msg(sb, KERN_ERR, "filesystem"
                         " too large to mount safely on this system");
                if (sizeof(sector_t) < 8)
                        ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled");
-               ret = -EFBIG;
                goto failed_mount;
        }
 
index cc9665522148a730b010953596cc24edefc00ed6..c465ae066c62c6392ee22047d2be0ec650b89c98 100644 (file)
@@ -1,6 +1,6 @@
 config GFS2_FS
        tristate "GFS2 file system support"
-       depends on EXPERIMENTAL && (64BIT || LBDAF)
+       depends on (64BIT || LBDAF)
        select DLM if GFS2_FS_LOCKING_DLM
        select CONFIGFS_FS if GFS2_FS_LOCKING_DLM
        select SYSFS if GFS2_FS_LOCKING_DLM
index 194fe16d8418a332a274a74769b15277ff2d6858..6b24afb96aaedade304b48bb427e664eae8e6e53 100644 (file)
@@ -36,8 +36,8 @@
 #include "glops.h"
 
 
-static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
-                                  unsigned int from, unsigned int to)
+void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
+                           unsigned int from, unsigned int to)
 {
        struct buffer_head *head = page_buffers(page);
        unsigned int bsize = head->b_size;
@@ -615,7 +615,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
        unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
        int alloc_required;
        int error = 0;
-       struct gfs2_alloc *al;
+       struct gfs2_alloc *al = NULL;
        pgoff_t index = pos >> PAGE_CACHE_SHIFT;
        unsigned from = pos & (PAGE_CACHE_SIZE - 1);
        unsigned to = from + len;
@@ -663,6 +663,8 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
                rblocks += RES_STATFS + RES_QUOTA;
        if (&ip->i_inode == sdp->sd_rindex)
                rblocks += 2 * RES_STATFS;
+       if (alloc_required)
+               rblocks += gfs2_rg_blocks(al);
 
        error = gfs2_trans_begin(sdp, rblocks,
                                 PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
@@ -696,13 +698,11 @@ out:
 
        page_cache_release(page);
 
-       /*
-        * XXX(truncate): the call below should probably be replaced with
-        * a call to the gfs2-specific truncate blocks helper to actually
-        * release disk blocks..
-        */
+       gfs2_trans_end(sdp);
        if (pos + len > ip->i_inode.i_size)
-               truncate_setsize(&ip->i_inode, ip->i_inode.i_size);
+               gfs2_trim_blocks(&ip->i_inode);
+       goto out_trans_fail;
+
 out_endtrans:
        gfs2_trans_end(sdp);
 out_trans_fail:
@@ -802,10 +802,8 @@ static int gfs2_stuffed_write_end(struct inode *inode, struct buffer_head *dibh,
        page_cache_release(page);
 
        if (copied) {
-               if (inode->i_size < to) {
+               if (inode->i_size < to)
                        i_size_write(inode, to);
-                       ip->i_disksize = inode->i_size;
-               }
                gfs2_dinode_out(ip, di);
                mark_inode_dirty(inode);
        }
@@ -876,8 +874,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
 
        ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
        if (ret > 0) {
-               if (inode->i_size > ip->i_disksize)
-                       ip->i_disksize = inode->i_size;
                gfs2_dinode_out(ip, dibh->b_data);
                mark_inode_dirty(inode);
        }
index 6f482809d1a35b4787e9cb62357958d532aeaa30..5476c066d4ee336733445eda2f804561179ecb41 100644 (file)
@@ -50,7 +50,7 @@ struct strip_mine {
  * @ip: the inode
  * @dibh: the dinode buffer
  * @block: the block number that was allocated
- * @private: any locked page held by the caller process
+ * @page: The (optional) page. This is looked up if @page is NULL
  *
  * Returns: errno
  */
@@ -109,8 +109,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
 /**
  * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big
  * @ip: The GFS2 inode to unstuff
- * @unstuffer: the routine that handles unstuffing a non-zero length file
- * @private: private data for the unstuffer
+ * @page: The (optional) page. This is looked up if the @page is NULL
  *
  * This routine unstuffs a dinode and returns it to a "normal" state such
  * that the height can be grown in the traditional way.
@@ -132,7 +131,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
        if (error)
                goto out;
 
-       if (ip->i_disksize) {
+       if (i_size_read(&ip->i_inode)) {
                /* Get a free block, fill it with the stuffed data,
                   and write it out to disk */
 
@@ -161,7 +160,7 @@ int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
        di = (struct gfs2_dinode *)dibh->b_data;
        gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
 
-       if (ip->i_disksize) {
+       if (i_size_read(&ip->i_inode)) {
                *(__be64 *)(di + 1) = cpu_to_be64(block);
                gfs2_add_inode_blocks(&ip->i_inode, 1);
                di->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode));
@@ -884,84 +883,15 @@ out:
        return error;
 }
 
-/**
- * do_grow - Make a file look bigger than it is
- * @ip: the inode
- * @size: the size to set the file to
- *
- * Called with an exclusive lock on @ip.
- *
- * Returns: errno
- */
-
-static int do_grow(struct gfs2_inode *ip, u64 size)
-{
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_alloc *al;
-       struct buffer_head *dibh;
-       int error;
-
-       al = gfs2_alloc_get(ip);
-       if (!al)
-               return -ENOMEM;
-
-       error = gfs2_quota_lock_check(ip);
-       if (error)
-               goto out;
-
-       al->al_requested = sdp->sd_max_height + RES_DATA;
-
-       error = gfs2_inplace_reserve(ip);
-       if (error)
-               goto out_gunlock_q;
-
-       error = gfs2_trans_begin(sdp,
-                       sdp->sd_max_height + al->al_rgd->rd_length +
-                       RES_JDATA + RES_DINODE + RES_STATFS + RES_QUOTA, 0);
-       if (error)
-               goto out_ipres;
-
-       error = gfs2_meta_inode_buffer(ip, &dibh);
-       if (error)
-               goto out_end_trans;
-
-       if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
-               if (gfs2_is_stuffed(ip)) {
-                       error = gfs2_unstuff_dinode(ip, NULL);
-                       if (error)
-                               goto out_brelse;
-               }
-       }
-
-       ip->i_disksize = size;
-       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
-       gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-       gfs2_dinode_out(ip, dibh->b_data);
-
-out_brelse:
-       brelse(dibh);
-out_end_trans:
-       gfs2_trans_end(sdp);
-out_ipres:
-       gfs2_inplace_release(ip);
-out_gunlock_q:
-       gfs2_quota_unlock(ip);
-out:
-       gfs2_alloc_put(ip);
-       return error;
-}
-
-
 /**
  * gfs2_block_truncate_page - Deal with zeroing out data for truncate
  *
  * This is partly borrowed from ext3.
  */
-static int gfs2_block_truncate_page(struct address_space *mapping)
+static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from)
 {
        struct inode *inode = mapping->host;
        struct gfs2_inode *ip = GFS2_I(inode);
-       loff_t from = inode->i_size;
        unsigned long index = from >> PAGE_CACHE_SHIFT;
        unsigned offset = from & (PAGE_CACHE_SIZE-1);
        unsigned blocksize, iblock, length, pos;
@@ -1023,9 +953,11 @@ unlock:
        return err;
 }
 
-static int trunc_start(struct gfs2_inode *ip, u64 size)
+static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
 {
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       struct address_space *mapping = inode->i_mapping;
        struct buffer_head *dibh;
        int journaled = gfs2_is_jdata(ip);
        int error;
@@ -1039,31 +971,26 @@ static int trunc_start(struct gfs2_inode *ip, u64 size)
        if (error)
                goto out;
 
+       gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+
        if (gfs2_is_stuffed(ip)) {
-               u64 dsize = size + sizeof(struct gfs2_dinode);
-               ip->i_disksize = size;
-               ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
-               gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-               gfs2_dinode_out(ip, dibh->b_data);
-               if (dsize > dibh->b_size)
-                       dsize = dibh->b_size;
-               gfs2_buffer_clear_tail(dibh, dsize);
-               error = 1;
+               gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + newsize);
        } else {
-               if (size & (u64)(sdp->sd_sb.sb_bsize - 1))
-                       error = gfs2_block_truncate_page(ip->i_inode.i_mapping);
-
-               if (!error) {
-                       ip->i_disksize = size;
-                       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
-                       ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG;
-                       gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-                       gfs2_dinode_out(ip, dibh->b_data);
+               if (newsize & (u64)(sdp->sd_sb.sb_bsize - 1)) {
+                       error = gfs2_block_truncate_page(mapping, newsize);
+                       if (error)
+                               goto out_brelse;
                }
+               ip->i_diskflags |= GFS2_DIF_TRUNC_IN_PROG;
        }
 
-       brelse(dibh);
+       i_size_write(inode, newsize);
+       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
+       gfs2_dinode_out(ip, dibh->b_data);
 
+       truncate_pagecache(inode, oldsize, newsize);
+out_brelse:
+       brelse(dibh);
 out:
        gfs2_trans_end(sdp);
        return error;
@@ -1123,7 +1050,7 @@ static int trunc_end(struct gfs2_inode *ip)
        if (error)
                goto out;
 
-       if (!ip->i_disksize) {
+       if (!i_size_read(&ip->i_inode)) {
                ip->i_height = 0;
                ip->i_goal = ip->i_no_addr;
                gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
@@ -1143,92 +1070,154 @@ out:
 
 /**
  * do_shrink - make a file smaller
- * @ip: the inode
- * @size: the size to make the file
- * @truncator: function to truncate the last partial block
+ * @inode: the inode
+ * @oldsize: the current inode size
+ * @newsize: the size to make the file
  *
- * Called with an exclusive lock on @ip.
+ * Called with an exclusive lock on @inode. The @size must
+ * be equal to or smaller than the current inode size.
  *
  * Returns: errno
  */
 
-static int do_shrink(struct gfs2_inode *ip, u64 size)
+static int do_shrink(struct inode *inode, u64 oldsize, u64 newsize)
 {
+       struct gfs2_inode *ip = GFS2_I(inode);
        int error;
 
-       error = trunc_start(ip, size);
+       error = trunc_start(inode, oldsize, newsize);
        if (error < 0)
                return error;
-       if (error > 0)
+       if (gfs2_is_stuffed(ip))
                return 0;
 
-       error = trunc_dealloc(ip, size);
-       if (!error)
+       error = trunc_dealloc(ip, newsize);
+       if (error == 0)
                error = trunc_end(ip);
 
        return error;
 }
 
-static int do_touch(struct gfs2_inode *ip, u64 size)
+void gfs2_trim_blocks(struct inode *inode)
 {
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       u64 size = inode->i_size;
+       int ret;
+
+       ret = do_shrink(inode, size, size);
+       WARN_ON(ret != 0);
+}
+
+/**
+ * do_grow - Touch and update inode size
+ * @inode: The inode
+ * @size: The new size
+ *
+ * This function updates the timestamps on the inode and
+ * may also increase the size of the inode. This function
+ * must not be called with @size any smaller than the current
+ * inode size.
+ *
+ * Although it is not strictly required to unstuff files here,
+ * earlier versions of GFS2 have a bug in the stuffed file reading
+ * code which will result in a buffer overrun if the size is larger
+ * than the max stuffed file size. In order to prevent this from
+ * occuring, such files are unstuffed, but in other cases we can
+ * just update the inode size directly.
+ *
+ * Returns: 0 on success, or -ve on error
+ */
+
+static int do_grow(struct inode *inode, u64 size)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct buffer_head *dibh;
+       struct gfs2_alloc *al = NULL;
        int error;
 
-       error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+       if (gfs2_is_stuffed(ip) &&
+           (size > (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)))) {
+               al = gfs2_alloc_get(ip);
+               if (al == NULL)
+                       return -ENOMEM;
+
+               error = gfs2_quota_lock_check(ip);
+               if (error)
+                       goto do_grow_alloc_put;
+
+               al->al_requested = 1;
+               error = gfs2_inplace_reserve(ip);
+               if (error)
+                       goto do_grow_qunlock;
+       }
+
+       error = gfs2_trans_begin(sdp, RES_DINODE + RES_STATFS + RES_RG_BIT, 0);
        if (error)
-               return error;
+               goto do_grow_release;
 
-       down_write(&ip->i_rw_mutex);
+       if (al) {
+               error = gfs2_unstuff_dinode(ip, NULL);
+               if (error)
+                       goto do_end_trans;
+       }
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (error)
-               goto do_touch_out;
+               goto do_end_trans;
 
+       i_size_write(inode, size);
        ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        gfs2_dinode_out(ip, dibh->b_data);
        brelse(dibh);
 
-do_touch_out:
-       up_write(&ip->i_rw_mutex);
+do_end_trans:
        gfs2_trans_end(sdp);
+do_grow_release:
+       if (al) {
+               gfs2_inplace_release(ip);
+do_grow_qunlock:
+               gfs2_quota_unlock(ip);
+do_grow_alloc_put:
+               gfs2_alloc_put(ip);
+       }
        return error;
 }
 
 /**
- * gfs2_truncatei - make a file a given size
- * @ip: the inode
- * @size: the size to make the file
- * @truncator: function to truncate the last partial block
+ * gfs2_setattr_size - make a file a given size
+ * @inode: the inode
+ * @newsize: the size to make the file
  *
- * The file size can grow, shrink, or stay the same size.
+ * The file size can grow, shrink, or stay the same size. This
+ * is called holding i_mutex and an exclusive glock on the inode
+ * in question.
  *
  * Returns: errno
  */
 
-int gfs2_truncatei(struct gfs2_inode *ip, u64 size)
+int gfs2_setattr_size(struct inode *inode, u64 newsize)
 {
-       int error;
+       int ret;
+       u64 oldsize;
 
-       if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_inode.i_mode)))
-               return -EINVAL;
+       BUG_ON(!S_ISREG(inode->i_mode));
 
-       if (size > ip->i_disksize)
-               error = do_grow(ip, size);
-       else if (size < ip->i_disksize)
-               error = do_shrink(ip, size);
-       else
-               /* update time stamps */
-               error = do_touch(ip, size);
+       ret = inode_newsize_ok(inode, newsize);
+       if (ret)
+               return ret;
 
-       return error;
+       oldsize = inode->i_size;
+       if (newsize >= oldsize)
+               return do_grow(inode, newsize);
+
+       return do_shrink(inode, oldsize, newsize);
 }
 
 int gfs2_truncatei_resume(struct gfs2_inode *ip)
 {
        int error;
-       error = trunc_dealloc(ip, ip->i_disksize);
+       error = trunc_dealloc(ip, i_size_read(&ip->i_inode));
        if (!error)
                error = trunc_end(ip);
        return error;
@@ -1269,7 +1258,7 @@ int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
 
        shift = sdp->sd_sb.sb_bsize_shift;
        BUG_ON(gfs2_is_dir(ip));
-       end_of_file = (ip->i_disksize + sdp->sd_sb.sb_bsize - 1) >> shift;
+       end_of_file = (i_size_read(&ip->i_inode) + sdp->sd_sb.sb_bsize - 1) >> shift;
        lblock = offset >> shift;
        lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
        if (lblock_stop > end_of_file)
index a20a5213135a50ae9293da676eb533e9c04063db..42fea03e2bd962b6674747967ac00499009d923f 100644 (file)
@@ -44,14 +44,16 @@ static inline void gfs2_write_calc_reserv(const struct gfs2_inode *ip,
        }
 }
 
-int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
-int gfs2_block_map(struct inode *inode, sector_t lblock, struct buffer_head *bh, int create);
-int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);
-
-int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
-int gfs2_truncatei_resume(struct gfs2_inode *ip);
-int gfs2_file_dealloc(struct gfs2_inode *ip);
-int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
-                             unsigned int len);
+extern int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
+extern int gfs2_block_map(struct inode *inode, sector_t lblock,
+                         struct buffer_head *bh, int create);
+extern int gfs2_extent_map(struct inode *inode, u64 lblock, int *new,
+                          u64 *dblock, unsigned *extlen);
+extern int gfs2_setattr_size(struct inode *inode, u64 size);
+extern void gfs2_trim_blocks(struct inode *inode);
+extern int gfs2_truncatei_resume(struct gfs2_inode *ip);
+extern int gfs2_file_dealloc(struct gfs2_inode *ip);
+extern int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
+                                    unsigned int len);
 
 #endif /* __BMAP_DOT_H__ */
index bb7907bde3d81b63b6ae5b198283a52db36e97b0..6798755b3858685b611da5e439393bcffb332563 100644 (file)
@@ -49,7 +49,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
                ip = GFS2_I(inode);
        }
 
-       if (sdp->sd_args.ar_localcaching)
+       if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
                goto valid;
 
        had_lock = (gfs2_glock_is_locked_by_me(dip->i_gl) != NULL);
index b9dd88a78dd47073e3af1645a1e0fa3bcb94d1bb..5c356d09c321c10133afc7cf93aba2eddd1cb3c1 100644 (file)
@@ -79,6 +79,9 @@
 #define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1)
 #define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1))
 
+struct qstr gfs2_qdot __read_mostly;
+struct qstr gfs2_qdotdot __read_mostly;
+
 typedef int (*leaf_call_t) (struct gfs2_inode *dip, u32 index, u32 len,
                            u64 leaf_no, void *data);
 typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent,
@@ -127,8 +130,8 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf,
 
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size);
-       if (ip->i_disksize < offset + size)
-               ip->i_disksize = offset + size;
+       if (ip->i_inode.i_size < offset + size)
+               i_size_write(&ip->i_inode, offset + size);
        ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
        gfs2_dinode_out(ip, dibh->b_data);
 
@@ -225,8 +228,8 @@ out:
        if (error)
                return error;
 
-       if (ip->i_disksize < offset + copied)
-               ip->i_disksize = offset + copied;
+       if (ip->i_inode.i_size < offset + copied)
+               i_size_write(&ip->i_inode, offset + copied);
        ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME;
 
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
@@ -275,12 +278,13 @@ static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
        unsigned int o;
        int copied = 0;
        int error = 0;
+       u64 disksize = i_size_read(&ip->i_inode);
 
-       if (offset >= ip->i_disksize)
+       if (offset >= disksize)
                return 0;
 
-       if (offset + size > ip->i_disksize)
-               size = ip->i_disksize - offset;
+       if (offset + size > disksize)
+               size = disksize - offset;
 
        if (!size)
                return 0;
@@ -727,7 +731,7 @@ static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode,
                unsigned hsize = 1 << ip->i_depth;
                unsigned index;
                u64 ln;
-               if (hsize * sizeof(u64) != ip->i_disksize) {
+               if (hsize * sizeof(u64) != i_size_read(inode)) {
                        gfs2_consist_inode(ip);
                        return ERR_PTR(-EIO);
                }
@@ -879,7 +883,7 @@ static int dir_make_exhash(struct inode *inode)
        for (x = sdp->sd_hash_ptrs; x--; lp++)
                *lp = cpu_to_be64(bn);
 
-       dip->i_disksize = sdp->sd_sb.sb_bsize / 2;
+       i_size_write(inode, sdp->sd_sb.sb_bsize / 2);
        gfs2_add_inode_blocks(&dip->i_inode, 1);
        dip->i_diskflags |= GFS2_DIF_EXHASH;
 
@@ -1057,11 +1061,12 @@ static int dir_double_exhash(struct gfs2_inode *dip)
        u64 *buf;
        u64 *from, *to;
        u64 block;
+       u64 disksize = i_size_read(&dip->i_inode);
        int x;
        int error = 0;
 
        hsize = 1 << dip->i_depth;
-       if (hsize * sizeof(u64) != dip->i_disksize) {
+       if (hsize * sizeof(u64) != disksize) {
                gfs2_consist_inode(dip);
                return -EIO;
        }
@@ -1072,7 +1077,7 @@ static int dir_double_exhash(struct gfs2_inode *dip)
        if (!buf)
                return -ENOMEM;
 
-       for (block = dip->i_disksize >> sdp->sd_hash_bsize_shift; block--;) {
+       for (block = disksize >> sdp->sd_hash_bsize_shift; block--;) {
                error = gfs2_dir_read_data(dip, (char *)buf,
                                            block * sdp->sd_hash_bsize,
                                            sdp->sd_hash_bsize, 1);
@@ -1370,7 +1375,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
        unsigned depth = 0;
 
        hsize = 1 << dip->i_depth;
-       if (hsize * sizeof(u64) != dip->i_disksize) {
+       if (hsize * sizeof(u64) != i_size_read(inode)) {
                gfs2_consist_inode(dip);
                return -EIO;
        }
@@ -1784,7 +1789,7 @@ static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data)
        int error = 0;
 
        hsize = 1 << dip->i_depth;
-       if (hsize * sizeof(u64) != dip->i_disksize) {
+       if (hsize * sizeof(u64) != i_size_read(&dip->i_inode)) {
                gfs2_consist_inode(dip);
                return -EIO;
        }
index 4f919440c3be3e20ed49c2acb742db6758096bea..a98f644bd3df33596cf2382767b89ca0cdd08161 100644 (file)
@@ -17,23 +17,24 @@ struct inode;
 struct gfs2_inode;
 struct gfs2_inum;
 
-struct inode *gfs2_dir_search(struct inode *dir, const struct qstr *filename);
-int gfs2_dir_check(struct inode *dir, const struct qstr *filename,
-                  const struct gfs2_inode *ip);
-int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
-                const struct gfs2_inode *ip, unsigned int type);
-int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename);
-int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
-                 filldir_t filldir);
-int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
-                  const struct gfs2_inode *nip, unsigned int new_type);
+extern struct inode *gfs2_dir_search(struct inode *dir,
+                                    const struct qstr *filename);
+extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename,
+                         const struct gfs2_inode *ip);
+extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
+                       const struct gfs2_inode *ip, unsigned int type);
+extern int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename);
+extern int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
+                        filldir_t filldir);
+extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
+                         const struct gfs2_inode *nip, unsigned int new_type);
 
-int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip);
+extern int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip);
 
-int gfs2_diradd_alloc_required(struct inode *dir,
-                              const struct qstr *filename);
-int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
-                           struct buffer_head **bhp);
+extern int gfs2_diradd_alloc_required(struct inode *dir,
+                                     const struct qstr *filename);
+extern int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
+                                  struct buffer_head **bhp);
 
 static inline u32 gfs2_disk_hash(const char *data, int len)
 {
@@ -61,4 +62,7 @@ static inline void gfs2_qstr2dirent(const struct qstr *name, u16 reclen, struct
        memcpy(dent + 1, name->name, name->len);
 }
 
+extern struct qstr gfs2_qdot;
+extern struct qstr gfs2_qdotdot;
+
 #endif /* __DIR_DOT_H__ */
index dfe237a3f8ad9e2a0f11bae403ff1f1d8687cbd0..06d582732d3427a058864d03ca6cb667c5063481 100644 (file)
@@ -126,16 +126,9 @@ static int gfs2_get_name(struct dentry *parent, char *name,
 
 static struct dentry *gfs2_get_parent(struct dentry *child)
 {
-       struct qstr dotdot;
        struct dentry *dentry;
 
-       /*
-        * XXX(hch): it would be a good idea to keep this around as a
-        *           static variable.
-        */
-       gfs2_str2qstr(&dotdot, "..");
-
-       dentry = d_obtain_alias(gfs2_lookupi(child->d_inode, &dotdot, 1));
+       dentry = d_obtain_alias(gfs2_lookupi(child->d_inode, &gfs2_qdotdot, 1));
        if (!IS_ERR(dentry))
                dentry->d_op = &gfs2_dops;
        return dentry;
index 4edd662c8232b2c24d1f1767b937f258071f8211..237ee6a940df23ab0720ed99252657611d0be7ec 100644 (file)
@@ -382,8 +382,10 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        rblocks = RES_DINODE + ind_blocks;
        if (gfs2_is_jdata(ip))
                rblocks += data_blocks ? data_blocks : 1;
-       if (ind_blocks || data_blocks)
+       if (ind_blocks || data_blocks) {
                rblocks += RES_STATFS + RES_QUOTA;
+               rblocks += gfs2_rg_blocks(al);
+       }
        ret = gfs2_trans_begin(sdp, rblocks, 0);
        if (ret)
                goto out_trans_fail;
@@ -491,7 +493,7 @@ static int gfs2_open(struct inode *inode, struct file *file)
                        goto fail;
 
                if (!(file->f_flags & O_LARGEFILE) &&
-                   ip->i_disksize > MAX_NON_LFS) {
+                   i_size_read(inode) > MAX_NON_LFS) {
                        error = -EOVERFLOW;
                        goto fail_gunlock;
                }
index 9adf8f924e08991c32d12938702e570f163c3215..87778857f0994fa504224d93c7c5611d10bc1e8c 100644 (file)
@@ -441,6 +441,8 @@ static void state_change(struct gfs2_glock *gl, unsigned int new_state)
                else
                        gfs2_glock_put_nolock(gl);
        }
+       if (held1 && held2 && list_empty(&gl->gl_holders))
+               clear_bit(GLF_QUEUED, &gl->gl_flags);
 
        gl->gl_state = new_state;
        gl->gl_tchange = jiffies;
@@ -1012,6 +1014,7 @@ fail:
                if (unlikely((gh->gh_flags & LM_FLAG_PRIORITY) && !insert_pt))
                        insert_pt = &gh2->gh_list;
        }
+       set_bit(GLF_QUEUED, &gl->gl_flags);
        if (likely(insert_pt == NULL)) {
                list_add_tail(&gh->gh_list, &gl->gl_holders);
                if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY))
@@ -1310,10 +1313,12 @@ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
 
        gfs2_glock_hold(gl);
        holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time;
-       if (time_before(now, holdtime))
-               delay = holdtime - now;
-       if (test_bit(GLF_REPLY_PENDING, &gl->gl_flags))
-               delay = gl->gl_ops->go_min_hold_time;
+       if (test_bit(GLF_QUEUED, &gl->gl_flags)) {
+               if (time_before(now, holdtime))
+                       delay = holdtime - now;
+               if (test_bit(GLF_REPLY_PENDING, &gl->gl_flags))
+                       delay = gl->gl_ops->go_min_hold_time;
+       }
 
        spin_lock(&gl->gl_spin);
        handle_callback(gl, state, delay);
@@ -1512,7 +1517,7 @@ static void clear_glock(struct gfs2_glock *gl)
        spin_unlock(&lru_lock);
 
        spin_lock(&gl->gl_spin);
-       if (find_first_holder(gl) == NULL && gl->gl_state != LM_ST_UNLOCKED)
+       if (gl->gl_state != LM_ST_UNLOCKED)
                handle_callback(gl, LM_ST_UNLOCKED, 0);
        spin_unlock(&gl->gl_spin);
        gfs2_glock_hold(gl);
@@ -1660,6 +1665,8 @@ static const char *gflags2str(char *buf, const unsigned long *gflags)
                *p++ = 'I';
        if (test_bit(GLF_FROZEN, gflags))
                *p++ = 'F';
+       if (test_bit(GLF_QUEUED, gflags))
+               *p++ = 'q';
        *p = 0;
        return buf;
 }
@@ -1776,10 +1783,12 @@ int __init gfs2_glock_init(void)
        }
 #endif
 
-       glock_workqueue = create_workqueue("glock_workqueue");
+       glock_workqueue = alloc_workqueue("glock_workqueue", WQ_RESCUER |
+                                         WQ_HIGHPRI | WQ_FREEZEABLE, 0);
        if (IS_ERR(glock_workqueue))
                return PTR_ERR(glock_workqueue);
-       gfs2_delete_workqueue = create_workqueue("delete_workqueue");
+       gfs2_delete_workqueue = alloc_workqueue("delete_workqueue", WQ_RESCUER |
+                                               WQ_FREEZEABLE, 0);
        if (IS_ERR(gfs2_delete_workqueue)) {
                destroy_workqueue(glock_workqueue);
                return PTR_ERR(gfs2_delete_workqueue);
index 2bda1911b1563347b52d4d2da7892768d93bd947..db1c26d6d2206c8f9e9b68396380ed8791f3c720 100644 (file)
@@ -215,7 +215,7 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs);
 void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...);
 
 /**
- * gfs2_glock_nq_init - intialize a holder and enqueue it on a glock
+ * gfs2_glock_nq_init - initialize a holder and enqueue it on a glock
  * @gl: the glock
  * @state: the state we're requesting
  * @flags: the modifier flags
index 49f97d3bb690c512cb0f338d85938e622d501a49..0d149dcc04e515adfaaeb632a6677e5e3b555f45 100644 (file)
@@ -262,13 +262,12 @@ static int inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
        const struct gfs2_inode *ip = gl->gl_object;
        if (ip == NULL)
                return 0;
-       gfs2_print_dbg(seq, " I: n:%llu/%llu t:%u f:0x%02lx d:0x%08x s:%llu/%llu\n",
+       gfs2_print_dbg(seq, " I: n:%llu/%llu t:%u f:0x%02lx d:0x%08x s:%llu\n",
                  (unsigned long long)ip->i_no_formal_ino,
                  (unsigned long long)ip->i_no_addr,
                  IF2DT(ip->i_inode.i_mode), ip->i_flags,
                  (unsigned int)ip->i_diskflags,
-                 (unsigned long long)ip->i_inode.i_size,
-                 (unsigned long long)ip->i_disksize);
+                 (unsigned long long)i_size_read(&ip->i_inode));
        return 0;
 }
 
@@ -453,7 +452,6 @@ const struct gfs2_glock_operations *gfs2_glops_list[] = {
        [LM_TYPE_META] = &gfs2_meta_glops,
        [LM_TYPE_INODE] = &gfs2_inode_glops,
        [LM_TYPE_RGRP] = &gfs2_rgrp_glops,
-       [LM_TYPE_NONDISK] = &gfs2_trans_glops,
        [LM_TYPE_IOPEN] = &gfs2_iopen_glops,
        [LM_TYPE_FLOCK] = &gfs2_flock_glops,
        [LM_TYPE_NONDISK] = &gfs2_nondisk_glops,
index fdbf4b366fa540d295dcbd73b298099b50418f8c..764fbb49efc8e3adbdeda7f83f178b0fd6ea70f8 100644 (file)
@@ -196,6 +196,7 @@ enum {
        GLF_REPLY_PENDING               = 9,
        GLF_INITIAL                     = 10,
        GLF_FROZEN                      = 11,
+       GLF_QUEUED                      = 12,
 };
 
 struct gfs2_glock {
@@ -267,7 +268,6 @@ struct gfs2_inode {
        u64 i_no_formal_ino;
        u64 i_generation;
        u64 i_eattr;
-       loff_t i_disksize;
        unsigned long i_flags;          /* GIF_... */
        struct gfs2_glock *i_gl; /* Move into i_gh? */
        struct gfs2_holder i_iopen_gh;
@@ -416,11 +416,8 @@ struct gfs2_args {
        char ar_locktable[GFS2_LOCKNAME_LEN];   /* Name of the Lock Table */
        char ar_hostdata[GFS2_LOCKNAME_LEN];    /* Host specific data */
        unsigned int ar_spectator:1;            /* Don't get a journal */
-       unsigned int ar_ignore_local_fs:1;      /* Ignore optimisations */
        unsigned int ar_localflocks:1;          /* Let the VFS do flock|fcntl */
-       unsigned int ar_localcaching:1;         /* Local caching */
        unsigned int ar_debug:1;                /* Oops on errors */
-       unsigned int ar_upgrade:1;              /* Upgrade ondisk format */
        unsigned int ar_posix_acl:1;            /* Enable posix acls */
        unsigned int ar_quota:2;                /* off/account/on */
        unsigned int ar_suiddir:1;              /* suiddir support */
@@ -497,7 +494,7 @@ struct gfs2_sb_host {
  */
 
 struct lm_lockstruct {
-       unsigned int ls_jid;
+       int ls_jid;
        unsigned int ls_first;
        unsigned int ls_first_done;
        unsigned int ls_nodir;
@@ -572,6 +569,7 @@ struct gfs2_sbd {
        struct list_head sd_rindex_mru_list;
        struct gfs2_rgrpd *sd_rindex_forward;
        unsigned int sd_rgrps;
+       unsigned int sd_max_rg_data;
 
        /* Journal index stuff */
 
index 08140f185a3792153e23bab24f03ac3107d04757..06370f8bd8cf4aafa95fd4df64e93ec8d657328d 100644 (file)
@@ -359,8 +359,7 @@ static int gfs2_dinode_in(struct gfs2_inode *ip, const void *buf)
         * to do that.
         */
        ip->i_inode.i_nlink = be32_to_cpu(str->di_nlink);
-       ip->i_disksize = be64_to_cpu(str->di_size);
-       i_size_write(&ip->i_inode, ip->i_disksize);
+       i_size_write(&ip->i_inode, be64_to_cpu(str->di_size));
        gfs2_set_inode_blocks(&ip->i_inode, be64_to_cpu(str->di_blocks));
        atime.tv_sec = be64_to_cpu(str->di_atime);
        atime.tv_nsec = be32_to_cpu(str->di_atime_nsec);
@@ -1055,7 +1054,7 @@ void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf)
        str->di_uid = cpu_to_be32(ip->i_inode.i_uid);
        str->di_gid = cpu_to_be32(ip->i_inode.i_gid);
        str->di_nlink = cpu_to_be32(ip->i_inode.i_nlink);
-       str->di_size = cpu_to_be64(ip->i_disksize);
+       str->di_size = cpu_to_be64(i_size_read(&ip->i_inode));
        str->di_blocks = cpu_to_be64(gfs2_get_inode_blocks(&ip->i_inode));
        str->di_atime = cpu_to_be64(ip->i_inode.i_atime.tv_sec);
        str->di_mtime = cpu_to_be64(ip->i_inode.i_mtime.tv_sec);
@@ -1085,8 +1084,8 @@ void gfs2_dinode_print(const struct gfs2_inode *ip)
               (unsigned long long)ip->i_no_formal_ino);
        printk(KERN_INFO "  no_addr = %llu\n",
               (unsigned long long)ip->i_no_addr);
-       printk(KERN_INFO "  i_disksize = %llu\n",
-              (unsigned long long)ip->i_disksize);
+       printk(KERN_INFO "  i_size = %llu\n",
+              (unsigned long long)i_size_read(&ip->i_inode));
        printk(KERN_INFO "  blocks = %llu\n",
               (unsigned long long)gfs2_get_inode_blocks(&ip->i_inode));
        printk(KERN_INFO "  i_goal = %llu\n",
index 300ada3f21de0cf5fc22677283343a76caf8200e..6720d7d5fbc6aac91083b399b95ba6c978922c67 100644 (file)
@@ -19,6 +19,8 @@ extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
 extern int gfs2_internal_read(struct gfs2_inode *ip,
                              struct file_ra_state *ra_state,
                              char *buf, loff_t *pos, unsigned size);
+extern void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
+                                  unsigned int from, unsigned int to);
 extern void gfs2_set_aops(struct inode *inode);
 
 static inline int gfs2_is_stuffed(const struct gfs2_inode *ip)
@@ -80,6 +82,19 @@ static inline void gfs2_inum_out(const struct gfs2_inode *ip,
        dent->de_inum.no_addr = cpu_to_be64(ip->i_no_addr);
 }
 
+static inline int gfs2_check_internal_file_size(struct inode *inode,
+                                               u64 minsize, u64 maxsize)
+{
+       u64 size = i_size_read(inode);
+       if (size < minsize || size > maxsize)
+               goto err;
+       if (size & ((1 << inode->i_blkbits) - 1))
+               goto err;
+       return 0;
+err:
+       gfs2_consist_inode(GFS2_I(inode));
+       return -EIO;
+}
 
 extern void gfs2_set_iop(struct inode *inode);
 extern struct inode *gfs2_inode_lookup(struct super_block *sb, unsigned type, 
index 0e0470ed34c273a341aed5860191bfadf42b41e5..1c09425b45fd728ba52c1f5f49c3feac187640a2 100644 (file)
@@ -42,9 +42,9 @@ static void gdlm_ast(void *arg)
                ret |= LM_OUT_CANCELED;
                goto out;
        case -EAGAIN: /* Try lock fails */
+       case -EDEADLK: /* Deadlock detected */
                goto out;
-       case -EINVAL: /* Invalid */
-       case -ENOMEM: /* Out of memory */
+       case -ETIMEDOUT: /* Canceled due to timeout */
                ret |= LM_OUT_ERROR;
                goto out;
        case 0: /* Success */
index b1e9630eb46a8d0338fef57ffa15caf23ab1cf0f..d7eb1e209aa899561f7168a6d2964460ae73a89f 100644 (file)
@@ -24,6 +24,7 @@
 #include "glock.h"
 #include "quota.h"
 #include "recovery.h"
+#include "dir.h"
 
 static struct shrinker qd_shrinker = {
        .shrink = gfs2_shrink_qd_memory,
@@ -78,6 +79,9 @@ static int __init init_gfs2_fs(void)
 {
        int error;
 
+       gfs2_str2qstr(&gfs2_qdot, ".");
+       gfs2_str2qstr(&gfs2_qdotdot, "..");
+
        error = gfs2_sys_init();
        if (error)
                return error;
@@ -140,7 +144,7 @@ static int __init init_gfs2_fs(void)
 
        error = -ENOMEM;
        gfs_recovery_wq = alloc_workqueue("gfs_recovery",
-                                         WQ_NON_REENTRANT | WQ_RESCUER, 0);
+                                         WQ_RESCUER | WQ_FREEZEABLE, 0);
        if (!gfs_recovery_wq)
                goto fail_wq;
 
index 4d4b1e8ac64c02ef64ffd216a71ec801e2fdb625..aeafc233dc897fdb102df29bf052fc040b61faef 100644 (file)
 #define DO 0
 #define UNDO 1
 
-static const u32 gfs2_old_fs_formats[] = {
-        0
-};
-
-static const u32 gfs2_old_multihost_formats[] = {
-        0
-};
-
 /**
  * gfs2_tune_init - Fill a gfs2_tune structure with default values
  * @gt: tune
@@ -135,8 +127,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
 
 static int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int silent)
 {
-       unsigned int x;
-
        if (sb->sb_magic != GFS2_MAGIC ||
            sb->sb_type != GFS2_METATYPE_SB) {
                if (!silent)
@@ -150,55 +140,9 @@ static int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb_host *sb, int sile
            sb->sb_multihost_format == GFS2_FORMAT_MULTI)
                return 0;
 
-       if (sb->sb_fs_format != GFS2_FORMAT_FS) {
-               for (x = 0; gfs2_old_fs_formats[x]; x++)
-                       if (gfs2_old_fs_formats[x] == sb->sb_fs_format)
-                               break;
+       fs_warn(sdp, "Unknown on-disk format, unable to mount\n");
 
-               if (!gfs2_old_fs_formats[x]) {
-                       printk(KERN_WARNING
-                              "GFS2: code version (%u, %u) is incompatible "
-                              "with ondisk format (%u, %u)\n",
-                              GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
-                              sb->sb_fs_format, sb->sb_multihost_format);
-                       printk(KERN_WARNING
-                              "GFS2: I don't know how to upgrade this FS\n");
-                       return -EINVAL;
-               }
-       }
-
-       if (sb->sb_multihost_format != GFS2_FORMAT_MULTI) {
-               for (x = 0; gfs2_old_multihost_formats[x]; x++)
-                       if (gfs2_old_multihost_formats[x] ==
-                           sb->sb_multihost_format)
-                               break;
-
-               if (!gfs2_old_multihost_formats[x]) {
-                       printk(KERN_WARNING
-                              "GFS2: code version (%u, %u) is incompatible "
-                              "with ondisk format (%u, %u)\n",
-                              GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
-                              sb->sb_fs_format, sb->sb_multihost_format);
-                       printk(KERN_WARNING
-                              "GFS2: I don't know how to upgrade this FS\n");
-                       return -EINVAL;
-               }
-       }
-
-       if (!sdp->sd_args.ar_upgrade) {
-               printk(KERN_WARNING
-                      "GFS2: code version (%u, %u) is incompatible "
-                      "with ondisk format (%u, %u)\n",
-                      GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
-                      sb->sb_fs_format, sb->sb_multihost_format);
-               printk(KERN_INFO
-                      "GFS2: Use the \"upgrade\" mount option to upgrade "
-                      "the FS\n");
-               printk(KERN_INFO "GFS2: See the manual for more details\n");
-               return -EINVAL;
-       }
-
-       return 0;
+       return -EINVAL;
 }
 
 static void end_bio_io_page(struct bio *bio, int error)
@@ -586,7 +530,7 @@ static int map_journal_extents(struct gfs2_sbd *sdp)
 
        prev_db = 0;
 
-       for (lb = 0; lb < ip->i_disksize >> sdp->sd_sb.sb_bsize_shift; lb++) {
+       for (lb = 0; lb < i_size_read(jd->jd_inode) >> sdp->sd_sb.sb_bsize_shift; lb++) {
                bh.b_state = 0;
                bh.b_blocknr = 0;
                bh.b_size = 1 << ip->i_inode.i_blkbits;
@@ -1022,7 +966,6 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
        if (!strcmp("lock_nolock", proto)) {
                lm = &nolock_ops;
                sdp->sd_args.ar_localflocks = 1;
-               sdp->sd_args.ar_localcaching = 1;
 #ifdef CONFIG_GFS2_FS_LOCKING_DLM
        } else if (!strcmp("lock_dlm", proto)) {
                lm = &gfs2_dlm_ops;
@@ -1113,8 +1056,6 @@ static int gfs2_journalid_wait(void *word)
 
 static int wait_on_journal(struct gfs2_sbd *sdp)
 {
-       if (sdp->sd_args.ar_spectator)
-               return 0;
        if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
                return 0;
 
@@ -1217,6 +1158,20 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
        if (error)
                goto fail_sb;
 
+       /*
+        * If user space has failed to join the cluster or some similar
+        * failure has occurred, then the journal id will contain a
+        * negative (error) number. This will then be returned to the
+        * caller (of the mount syscall). We do this even for spectator
+        * mounts (which just write a jid of 0 to indicate "ok" even though
+        * the jid is unused in the spectator case)
+        */
+       if (sdp->sd_lockstruct.ls_jid < 0) {
+               error = sdp->sd_lockstruct.ls_jid;
+               sdp->sd_lockstruct.ls_jid = 0;
+               goto fail_sb;
+       }
+
        error = init_inodes(sdp, DO);
        if (error)
                goto fail_sb;
index 1009be2c9737687cdee8b48668a5f5d09752abeb..0534510200d5961887d3ee957d799e3b4669e76b 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/gfs2_ondisk.h>
 #include <linux/crc32.h>
 #include <linux/fiemap.h>
+#include <linux/swap.h>
+#include <linux/falloc.h>
 #include <asm/uaccess.h>
 
 #include "gfs2.h"
@@ -217,7 +219,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
                        goto out_gunlock_q;
 
                error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-                                        al->al_rgd->rd_length +
+                                        gfs2_rg_blocks(al) +
                                         2 * RES_DINODE + RES_STATFS +
                                         RES_QUOTA, 0);
                if (error)
@@ -406,7 +408,6 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
 
        ip = ghs[1].gh_gl->gl_object;
 
-       ip->i_disksize = size;
        i_size_write(inode, size);
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
@@ -461,7 +462,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        ip = ghs[1].gh_gl->gl_object;
 
        ip->i_inode.i_nlink = 2;
-       ip->i_disksize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);
+       i_size_write(inode, sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode));
        ip->i_diskflags |= GFS2_DIF_JDATA;
        ip->i_entries = 2;
 
@@ -470,18 +471,15 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        if (!gfs2_assert_withdraw(sdp, !error)) {
                struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
                struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);
-               struct qstr str;
 
-               gfs2_str2qstr(&str, ".");
                gfs2_trans_add_bh(ip->i_gl, dibh, 1);
-               gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent);
+               gfs2_qstr2dirent(&gfs2_qdot, GFS2_DIRENT_SIZE(gfs2_qdot.len), dent);
                dent->de_inum = di->di_num; /* already GFS2 endian */
                dent->de_type = cpu_to_be16(DT_DIR);
                di->di_entries = cpu_to_be32(1);
 
-               gfs2_str2qstr(&str, "..");
                dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1));
-               gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);
+               gfs2_qstr2dirent(&gfs2_qdotdot, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);
 
                gfs2_inum_out(dip, dent);
                dent->de_type = cpu_to_be16(DT_DIR);
@@ -522,7 +520,6 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 static int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
                       struct gfs2_inode *ip)
 {
-       struct qstr dotname;
        int error;
 
        if (ip->i_entries != 2) {
@@ -539,13 +536,11 @@ static int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
        if (error)
                return error;
 
-       gfs2_str2qstr(&dotname, ".");
-       error = gfs2_dir_del(ip, &dotname);
+       error = gfs2_dir_del(ip, &gfs2_qdot);
        if (error)
                return error;
 
-       gfs2_str2qstr(&dotname, "..");
-       error = gfs2_dir_del(ip, &dotname);
+       error = gfs2_dir_del(ip, &gfs2_qdotdot);
        if (error)
                return error;
 
@@ -694,11 +689,8 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
        struct inode *dir = &to->i_inode;
        struct super_block *sb = dir->i_sb;
        struct inode *tmp;
-       struct qstr dotdot;
        int error = 0;
 
-       gfs2_str2qstr(&dotdot, "..");
-
        igrab(dir);
 
        for (;;) {
@@ -711,7 +703,7 @@ static int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
                        break;
                }
 
-               tmp = gfs2_lookupi(dir, &dotdot, 1);
+               tmp = gfs2_lookupi(dir, &gfs2_qdotdot, 1);
                if (IS_ERR(tmp)) {
                        error = PTR_ERR(tmp);
                        break;
@@ -744,7 +736,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
        struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
        struct gfs2_inode *nip = NULL;
        struct gfs2_sbd *sdp = GFS2_SB(odir);
-       struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, };
+       struct gfs2_holder ghs[5], r_gh = { .gh_gl = NULL, }, ri_gh;
        struct gfs2_rgrpd *nrgd;
        unsigned int num_gh;
        int dir_rename = 0;
@@ -758,6 +750,9 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
                        return 0;
        }
 
+       error = gfs2_rindex_hold(sdp, &ri_gh);
+       if (error)
+               return error;
 
        if (odip != ndip) {
                error = gfs2_glock_nq_init(sdp->sd_rename_gl, LM_ST_EXCLUSIVE,
@@ -887,12 +882,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
 
                al->al_requested = sdp->sd_max_dirres;
 
-               error = gfs2_inplace_reserve(ndip);
+               error = gfs2_inplace_reserve_ri(ndip);
                if (error)
                        goto out_gunlock_q;
 
                error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-                                        al->al_rgd->rd_length +
+                                        gfs2_rg_blocks(al) +
                                         4 * RES_DINODE + 4 * RES_LEAF +
                                         RES_STATFS + RES_QUOTA + 4, 0);
                if (error)
@@ -920,9 +915,6 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
        }
 
        if (dir_rename) {
-               struct qstr name;
-               gfs2_str2qstr(&name, "..");
-
                error = gfs2_change_nlink(ndip, +1);
                if (error)
                        goto out_end_trans;
@@ -930,7 +922,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
                if (error)
                        goto out_end_trans;
 
-               error = gfs2_dir_mvino(ip, &name, ndip, DT_DIR);
+               error = gfs2_dir_mvino(ip, &gfs2_qdotdot, ndip, DT_DIR);
                if (error)
                        goto out_end_trans;
        } else {
@@ -972,6 +964,7 @@ out_gunlock_r:
        if (r_gh.gh_gl)
                gfs2_glock_dq_uninit(&r_gh);
 out:
+       gfs2_glock_dq_uninit(&ri_gh);
        return error;
 }
 
@@ -990,7 +983,7 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
        struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
        struct gfs2_holder i_gh;
        struct buffer_head *dibh;
-       unsigned int x;
+       unsigned int x, size;
        char *buf;
        int error;
 
@@ -1002,7 +995,8 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
                return NULL;
        }
 
-       if (!ip->i_disksize) {
+       size = (unsigned int)i_size_read(&ip->i_inode);
+       if (size == 0) {
                gfs2_consist_inode(ip);
                buf = ERR_PTR(-EIO);
                goto out;
@@ -1014,7 +1008,7 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
                goto out;
        }
 
-       x = ip->i_disksize + 1;
+       x = size + 1;
        buf = kmalloc(x, GFP_NOFS);
        if (!buf)
                buf = ERR_PTR(-ENOMEM);
@@ -1071,30 +1065,6 @@ int gfs2_permission(struct inode *inode, int mask)
        return error;
 }
 
-/*
- * XXX(truncate): the truncate_setsize calls should be moved to the end.
- */
-static int setattr_size(struct inode *inode, struct iattr *attr)
-{
-       struct gfs2_inode *ip = GFS2_I(inode);
-       struct gfs2_sbd *sdp = GFS2_SB(inode);
-       int error;
-
-       if (attr->ia_size != ip->i_disksize) {
-               error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
-               if (error)
-                       return error;
-               truncate_setsize(inode, attr->ia_size);
-               gfs2_trans_end(sdp);
-       }
-
-       error = gfs2_truncatei(ip, attr->ia_size);
-       if (error && (inode->i_size != ip->i_disksize))
-               i_size_write(inode, ip->i_disksize);
-
-       return error;
-}
-
 static int setattr_chown(struct inode *inode, struct iattr *attr)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
@@ -1195,7 +1165,7 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
                goto out;
 
        if (attr->ia_valid & ATTR_SIZE)
-               error = setattr_size(inode, attr);
+               error = gfs2_setattr_size(inode, attr->ia_size);
        else if (attr->ia_valid & (ATTR_UID | ATTR_GID))
                error = setattr_chown(inode, attr);
        else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
@@ -1301,6 +1271,257 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name)
        return ret;
 }
 
+static void empty_write_end(struct page *page, unsigned from,
+                          unsigned to)
+{
+       struct gfs2_inode *ip = GFS2_I(page->mapping->host);
+
+       page_zero_new_buffers(page, from, to);
+       flush_dcache_page(page);
+       mark_page_accessed(page);
+
+       if (!gfs2_is_writeback(ip))
+               gfs2_page_add_databufs(ip, page, from, to);
+
+       block_commit_write(page, from, to);
+}
+
+
+static int write_empty_blocks(struct page *page, unsigned from, unsigned to)
+{
+       unsigned start, end, next;
+       struct buffer_head *bh, *head;
+       int error;
+
+       if (!page_has_buffers(page)) {
+               error = block_prepare_write(page, from, to, gfs2_block_map);
+               if (unlikely(error))
+                       return error;
+
+               empty_write_end(page, from, to);
+               return 0;
+       }
+
+       bh = head = page_buffers(page);
+       next = end = 0;
+       while (next < from) {
+               next += bh->b_size;
+               bh = bh->b_this_page;
+       }
+       start = next;
+       do {
+               next += bh->b_size;
+               if (buffer_mapped(bh)) {
+                       if (end) {
+                               error = block_prepare_write(page, start, end,
+                                                           gfs2_block_map);
+                               if (unlikely(error))
+                                       return error;
+                               empty_write_end(page, start, end);
+                               end = 0;
+                       }
+                       start = next;
+               }
+               else
+                       end = next;
+               bh = bh->b_this_page;
+       } while (next < to);
+
+       if (end) {
+               error = block_prepare_write(page, start, end, gfs2_block_map);
+               if (unlikely(error))
+                       return error;
+               empty_write_end(page, start, end);
+       }
+
+       return 0;
+}
+
+static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
+                          int mode)
+{
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct buffer_head *dibh;
+       int error;
+       u64 start = offset >> PAGE_CACHE_SHIFT;
+       unsigned int start_offset = offset & ~PAGE_CACHE_MASK;
+       u64 end = (offset + len - 1) >> PAGE_CACHE_SHIFT;
+       pgoff_t curr;
+       struct page *page;
+       unsigned int end_offset = (offset + len) & ~PAGE_CACHE_MASK;
+       unsigned int from, to;
+
+       if (!end_offset)
+               end_offset = PAGE_CACHE_SIZE;
+
+       error = gfs2_meta_inode_buffer(ip, &dibh);
+       if (unlikely(error))
+               goto out;
+
+       gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+
+       if (gfs2_is_stuffed(ip)) {
+               error = gfs2_unstuff_dinode(ip, NULL);
+               if (unlikely(error))
+                       goto out;
+       }
+
+       curr = start;
+       offset = start << PAGE_CACHE_SHIFT;
+       from = start_offset;
+       to = PAGE_CACHE_SIZE;
+       while (curr <= end) {
+               page = grab_cache_page_write_begin(inode->i_mapping, curr,
+                                                  AOP_FLAG_NOFS);
+               if (unlikely(!page)) {
+                       error = -ENOMEM;
+                       goto out;
+               }
+
+               if (curr == end)
+                       to = end_offset;
+               error = write_empty_blocks(page, from, to);
+               if (!error && offset + to > inode->i_size &&
+                   !(mode & FALLOC_FL_KEEP_SIZE)) {
+                       i_size_write(inode, offset + to);
+               }
+               unlock_page(page);
+               page_cache_release(page);
+               if (error)
+                       goto out;
+               curr++;
+               offset += PAGE_CACHE_SIZE;
+               from = 0;
+       }
+
+       gfs2_dinode_out(ip, dibh->b_data);
+       mark_inode_dirty(inode);
+
+       brelse(dibh);
+
+out:
+       return error;
+}
+
+static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len,
+                           unsigned int *data_blocks, unsigned int *ind_blocks)
+{
+       const struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+       unsigned int max_blocks = ip->i_alloc->al_rgd->rd_free_clone;
+       unsigned int tmp, max_data = max_blocks - 3 * (sdp->sd_max_height - 1);
+
+       for (tmp = max_data; tmp > sdp->sd_diptrs;) {
+               tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs);
+               max_data -= tmp;
+       }
+       /* This calculation isn't the exact reverse of gfs2_write_calc_reserve,
+          so it might end up with fewer data blocks */
+       if (max_data <= *data_blocks)
+               return;
+       *data_blocks = max_data;
+       *ind_blocks = max_blocks - max_data;
+       *len = ((loff_t)max_data - 3) << sdp->sd_sb.sb_bsize_shift;
+       if (*len > max) {
+               *len = max;
+               gfs2_write_calc_reserv(ip, max, data_blocks, ind_blocks);
+       }
+}
+
+static long gfs2_fallocate(struct inode *inode, int mode, loff_t offset,
+                          loff_t len)
+{
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       struct gfs2_inode *ip = GFS2_I(inode);
+       unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
+       loff_t bytes, max_bytes;
+       struct gfs2_alloc *al;
+       int error;
+       loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift;
+       next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
+
+       offset = (offset >> sdp->sd_sb.sb_bsize_shift) <<
+                sdp->sd_sb.sb_bsize_shift;
+
+       len = next - offset;
+       bytes = sdp->sd_max_rg_data * sdp->sd_sb.sb_bsize / 2;
+       if (!bytes)
+               bytes = UINT_MAX;
+
+       gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &ip->i_gh);
+       error = gfs2_glock_nq(&ip->i_gh);
+       if (unlikely(error))
+               goto out_uninit;
+
+       if (!gfs2_write_alloc_required(ip, offset, len))
+               goto out_unlock;
+
+       while (len > 0) {
+               if (len < bytes)
+                       bytes = len;
+               al = gfs2_alloc_get(ip);
+               if (!al) {
+                       error = -ENOMEM;
+                       goto out_unlock;
+               }
+
+               error = gfs2_quota_lock_check(ip);
+               if (error)
+                       goto out_alloc_put;
+
+retry:
+               gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks);
+
+               al->al_requested = data_blocks + ind_blocks;
+               error = gfs2_inplace_reserve(ip);
+               if (error) {
+                       if (error == -ENOSPC && bytes > sdp->sd_sb.sb_bsize) {
+                               bytes >>= 1;
+                               goto retry;
+                       }
+                       goto out_qunlock;
+               }
+               max_bytes = bytes;
+               calc_max_reserv(ip, len, &max_bytes, &data_blocks, &ind_blocks);
+               al->al_requested = data_blocks + ind_blocks;
+
+               rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
+                         RES_RG_HDR + gfs2_rg_blocks(al);
+               if (gfs2_is_jdata(ip))
+                       rblocks += data_blocks ? data_blocks : 1;
+
+               error = gfs2_trans_begin(sdp, rblocks,
+                                        PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
+               if (error)
+                       goto out_trans_fail;
+
+               error = fallocate_chunk(inode, offset, max_bytes, mode);
+               gfs2_trans_end(sdp);
+
+               if (error)
+                       goto out_trans_fail;
+
+               len -= max_bytes;
+               offset += max_bytes;
+               gfs2_inplace_release(ip);
+               gfs2_quota_unlock(ip);
+               gfs2_alloc_put(ip);
+       }
+       goto out_unlock;
+
+out_trans_fail:
+       gfs2_inplace_release(ip);
+out_qunlock:
+       gfs2_quota_unlock(ip);
+out_alloc_put:
+       gfs2_alloc_put(ip);
+out_unlock:
+       gfs2_glock_dq(&ip->i_gh);
+out_uninit:
+       gfs2_holder_uninit(&ip->i_gh);
+       return error;
+}
+
+
 static int gfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                       u64 start, u64 len)
 {
@@ -1351,6 +1572,7 @@ const struct inode_operations gfs2_file_iops = {
        .getxattr = gfs2_getxattr,
        .listxattr = gfs2_listxattr,
        .removexattr = gfs2_removexattr,
+       .fallocate = gfs2_fallocate,
        .fiemap = gfs2_fiemap,
 };
 
index 1bc6b5695e6dfb34870810b87bd09c819f25c93f..58a9b9998b42d0d9603c7a49ffc746ab4a22ef87 100644 (file)
@@ -735,10 +735,8 @@ get_a_page:
                goto out;
 
        size = loc + sizeof(struct gfs2_quota);
-       if (size > inode->i_size) {
-               ip->i_disksize = size;
+       if (size > inode->i_size)
                i_size_write(inode, size);
-       }
        inode->i_mtime = inode->i_atime = CURRENT_TIME;
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        gfs2_dinode_out(ip, dibh->b_data);
@@ -817,7 +815,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
                goto out_alloc;
 
        if (nalloc)
-               blocks += al->al_rgd->rd_length + nalloc * ind_blocks + RES_STATFS;
+               blocks += gfs2_rg_blocks(al) + nalloc * ind_blocks + RES_STATFS;
 
        error = gfs2_trans_begin(sdp, blocks, 0);
        if (error)
@@ -1190,18 +1188,17 @@ static void gfs2_quota_change_in(struct gfs2_quota_change_host *qc, const void *
 int gfs2_quota_init(struct gfs2_sbd *sdp)
 {
        struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
-       unsigned int blocks = ip->i_disksize >> sdp->sd_sb.sb_bsize_shift;
+       u64 size = i_size_read(sdp->sd_qc_inode);
+       unsigned int blocks = size >> sdp->sd_sb.sb_bsize_shift;
        unsigned int x, slot = 0;
        unsigned int found = 0;
        u64 dblock;
        u32 extlen = 0;
        int error;
 
-       if (!ip->i_disksize || ip->i_disksize > (64 << 20) ||
-           ip->i_disksize & (sdp->sd_sb.sb_bsize - 1)) {
-               gfs2_consist_inode(ip);
+       if (gfs2_check_internal_file_size(sdp->sd_qc_inode, 1, 64 << 20))
                return -EIO;
-       }
+
        sdp->sd_quota_slots = blocks * sdp->sd_qc_per_block;
        sdp->sd_quota_chunks = DIV_ROUND_UP(sdp->sd_quota_slots, 8 * PAGE_SIZE);
 
@@ -1589,6 +1586,7 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
                error = gfs2_inplace_reserve(ip);
                if (error)
                        goto out_alloc;
+               blocks += gfs2_rg_blocks(al);
        }
 
        error = gfs2_trans_begin(sdp, blocks + RES_DINODE + 1, 0);
index f7f89a94a5a4598a4b532016a0c16846a62cef2b..f2a02edcac8f43e9de1dd22fd4c72ac7347f39a5 100644 (file)
@@ -455,11 +455,13 @@ void gfs2_recover_func(struct work_struct *work)
        int ro = 0;
        unsigned int pass;
        int error;
+       int jlocked = 0;
 
-       if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) {
+       if (sdp->sd_args.ar_spectator ||
+           (jd->jd_jid != sdp->sd_lockstruct.ls_jid)) {
                fs_info(sdp, "jid=%u: Trying to acquire journal lock...\n",
                        jd->jd_jid);
-
+               jlocked = 1;
                /* Acquire the journal lock so we can do recovery */
 
                error = gfs2_glock_nq_num(sdp, jd->jd_jid, &gfs2_journal_glops,
@@ -554,13 +556,12 @@ void gfs2_recover_func(struct work_struct *work)
                        jd->jd_jid, t);
        }
 
-       if (jd->jd_jid != sdp->sd_lockstruct.ls_jid)
-               gfs2_glock_dq_uninit(&ji_gh);
-
        gfs2_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS);
 
-       if (jd->jd_jid != sdp->sd_lockstruct.ls_jid)
+       if (jlocked) {
+               gfs2_glock_dq_uninit(&ji_gh);
                gfs2_glock_dq_uninit(&j_gh);
+       }
 
        fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
        goto done;
@@ -568,7 +569,7 @@ void gfs2_recover_func(struct work_struct *work)
 fail_gunlock_tr:
        gfs2_glock_dq_uninit(&t_gh);
 fail_gunlock_ji:
-       if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) {
+       if (jlocked) {
                gfs2_glock_dq_uninit(&ji_gh);
 fail_gunlock_j:
                gfs2_glock_dq_uninit(&j_gh);
index 171a744f8e45d172f4e43eb793ae4e08dba8ba23..fb67f593f40856b213f03887642c44a3e4c7ccc5 100644 (file)
@@ -500,7 +500,7 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp)
        for (rgrps = 0;; rgrps++) {
                loff_t pos = rgrps * sizeof(struct gfs2_rindex);
 
-               if (pos + sizeof(struct gfs2_rindex) >= ip->i_disksize)
+               if (pos + sizeof(struct gfs2_rindex) >= i_size_read(inode))
                        break;
                error = gfs2_internal_read(ip, &ra_state, buf, &pos,
                                           sizeof(struct gfs2_rindex));
@@ -588,7 +588,9 @@ static int gfs2_ri_update(struct gfs2_inode *ip)
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct inode *inode = &ip->i_inode;
        struct file_ra_state ra_state;
-       u64 rgrp_count = ip->i_disksize;
+       u64 rgrp_count = i_size_read(inode);
+       struct gfs2_rgrpd *rgd;
+       unsigned int max_data = 0;
        int error;
 
        do_div(rgrp_count, sizeof(struct gfs2_rindex));
@@ -603,6 +605,10 @@ static int gfs2_ri_update(struct gfs2_inode *ip)
                }
        }
 
+       list_for_each_entry(rgd, &sdp->sd_rindex_list, rd_list)
+               if (rgd->rd_data > max_data)
+                       max_data = rgd->rd_data;
+       sdp->sd_max_rg_data = max_data;
        sdp->sd_rindex_uptodate = 1;
        return 0;
 }
@@ -622,13 +628,15 @@ static int gfs2_ri_update_special(struct gfs2_inode *ip)
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct inode *inode = &ip->i_inode;
        struct file_ra_state ra_state;
+       struct gfs2_rgrpd *rgd;
+       unsigned int max_data = 0;
        int error;
 
        file_ra_state_init(&ra_state, inode->i_mapping);
        for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) {
                /* Ignore partials */
                if ((sdp->sd_rgrps + 1) * sizeof(struct gfs2_rindex) >
-                   ip->i_disksize)
+                   i_size_read(inode))
                        break;
                error = read_rindex_entry(ip, &ra_state);
                if (error) {
@@ -636,6 +644,10 @@ static int gfs2_ri_update_special(struct gfs2_inode *ip)
                        return error;
                }
        }
+       list_for_each_entry(rgd, &sdp->sd_rindex_list, rd_list)
+               if (rgd->rd_data > max_data)
+                       max_data = rgd->rd_data;
+       sdp->sd_max_rg_data = max_data;
 
        sdp->sd_rindex_uptodate = 1;
        return 0;
@@ -1188,7 +1200,8 @@ out:
  * Returns: errno
  */
 
-int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
+int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
+                          char *file, unsigned int line)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct gfs2_alloc *al = ip->i_alloc;
@@ -1199,12 +1212,15 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
                return -EINVAL;
 
 try_again:
-       /* We need to hold the rindex unless the inode we're using is
-          the rindex itself, in which case it's already held. */
-       if (ip != GFS2_I(sdp->sd_rindex))
-               error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
-       else if (!sdp->sd_rgrps) /* We may not have the rindex read in, so: */
-               error = gfs2_ri_update_special(ip);
+       if (hold_rindex) {
+               /* We need to hold the rindex unless the inode we're using is
+                  the rindex itself, in which case it's already held. */
+               if (ip != GFS2_I(sdp->sd_rindex))
+                       error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
+               else if (!sdp->sd_rgrps) /* We may not have the rindex read
+                                           in, so: */
+                       error = gfs2_ri_update_special(ip);
+       }
 
        if (error)
                return error;
@@ -1215,7 +1231,7 @@ try_again:
           try to free it, and try the allocation again. */
        error = get_local_rgrp(ip, &unlinked, &last_unlinked);
        if (error) {
-               if (ip != GFS2_I(sdp->sd_rindex))
+               if (hold_rindex && ip != GFS2_I(sdp->sd_rindex))
                        gfs2_glock_dq_uninit(&al->al_ri_gh);
                if (error != -EAGAIN)
                        return error;
@@ -1257,7 +1273,7 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
        al->al_rgd = NULL;
        if (al->al_rgd_gh.gh_gl)
                gfs2_glock_dq_uninit(&al->al_rgd_gh);
-       if (ip != GFS2_I(sdp->sd_rindex))
+       if (ip != GFS2_I(sdp->sd_rindex) && al->al_ri_gh.gh_gl)
                gfs2_glock_dq_uninit(&al->al_ri_gh);
 }
 
@@ -1496,11 +1512,19 @@ int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n)
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct buffer_head *dibh;
        struct gfs2_alloc *al = ip->i_alloc;
-       struct gfs2_rgrpd *rgd = al->al_rgd;
+       struct gfs2_rgrpd *rgd;
        u32 goal, blk;
        u64 block;
        int error;
 
+       /* Only happens if there is a bug in gfs2, return something distinctive
+        * to ensure that it is noticed.
+        */
+       if (al == NULL)
+               return -ECANCELED;
+
+       rgd = al->al_rgd;
+
        if (rgrp_contains_block(rgd, ip->i_goal))
                goal = ip->i_goal - rgd->rd_data0;
        else
index f07119d89557855fc9a8673b32e9119cad921570..0e35c0466f9a6c5979a3fe8c339def323bc37fad 100644 (file)
@@ -39,10 +39,12 @@ static inline void gfs2_alloc_put(struct gfs2_inode *ip)
        ip->i_alloc = NULL;
 }
 
-extern int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file,
-                                 unsigned int line);
+extern int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex,
+                                 char *file, unsigned int line);
 #define gfs2_inplace_reserve(ip) \
-gfs2_inplace_reserve_i((ip), __FILE__, __LINE__)
+       gfs2_inplace_reserve_i((ip), 1, __FILE__, __LINE__)
+#define gfs2_inplace_reserve_ri(ip) \
+       gfs2_inplace_reserve_i((ip), 0, __FILE__, __LINE__)
 
 extern void gfs2_inplace_release(struct gfs2_inode *ip);
 
index 77cb9f830ee47eb51520bd8581ebc700b426455e..047d1176096c79d6f0ce50227b8c098755fb0150 100644 (file)
@@ -85,6 +85,7 @@ static const match_table_t tokens = {
        {Opt_locktable, "locktable=%s"},
        {Opt_hostdata, "hostdata=%s"},
        {Opt_spectator, "spectator"},
+       {Opt_spectator, "norecovery"},
        {Opt_ignore_local_fs, "ignore_local_fs"},
        {Opt_localflocks, "localflocks"},
        {Opt_localcaching, "localcaching"},
@@ -159,13 +160,13 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
                        args->ar_spectator = 1;
                        break;
                case Opt_ignore_local_fs:
-                       args->ar_ignore_local_fs = 1;
+                       /* Retained for backwards compat only */
                        break;
                case Opt_localflocks:
                        args->ar_localflocks = 1;
                        break;
                case Opt_localcaching:
-                       args->ar_localcaching = 1;
+                       /* Retained for backwards compat only */
                        break;
                case Opt_debug:
                        if (args->ar_errors == GFS2_ERRORS_PANIC) {
@@ -179,7 +180,7 @@ int gfs2_mount_args(struct gfs2_args *args, char *options)
                        args->ar_debug = 0;
                        break;
                case Opt_upgrade:
-                       args->ar_upgrade = 1;
+                       /* Retained for backwards compat only */
                        break;
                case Opt_acl:
                        args->ar_posix_acl = 1;
@@ -342,15 +343,14 @@ int gfs2_jdesc_check(struct gfs2_jdesc *jd)
 {
        struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
        struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+       u64 size = i_size_read(jd->jd_inode);
 
-       if (ip->i_disksize < (8 << 20) || ip->i_disksize > (1 << 30) ||
-           (ip->i_disksize & (sdp->sd_sb.sb_bsize - 1))) {
-               gfs2_consist_inode(ip);
+       if (gfs2_check_internal_file_size(jd->jd_inode, 8 << 20, 1 << 30))
                return -EIO;
-       }
-       jd->jd_blocks = ip->i_disksize >> sdp->sd_sb.sb_bsize_shift;
 
-       if (gfs2_write_alloc_required(ip, 0, ip->i_disksize)) {
+       jd->jd_blocks = size >> sdp->sd_sb.sb_bsize_shift;
+
+       if (gfs2_write_alloc_required(ip, 0, size)) {
                gfs2_consist_inode(ip);
                return -EIO;
        }
@@ -1129,9 +1129,7 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
 
        /* Some flags must not be changed */
        if (args_neq(&args, &sdp->sd_args, spectator) ||
-           args_neq(&args, &sdp->sd_args, ignore_local_fs) ||
            args_neq(&args, &sdp->sd_args, localflocks) ||
-           args_neq(&args, &sdp->sd_args, localcaching) ||
            args_neq(&args, &sdp->sd_args, meta))
                return -EINVAL;
 
@@ -1234,16 +1232,10 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
                seq_printf(s, ",hostdata=%s", args->ar_hostdata);
        if (args->ar_spectator)
                seq_printf(s, ",spectator");
-       if (args->ar_ignore_local_fs)
-               seq_printf(s, ",ignore_local_fs");
        if (args->ar_localflocks)
                seq_printf(s, ",localflocks");
-       if (args->ar_localcaching)
-               seq_printf(s, ",localcaching");
        if (args->ar_debug)
                seq_printf(s, ",debug");
-       if (args->ar_upgrade)
-               seq_printf(s, ",upgrade");
        if (args->ar_posix_acl)
                seq_printf(s, ",acl");
        if (args->ar_quota != GFS2_QUOTA_DEFAULT) {
index ccacffd2faaa6d65d1f116b9b2788ee732786f3f..748ccb557c18fc504c28951f13d634fe9f05fa0a 100644 (file)
@@ -230,7 +230,10 @@ static ssize_t demote_rq_store(struct gfs2_sbd *sdp, const char *buf, size_t len
 
        if (gltype > LM_TYPE_JOURNAL)
                return -EINVAL;
-       glops = gfs2_glops_list[gltype];
+       if (gltype == LM_TYPE_NONDISK && glnum == GFS2_TRANS_LOCK)
+               glops = &gfs2_trans_glops;
+       else
+               glops = gfs2_glops_list[gltype];
        if (glops == NULL)
                return -EINVAL;
        if (!test_and_set_bit(SDF_DEMOTE, &sdp->sd_flags))
@@ -399,31 +402,32 @@ static ssize_t recover_status_show(struct gfs2_sbd *sdp, char *buf)
 
 static ssize_t jid_show(struct gfs2_sbd *sdp, char *buf)
 {
-       return sprintf(buf, "%u\n", sdp->sd_lockstruct.ls_jid);
+       return sprintf(buf, "%d\n", sdp->sd_lockstruct.ls_jid);
 }
 
 static ssize_t jid_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
 {
-        unsigned jid;
+        int jid;
        int rv;
 
-       rv = sscanf(buf, "%u", &jid);
+       rv = sscanf(buf, "%d", &jid);
        if (rv != 1)
                return -EINVAL;
 
        spin_lock(&sdp->sd_jindex_spin);
        rv = -EINVAL;
-       if (sdp->sd_args.ar_spectator)
-               goto out;
        if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL)
                goto out;
        rv = -EBUSY;
-       if (test_and_clear_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0)
+       if (test_bit(SDF_NOJOURNALID, &sdp->sd_flags) == 0)
                goto out;
+       rv = 0;
+       if (sdp->sd_args.ar_spectator && jid > 0)
+               rv = jid = -EINVAL;
        sdp->sd_lockstruct.ls_jid = jid;
+       clear_bit(SDF_NOJOURNALID, &sdp->sd_flags);
        smp_mb__after_clear_bit();
        wake_up_bit(&sdp->sd_flags, SDF_NOJOURNALID);
-       rv = 0;
 out:
        spin_unlock(&sdp->sd_jindex_spin);
        return rv ? rv : len;
@@ -617,7 +621,7 @@ static int gfs2_uevent(struct kset *kset, struct kobject *kobj,
        add_uevent_var(env, "LOCKTABLE=%s", sdp->sd_table_name);
        add_uevent_var(env, "LOCKPROTO=%s", sdp->sd_proto_name);
        if (!test_bit(SDF_NOJOURNALID, &sdp->sd_flags))
-               add_uevent_var(env, "JOURNALID=%u", sdp->sd_lockstruct.ls_jid);
+               add_uevent_var(env, "JOURNALID=%d", sdp->sd_lockstruct.ls_jid);
        if (gfs2_uuid_valid(uuid))
                add_uevent_var(env, "UUID=%pUB", uuid);
        return 0;
index 148d55c14171dee39435c83d56c906c09dcd0cf8..cedb0bb96d968414d14e6eca3e5b934b68ee606e 100644 (file)
@@ -39,7 +39,8 @@
        {(1UL << GLF_INVALIDATE_IN_PROGRESS),   "i" },          \
        {(1UL << GLF_REPLY_PENDING),            "r" },          \
        {(1UL << GLF_INITIAL),                  "I" },          \
-       {(1UL << GLF_FROZEN),                   "F" })
+       {(1UL << GLF_FROZEN),                   "F" },          \
+       {(1UL << GLF_QUEUED),                   "q" })
 
 #ifndef NUMPTY
 #define NUMPTY
index edf9d4bd908ee2726991f12ac869bfeb60971381..fb56b783e028c8ce61b0b663e67e2df14e408b07 100644 (file)
@@ -20,11 +20,20 @@ struct gfs2_glock;
 #define RES_JDATA      1
 #define RES_DATA       1
 #define RES_LEAF       1
+#define RES_RG_HDR     1
 #define RES_RG_BIT     2
 #define RES_EATTR      1
 #define RES_STATFS     1
 #define RES_QUOTA      2
 
+/* reserve either the number of blocks to be allocated plus the rg header
+ * block, or all of the blocks in the rg, whichever is smaller */
+static inline unsigned int gfs2_rg_blocks(const struct gfs2_alloc *al)
+{
+       return (al->al_requested < al->al_rgd->rd_length)?
+              al->al_requested + 1 : al->al_rgd->rd_length;
+}
+
 int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
                     unsigned int revokes);
 
index 776af6eb4bcb1b193ecf5ef858ac09cb0535b95f..30b58f07c8a6b219fc964efe101ce5f861397885 100644 (file)
@@ -734,7 +734,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
                goto out_gunlock_q;
 
        error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
-                                blks + al->al_rgd->rd_length +
+                                blks + gfs2_rg_blocks(al) +
                                 RES_DINODE + RES_STATFS + RES_QUOTA, 0);
        if (error)
                goto out_ipres;
index 4129cdb3f0d8fbf80c4b161d877d9e922666f9ea..571abe97b42a2919caf381238eec6e58c57d0eaf 100644 (file)
@@ -23,7 +23,7 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
        fd->search_key = ptr;
        fd->key = ptr + tree->max_key_len + 2;
        dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0));
-       down(&tree->tree_lock);
+       mutex_lock(&tree->tree_lock);
        return 0;
 }
 
@@ -32,7 +32,7 @@ void hfs_find_exit(struct hfs_find_data *fd)
        hfs_bnode_put(fd->bnode);
        kfree(fd->search_key);
        dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0));
-       up(&fd->tree->tree_lock);
+       mutex_unlock(&fd->tree->tree_lock);
        fd->tree = NULL;
 }
 
index 38a0a9917d7f3a67b0eaad49a75246430eef7d76..3ebc437736febb4e0ef37a3612ea6501c7eac59a 100644 (file)
@@ -27,7 +27,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
        if (!tree)
                return NULL;
 
-       init_MUTEX(&tree->tree_lock);
+       mutex_init(&tree->tree_lock);
        spin_lock_init(&tree->hash_lock);
        /* Set the correct compare function */
        tree->sb = sb;
index cc51905ac21de4f110929dedd9160152d76a0f26..2a1d712f85dccfb5bb2983615e84278a1c4923e7 100644 (file)
@@ -33,7 +33,7 @@ struct hfs_btree {
        unsigned int depth;
 
        //unsigned int map1_size, map_size;
-       struct semaphore tree_lock;
+       struct mutex tree_lock;
 
        unsigned int pages_per_bnode;
        spinlock_t hash_lock;
index 5007a41f1be9d345ff11dd7420285ee6a79c08e2..d182438c7ae4bea8b4ae108ad910ee795417410a 100644 (file)
@@ -23,7 +23,7 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
        fd->search_key = ptr;
        fd->key = ptr + tree->max_key_len + 2;
        dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0));
-       down(&tree->tree_lock);
+       mutex_lock(&tree->tree_lock);
        return 0;
 }
 
@@ -32,7 +32,7 @@ void hfs_find_exit(struct hfs_find_data *fd)
        hfs_bnode_put(fd->bnode);
        kfree(fd->search_key);
        dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0));
-       up(&fd->tree->tree_lock);
+       mutex_unlock(&fd->tree->tree_lock);
        fd->tree = NULL;
 }
 
@@ -52,6 +52,10 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
                rec = (e + b) / 2;
                len = hfs_brec_lenoff(bnode, rec, &off);
                keylen = hfs_brec_keylen(bnode, rec);
+               if (keylen == 0) {
+                       res = -EINVAL;
+                       goto fail;
+               }
                hfs_bnode_read(bnode, fd->key, off, keylen);
                cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
                if (!cmpval) {
@@ -67,6 +71,10 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
        if (rec != e && e >= 0) {
                len = hfs_brec_lenoff(bnode, e, &off);
                keylen = hfs_brec_keylen(bnode, e);
+               if (keylen == 0) {
+                       res = -EINVAL;
+                       goto fail;
+               }
                hfs_bnode_read(bnode, fd->key, off, keylen);
        }
 done:
@@ -75,6 +83,7 @@ done:
        fd->keylength = keylen;
        fd->entryoffset = off + keylen;
        fd->entrylength = len - keylen;
+fail:
        return res;
 }
 
@@ -198,6 +207,10 @@ int hfs_brec_goto(struct hfs_find_data *fd, int cnt)
 
        len = hfs_brec_lenoff(bnode, fd->record, &off);
        keylen = hfs_brec_keylen(bnode, fd->record);
+       if (keylen == 0) {
+               res = -EINVAL;
+               goto out;
+       }
        fd->keyoffset = off;
        fd->keylength = keylen;
        fd->entryoffset = off + keylen;
index ea30afc2a03c774221cc17341c446d30a0cb341b..ad57f5991eb1f14e3ac24dafa207e440d6d74be3 100644 (file)
@@ -17,6 +17,7 @@
 
 int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *max)
 {
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        struct page *page;
        struct address_space *mapping;
        __be32 *pptr, *curr, *end;
@@ -29,8 +30,8 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
                return size;
 
        dprint(DBG_BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len);
-       mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
-       mapping = HFSPLUS_SB(sb).alloc_file->i_mapping;
+       mutex_lock(&sbi->alloc_mutex);
+       mapping = sbi->alloc_file->i_mapping;
        page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL);
        if (IS_ERR(page)) {
                start = size;
@@ -150,16 +151,17 @@ done:
        set_page_dirty(page);
        kunmap(page);
        *max = offset + (curr - pptr) * 32 + i - start;
-       HFSPLUS_SB(sb).free_blocks -= *max;
+       sbi->free_blocks -= *max;
        sb->s_dirt = 1;
        dprint(DBG_BITMAP, "-> %u,%u\n", start, *max);
 out:
-       mutex_unlock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
+       mutex_unlock(&sbi->alloc_mutex);
        return start;
 }
 
 int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
 {
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        struct page *page;
        struct address_space *mapping;
        __be32 *pptr, *curr, *end;
@@ -172,11 +174,11 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
 
        dprint(DBG_BITMAP, "block_free: %u,%u\n", offset, count);
        /* are all of the bits in range? */
-       if ((offset + count) > HFSPLUS_SB(sb).total_blocks)
+       if ((offset + count) > sbi->total_blocks)
                return -2;
 
-       mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
-       mapping = HFSPLUS_SB(sb).alloc_file->i_mapping;
+       mutex_lock(&sbi->alloc_mutex);
+       mapping = sbi->alloc_file->i_mapping;
        pnr = offset / PAGE_CACHE_BITS;
        page = read_mapping_page(mapping, pnr, NULL);
        pptr = kmap(page);
@@ -224,9 +226,9 @@ done:
 out:
        set_page_dirty(page);
        kunmap(page);
-       HFSPLUS_SB(sb).free_blocks += len;
+       sbi->free_blocks += len;
        sb->s_dirt = 1;
-       mutex_unlock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
+       mutex_unlock(&sbi->alloc_mutex);
 
        return 0;
 }
index c88e5d72a402ae2d29a8905cdccf7b59ccd4337d..2f39d05443e1a374b197359f70d20337562aa9e8 100644 (file)
@@ -42,10 +42,13 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
                recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
                if (!recoff)
                        return 0;
-               if (node->tree->attributes & HFS_TREE_BIGKEYS)
-                       retval = hfs_bnode_read_u16(node, recoff) + 2;
-               else
-                       retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
+
+               retval = hfs_bnode_read_u16(node, recoff) + 2;
+               if (retval > node->tree->max_key_len + 2) {
+                       printk(KERN_ERR "hfs: keylen %d too large\n",
+                               retval);
+                       retval = 0;
+               }
        }
        return retval;
 }
@@ -216,7 +219,7 @@ skip:
 static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
 {
        struct hfs_btree *tree;
-       struct hfs_bnode *node, *new_node;
+       struct hfs_bnode *node, *new_node, *next_node;
        struct hfs_bnode_desc node_desc;
        int num_recs, new_rec_off, new_off, old_rec_off;
        int data_start, data_end, size;
@@ -235,6 +238,17 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
        new_node->type = node->type;
        new_node->height = node->height;
 
+       if (node->next)
+               next_node = hfs_bnode_find(tree, node->next);
+       else
+               next_node = NULL;
+
+       if (IS_ERR(next_node)) {
+               hfs_bnode_put(node);
+               hfs_bnode_put(new_node);
+               return next_node;
+       }
+
        size = tree->node_size / 2 - node->num_recs * 2 - 14;
        old_rec_off = tree->node_size - 4;
        num_recs = 1;
@@ -248,6 +262,8 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
                /* panic? */
                hfs_bnode_put(node);
                hfs_bnode_put(new_node);
+               if (next_node)
+                       hfs_bnode_put(next_node);
                return ERR_PTR(-ENOSPC);
        }
 
@@ -302,8 +318,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
        hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));
 
        /* update next bnode header */
-       if (new_node->next) {
-               struct hfs_bnode *next_node = hfs_bnode_find(tree, new_node->next);
+       if (next_node) {
                next_node->prev = new_node->this;
                hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
                node_desc.prev = cpu_to_be32(next_node->prev);
index e49fcee1e293f725786e84ea6126e408e5eda7c8..22e4d4e329999c3ba9848036a3639bc194598f74 100644 (file)
@@ -30,7 +30,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
        if (!tree)
                return NULL;
 
-       init_MUTEX(&tree->tree_lock);
+       mutex_init(&tree->tree_lock);
        spin_lock_init(&tree->hash_lock);
        tree->sb = sb;
        tree->cnid = id;
@@ -39,10 +39,16 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
                goto free_tree;
        tree->inode = inode;
 
+       if (!HFSPLUS_I(tree->inode)->first_blocks) {
+               printk(KERN_ERR
+                      "hfs: invalid btree extent records (0 size).\n");
+               goto free_inode;
+       }
+
        mapping = tree->inode->i_mapping;
        page = read_mapping_page(mapping, 0, NULL);
        if (IS_ERR(page))
-               goto free_tree;
+               goto free_inode;
 
        /* Load the header */
        head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
@@ -57,27 +63,56 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
        tree->max_key_len = be16_to_cpu(head->max_key_len);
        tree->depth = be16_to_cpu(head->depth);
 
-       /* Set the correct compare function */
-       if (id == HFSPLUS_EXT_CNID) {
+       /* Verify the tree and set the correct compare function */
+       switch (id) {
+       case HFSPLUS_EXT_CNID:
+               if (tree->max_key_len != HFSPLUS_EXT_KEYLEN - sizeof(u16)) {
+                       printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
+                               tree->max_key_len);
+                       goto fail_page;
+               }
+               if (tree->attributes & HFS_TREE_VARIDXKEYS) {
+                       printk(KERN_ERR "hfs: invalid extent btree flag\n");
+                       goto fail_page;
+               }
+
                tree->keycmp = hfsplus_ext_cmp_key;
-       } else if (id == HFSPLUS_CAT_CNID) {
-               if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) &&
+               break;
+       case HFSPLUS_CAT_CNID:
+               if (tree->max_key_len != HFSPLUS_CAT_KEYLEN - sizeof(u16)) {
+                       printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
+                               tree->max_key_len);
+                       goto fail_page;
+               }
+               if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
+                       printk(KERN_ERR "hfs: invalid catalog btree flag\n");
+                       goto fail_page;
+               }
+
+               if (test_bit(HFSPLUS_SB_HFSX, &HFSPLUS_SB(sb)->flags) &&
                    (head->key_type == HFSPLUS_KEY_BINARY))
                        tree->keycmp = hfsplus_cat_bin_cmp_key;
                else {
                        tree->keycmp = hfsplus_cat_case_cmp_key;
-                       HFSPLUS_SB(sb).flags |= HFSPLUS_SB_CASEFOLD;
+                       set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
                }
-       } else {
+               break;
+       default:
                printk(KERN_ERR "hfs: unknown B*Tree requested\n");
                goto fail_page;
        }
 
+       if (!(tree->attributes & HFS_TREE_BIGKEYS)) {
+               printk(KERN_ERR "hfs: invalid btree flag\n");
+               goto fail_page;
+       }
+
        size = tree->node_size;
        if (!is_power_of_2(size))
                goto fail_page;
        if (!tree->node_count)
                goto fail_page;
+
        tree->node_size_shift = ffs(size) - 1;
 
        tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
@@ -87,10 +122,11 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
        return tree;
 
  fail_page:
-       tree->inode->i_mapping->a_ops = &hfsplus_aops;
        page_cache_release(page);
- free_tree:
+ free_inode:
+       tree->inode->i_mapping->a_ops = &hfsplus_aops;
        iput(tree->inode);
+ free_tree:
        kfree(tree);
        return NULL;
 }
@@ -192,17 +228,18 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
 
        while (!tree->free_nodes) {
                struct inode *inode = tree->inode;
+               struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
                u32 count;
                int res;
 
                res = hfsplus_file_extend(inode);
                if (res)
                        return ERR_PTR(res);
-               HFSPLUS_I(inode).phys_size = inode->i_size =
-                               (loff_t)HFSPLUS_I(inode).alloc_blocks <<
-                               HFSPLUS_SB(tree->sb).alloc_blksz_shift;
-               HFSPLUS_I(inode).fs_blocks = HFSPLUS_I(inode).alloc_blocks <<
-                                            HFSPLUS_SB(tree->sb).fs_shift;
+               hip->phys_size = inode->i_size =
+                       (loff_t)hip->alloc_blocks <<
+                               HFSPLUS_SB(tree->sb)->alloc_blksz_shift;
+               hip->fs_blocks =
+                       hip->alloc_blocks << HFSPLUS_SB(tree->sb)->fs_shift;
                inode_set_bytes(inode, inode->i_size);
                count = inode->i_size >> tree->node_size_shift;
                tree->free_nodes = count - tree->node_count;
index f6874acb2cf2a3a81a242f1983600eb912b9f607..8af45fc5b051abb3353501441fa9ea9030d9395a 100644 (file)
@@ -67,7 +67,7 @@ static void hfsplus_cat_build_key_uni(hfsplus_btree_key *key, u32 parent,
        key->key_len = cpu_to_be16(6 + ustrlen);
 }
 
-static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
+void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms)
 {
        if (inode->i_flags & S_IMMUTABLE)
                perms->rootflags |= HFSPLUS_FLG_IMMUTABLE;
@@ -77,15 +77,24 @@ static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
                perms->rootflags |= HFSPLUS_FLG_APPEND;
        else
                perms->rootflags &= ~HFSPLUS_FLG_APPEND;
-       HFSPLUS_I(inode).rootflags = perms->rootflags;
-       HFSPLUS_I(inode).userflags = perms->userflags;
+
+       perms->userflags = HFSPLUS_I(inode)->userflags;
        perms->mode = cpu_to_be16(inode->i_mode);
        perms->owner = cpu_to_be32(inode->i_uid);
        perms->group = cpu_to_be32(inode->i_gid);
+
+       if (S_ISREG(inode->i_mode))
+               perms->dev = cpu_to_be32(inode->i_nlink);
+       else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
+               perms->dev = cpu_to_be32(inode->i_rdev);
+       else
+               perms->dev = 0;
 }
 
 static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct inode *inode)
 {
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
+
        if (S_ISDIR(inode->i_mode)) {
                struct hfsplus_cat_folder *folder;
 
@@ -93,13 +102,13 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
                memset(folder, 0, sizeof(*folder));
                folder->type = cpu_to_be16(HFSPLUS_FOLDER);
                folder->id = cpu_to_be32(inode->i_ino);
-               HFSPLUS_I(inode).create_date =
+               HFSPLUS_I(inode)->create_date =
                        folder->create_date =
                        folder->content_mod_date =
                        folder->attribute_mod_date =
                        folder->access_date = hfsp_now2mt();
-               hfsplus_set_perms(inode, &folder->permissions);
-               if (inode == HFSPLUS_SB(inode->i_sb).hidden_dir)
+               hfsplus_cat_set_perms(inode, &folder->permissions);
+               if (inode == sbi->hidden_dir)
                        /* invisible and namelocked */
                        folder->user_info.frFlags = cpu_to_be16(0x5000);
                return sizeof(*folder);
@@ -111,19 +120,19 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
                file->type = cpu_to_be16(HFSPLUS_FILE);
                file->flags = cpu_to_be16(HFSPLUS_FILE_THREAD_EXISTS);
                file->id = cpu_to_be32(cnid);
-               HFSPLUS_I(inode).create_date =
+               HFSPLUS_I(inode)->create_date =
                        file->create_date =
                        file->content_mod_date =
                        file->attribute_mod_date =
                        file->access_date = hfsp_now2mt();
                if (cnid == inode->i_ino) {
-                       hfsplus_set_perms(inode, &file->permissions);
+                       hfsplus_cat_set_perms(inode, &file->permissions);
                        if (S_ISLNK(inode->i_mode)) {
                                file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE);
                                file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR);
                        } else {
-                               file->user_info.fdType = cpu_to_be32(HFSPLUS_SB(inode->i_sb).type);
-                               file->user_info.fdCreator = cpu_to_be32(HFSPLUS_SB(inode->i_sb).creator);
+                               file->user_info.fdType = cpu_to_be32(sbi->type);
+                               file->user_info.fdCreator = cpu_to_be32(sbi->creator);
                        }
                        if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
                                file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
@@ -131,8 +140,8 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i
                        file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE);
                        file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR);
                        file->user_info.fdFlags = cpu_to_be16(0x100);
-                       file->create_date = HFSPLUS_I(HFSPLUS_SB(inode->i_sb).hidden_dir).create_date;
-                       file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode).dev);
+                       file->create_date = HFSPLUS_I(sbi->hidden_dir)->create_date;
+                       file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode)->linkid);
                }
                return sizeof(*file);
        }
@@ -180,15 +189,14 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
 
 int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode)
 {
+       struct super_block *sb = dir->i_sb;
        struct hfs_find_data fd;
-       struct super_block *sb;
        hfsplus_cat_entry entry;
        int entry_size;
        int err;
 
        dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink);
-       sb = dir->i_sb;
-       hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
+       hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
 
        hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
        entry_size = hfsplus_fill_cat_thread(sb, &entry, S_ISDIR(inode->i_mode) ?
@@ -234,7 +242,7 @@ err2:
 
 int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
 {
-       struct super_block *sb;
+       struct super_block *sb = dir->i_sb;
        struct hfs_find_data fd;
        struct hfsplus_fork_raw fork;
        struct list_head *pos;
@@ -242,8 +250,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
        u16 type;
 
        dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
-       sb = dir->i_sb;
-       hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
+       hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
 
        if (!str) {
                int len;
@@ -279,7 +286,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)
                hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC);
        }
 
-       list_for_each(pos, &HFSPLUS_I(dir).open_dir_list) {
+       list_for_each(pos, &HFSPLUS_I(dir)->open_dir_list) {
                struct hfsplus_readdir_data *rd =
                        list_entry(pos, struct hfsplus_readdir_data, list);
                if (fd.tree->keycmp(fd.search_key, (void *)&rd->key) < 0)
@@ -312,7 +319,7 @@ int hfsplus_rename_cat(u32 cnid,
                       struct inode *src_dir, struct qstr *src_name,
                       struct inode *dst_dir, struct qstr *dst_name)
 {
-       struct super_block *sb;
+       struct super_block *sb = src_dir->i_sb;
        struct hfs_find_data src_fd, dst_fd;
        hfsplus_cat_entry entry;
        int entry_size, type;
@@ -320,8 +327,7 @@ int hfsplus_rename_cat(u32 cnid,
 
        dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name,
                dst_dir->i_ino, dst_name->name);
-       sb = src_dir->i_sb;
-       hfs_find_init(HFSPLUS_SB(sb).cat_tree, &src_fd);
+       hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
        dst_fd = src_fd;
 
        /* find the old dir entry and read the data */
index 764fd1bdca882da08028e34b133930d9d155a364..d236d85ec9d73f703384ecaa9d6522fe7433c775 100644 (file)
@@ -39,7 +39,7 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
 
        dentry->d_op = &hfsplus_dentry_operations;
        dentry->d_fsdata = NULL;
-       hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
+       hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
        hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name);
 again:
        err = hfs_brec_read(&fd, &entry, sizeof(entry));
@@ -68,9 +68,9 @@ again:
                cnid = be32_to_cpu(entry.file.id);
                if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) &&
                    entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) &&
-                   (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb).hidden_dir).create_date ||
-                    entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode).create_date) &&
-                   HFSPLUS_SB(sb).hidden_dir) {
+                   (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->create_date ||
+                    entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode)->create_date) &&
+                   HFSPLUS_SB(sb)->hidden_dir) {
                        struct qstr str;
                        char name[32];
 
@@ -86,7 +86,8 @@ again:
                                linkid = be32_to_cpu(entry.file.permissions.dev);
                                str.len = sprintf(name, "iNode%d", linkid);
                                str.name = name;
-                               hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_SB(sb).hidden_dir->i_ino, &str);
+                               hfsplus_cat_build_key(sb, fd.search_key,
+                                       HFSPLUS_SB(sb)->hidden_dir->i_ino, &str);
                                goto again;
                        }
                } else if (!dentry->d_fsdata)
@@ -101,7 +102,7 @@ again:
        if (IS_ERR(inode))
                return ERR_CAST(inode);
        if (S_ISREG(inode->i_mode))
-               HFSPLUS_I(inode).dev = linkid;
+               HFSPLUS_I(inode)->linkid = linkid;
 out:
        d_add(dentry, inode);
        return NULL;
@@ -124,7 +125,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
        if (filp->f_pos >= inode->i_size)
                return 0;
 
-       hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
+       hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
        hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
        err = hfs_brec_find(&fd);
        if (err)
@@ -180,8 +181,9 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
                                err = -EIO;
                                goto out;
                        }
-                       if (HFSPLUS_SB(sb).hidden_dir &&
-                           HFSPLUS_SB(sb).hidden_dir->i_ino == be32_to_cpu(entry.folder.id))
+                       if (HFSPLUS_SB(sb)->hidden_dir &&
+                           HFSPLUS_SB(sb)->hidden_dir->i_ino ==
+                                       be32_to_cpu(entry.folder.id))
                                goto next;
                        if (filldir(dirent, strbuf, len, filp->f_pos,
                                    be32_to_cpu(entry.folder.id), DT_DIR))
@@ -217,7 +219,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
                }
                filp->private_data = rd;
                rd->file = filp;
-               list_add(&rd->list, &HFSPLUS_I(inode).open_dir_list);
+               list_add(&rd->list, &HFSPLUS_I(inode)->open_dir_list);
        }
        memcpy(&rd->key, fd.key, sizeof(struct hfsplus_cat_key));
 out:
@@ -229,38 +231,18 @@ static int hfsplus_dir_release(struct inode *inode, struct file *file)
 {
        struct hfsplus_readdir_data *rd = file->private_data;
        if (rd) {
+               mutex_lock(&inode->i_mutex);
                list_del(&rd->list);
+               mutex_unlock(&inode->i_mutex);
                kfree(rd);
        }
        return 0;
 }
 
-static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode,
-                         struct nameidata *nd)
-{
-       struct inode *inode;
-       int res;
-
-       inode = hfsplus_new_inode(dir->i_sb, mode);
-       if (!inode)
-               return -ENOSPC;
-
-       res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
-       if (res) {
-               inode->i_nlink = 0;
-               hfsplus_delete_inode(inode);
-               iput(inode);
-               return res;
-       }
-       hfsplus_instantiate(dentry, inode, inode->i_ino);
-       mark_inode_dirty(inode);
-       return 0;
-}
-
 static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
                        struct dentry *dst_dentry)
 {
-       struct super_block *sb = dst_dir->i_sb;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dst_dir->i_sb);
        struct inode *inode = src_dentry->d_inode;
        struct inode *src_dir = src_dentry->d_parent->d_inode;
        struct qstr str;
@@ -270,7 +252,10 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
 
        if (HFSPLUS_IS_RSRC(inode))
                return -EPERM;
+       if (!S_ISREG(inode->i_mode))
+               return -EPERM;
 
+       mutex_lock(&sbi->vh_mutex);
        if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) {
                for (;;) {
                        get_random_bytes(&id, sizeof(cnid));
@@ -279,40 +264,41 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
                        str.len = sprintf(name, "iNode%d", id);
                        res = hfsplus_rename_cat(inode->i_ino,
                                                 src_dir, &src_dentry->d_name,
-                                                HFSPLUS_SB(sb).hidden_dir, &str);
+                                                sbi->hidden_dir, &str);
                        if (!res)
                                break;
                        if (res != -EEXIST)
-                               return res;
+                               goto out;
                }
-               HFSPLUS_I(inode).dev = id;
-               cnid = HFSPLUS_SB(sb).next_cnid++;
+               HFSPLUS_I(inode)->linkid = id;
+               cnid = sbi->next_cnid++;
                src_dentry->d_fsdata = (void *)(unsigned long)cnid;
                res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode);
                if (res)
                        /* panic? */
-                       return res;
-               HFSPLUS_SB(sb).file_count++;
+                       goto out;
+               sbi->file_count++;
        }
-       cnid = HFSPLUS_SB(sb).next_cnid++;
+       cnid = sbi->next_cnid++;
        res = hfsplus_create_cat(cnid, dst_dir, &dst_dentry->d_name, inode);
        if (res)
-               return res;
+               goto out;
 
        inc_nlink(inode);
        hfsplus_instantiate(dst_dentry, inode, cnid);
        atomic_inc(&inode->i_count);
        inode->i_ctime = CURRENT_TIME_SEC;
        mark_inode_dirty(inode);
-       HFSPLUS_SB(sb).file_count++;
-       sb->s_dirt = 1;
-
-       return 0;
+       sbi->file_count++;
+       dst_dir->i_sb->s_dirt = 1;
+out:
+       mutex_unlock(&sbi->vh_mutex);
+       return res;
 }
 
 static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
 {
-       struct super_block *sb = dir->i_sb;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
        struct inode *inode = dentry->d_inode;
        struct qstr str;
        char name[32];
@@ -322,21 +308,22 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
        if (HFSPLUS_IS_RSRC(inode))
                return -EPERM;
 
+       mutex_lock(&sbi->vh_mutex);
        cnid = (u32)(unsigned long)dentry->d_fsdata;
        if (inode->i_ino == cnid &&
-           atomic_read(&HFSPLUS_I(inode).opencnt)) {
+           atomic_read(&HFSPLUS_I(inode)->opencnt)) {
                str.name = name;
                str.len = sprintf(name, "temp%lu", inode->i_ino);
                res = hfsplus_rename_cat(inode->i_ino,
                                         dir, &dentry->d_name,
-                                        HFSPLUS_SB(sb).hidden_dir, &str);
+                                        sbi->hidden_dir, &str);
                if (!res)
                        inode->i_flags |= S_DEAD;
-               return res;
+               goto out;
        }
        res = hfsplus_delete_cat(cnid, dir, &dentry->d_name);
        if (res)
-               return res;
+               goto out;
 
        if (inode->i_nlink > 0)
                drop_nlink(inode);
@@ -344,10 +331,10 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
                clear_nlink(inode);
        if (!inode->i_nlink) {
                if (inode->i_ino != cnid) {
-                       HFSPLUS_SB(sb).file_count--;
-                       if (!atomic_read(&HFSPLUS_I(inode).opencnt)) {
+                       sbi->file_count--;
+                       if (!atomic_read(&HFSPLUS_I(inode)->opencnt)) {
                                res = hfsplus_delete_cat(inode->i_ino,
-                                                        HFSPLUS_SB(sb).hidden_dir,
+                                                        sbi->hidden_dir,
                                                         NULL);
                                if (!res)
                                        hfsplus_delete_inode(inode);
@@ -356,107 +343,108 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
                } else
                        hfsplus_delete_inode(inode);
        } else
-               HFSPLUS_SB(sb).file_count--;
+               sbi->file_count--;
        inode->i_ctime = CURRENT_TIME_SEC;
        mark_inode_dirty(inode);
-
+out:
+       mutex_unlock(&sbi->vh_mutex);
        return res;
 }
 
-static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, int mode)
-{
-       struct inode *inode;
-       int res;
-
-       inode = hfsplus_new_inode(dir->i_sb, S_IFDIR | mode);
-       if (!inode)
-               return -ENOSPC;
-
-       res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
-       if (res) {
-               inode->i_nlink = 0;
-               hfsplus_delete_inode(inode);
-               iput(inode);
-               return res;
-       }
-       hfsplus_instantiate(dentry, inode, inode->i_ino);
-       mark_inode_dirty(inode);
-       return 0;
-}
-
 static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       struct inode *inode;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
+       struct inode *inode = dentry->d_inode;
        int res;
 
-       inode = dentry->d_inode;
        if (inode->i_size != 2)
                return -ENOTEMPTY;
+
+       mutex_lock(&sbi->vh_mutex);
        res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
        if (res)
-               return res;
+               goto out;
        clear_nlink(inode);
        inode->i_ctime = CURRENT_TIME_SEC;
        hfsplus_delete_inode(inode);
        mark_inode_dirty(inode);
-       return 0;
+out:
+       mutex_unlock(&sbi->vh_mutex);
+       return res;
 }
 
 static int hfsplus_symlink(struct inode *dir, struct dentry *dentry,
                           const char *symname)
 {
-       struct super_block *sb;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
        struct inode *inode;
-       int res;
+       int res = -ENOSPC;
 
-       sb = dir->i_sb;
-       inode = hfsplus_new_inode(sb, S_IFLNK | S_IRWXUGO);
+       mutex_lock(&sbi->vh_mutex);
+       inode = hfsplus_new_inode(dir->i_sb, S_IFLNK | S_IRWXUGO);
        if (!inode)
-               return -ENOSPC;
+               goto out;
 
        res = page_symlink(inode, symname, strlen(symname) + 1);
-       if (res) {
-               inode->i_nlink = 0;
-               hfsplus_delete_inode(inode);
-               iput(inode);
-               return res;
-       }
+       if (res)
+               goto out_err;
 
-       mark_inode_dirty(inode);
        res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
+       if (res)
+               goto out_err;
 
-       if (!res) {
-               hfsplus_instantiate(dentry, inode, inode->i_ino);
-               mark_inode_dirty(inode);
-       }
+       hfsplus_instantiate(dentry, inode, inode->i_ino);
+       mark_inode_dirty(inode);
+       goto out;
 
+out_err:
+       inode->i_nlink = 0;
+       hfsplus_delete_inode(inode);
+       iput(inode);
+out:
+       mutex_unlock(&sbi->vh_mutex);
        return res;
 }
 
 static int hfsplus_mknod(struct inode *dir, struct dentry *dentry,
                         int mode, dev_t rdev)
 {
-       struct super_block *sb;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(dir->i_sb);
        struct inode *inode;
-       int res;
+       int res = -ENOSPC;
 
-       sb = dir->i_sb;
-       inode = hfsplus_new_inode(sb, mode);
+       mutex_lock(&sbi->vh_mutex);
+       inode = hfsplus_new_inode(dir->i_sb, mode);
        if (!inode)
-               return -ENOSPC;
+               goto out;
+
+       if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode))
+               init_special_inode(inode, mode, rdev);
 
        res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
        if (res) {
                inode->i_nlink = 0;
                hfsplus_delete_inode(inode);
                iput(inode);
-               return res;
+               goto out;
        }
-       init_special_inode(inode, mode, rdev);
+
        hfsplus_instantiate(dentry, inode, inode->i_ino);
        mark_inode_dirty(inode);
+out:
+       mutex_unlock(&sbi->vh_mutex);
+       return res;
+}
 
-       return 0;
+static int hfsplus_create(struct inode *dir, struct dentry *dentry, int mode,
+                         struct nameidata *nd)
+{
+       return hfsplus_mknod(dir, dentry, mode, 0);
+}
+
+static int hfsplus_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+       return hfsplus_mknod(dir, dentry, mode | S_IFDIR, 0);
 }
 
 static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
@@ -466,7 +454,10 @@ static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        /* Unlink destination if it already exists */
        if (new_dentry->d_inode) {
-               res = hfsplus_unlink(new_dir, new_dentry);
+               if (S_ISDIR(new_dentry->d_inode->i_mode))
+                       res = hfsplus_rmdir(new_dir, new_dentry);
+               else
+                       res = hfsplus_unlink(new_dir, new_dentry);
                if (res)
                        return res;
        }
index 0022eec63cdacd97c2a438b8d9f623ff6be88dd4..0c9cb1820a523fae02c6bf2f37e6fbdc5c5dceeb 100644 (file)
@@ -85,35 +85,49 @@ static u32 hfsplus_ext_lastblock(struct hfsplus_extent *ext)
 
 static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd)
 {
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        int res;
 
-       hfsplus_ext_build_key(fd->search_key, inode->i_ino, HFSPLUS_I(inode).cached_start,
-                             HFSPLUS_IS_RSRC(inode) ?  HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
+       WARN_ON(!mutex_is_locked(&hip->extents_lock));
+
+       hfsplus_ext_build_key(fd->search_key, inode->i_ino, hip->cached_start,
+                             HFSPLUS_IS_RSRC(inode) ?
+                               HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
+
        res = hfs_brec_find(fd);
-       if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_NEW) {
+       if (hip->flags & HFSPLUS_FLG_EXT_NEW) {
                if (res != -ENOENT)
                        return;
-               hfs_brec_insert(fd, HFSPLUS_I(inode).cached_extents, sizeof(hfsplus_extent_rec));
-               HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
+               hfs_brec_insert(fd, hip->cached_extents,
+                               sizeof(hfsplus_extent_rec));
+               hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
        } else {
                if (res)
                        return;
-               hfs_bnode_write(fd->bnode, HFSPLUS_I(inode).cached_extents, fd->entryoffset, fd->entrylength);
-               HFSPLUS_I(inode).flags &= ~HFSPLUS_FLG_EXT_DIRTY;
+               hfs_bnode_write(fd->bnode, hip->cached_extents,
+                               fd->entryoffset, fd->entrylength);
+               hip->flags &= ~HFSPLUS_FLG_EXT_DIRTY;
        }
 }
 
-void hfsplus_ext_write_extent(struct inode *inode)
+static void hfsplus_ext_write_extent_locked(struct inode *inode)
 {
-       if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_DIRTY) {
+       if (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_EXT_DIRTY) {
                struct hfs_find_data fd;
 
-               hfs_find_init(HFSPLUS_SB(inode->i_sb).ext_tree, &fd);
+               hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
                __hfsplus_ext_write_extent(inode, &fd);
                hfs_find_exit(&fd);
        }
 }
 
+void hfsplus_ext_write_extent(struct inode *inode)
+{
+       mutex_lock(&HFSPLUS_I(inode)->extents_lock);
+       hfsplus_ext_write_extent_locked(inode);
+       mutex_unlock(&HFSPLUS_I(inode)->extents_lock);
+}
+
 static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
                                            struct hfsplus_extent *extent,
                                            u32 cnid, u32 block, u8 type)
@@ -136,33 +150,39 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
 
 static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block)
 {
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        int res;
 
-       if (HFSPLUS_I(inode).flags & HFSPLUS_FLG_EXT_DIRTY)
+       WARN_ON(!mutex_is_locked(&hip->extents_lock));
+
+       if (hip->flags & HFSPLUS_FLG_EXT_DIRTY)
                __hfsplus_ext_write_extent(inode, fd);
 
-       res = __hfsplus_ext_read_extent(fd, HFSPLUS_I(inode).cached_extents, inode->i_ino,
-                                       block, HFSPLUS_IS_RSRC(inode) ? HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA);
+       res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino,
+                                       block, HFSPLUS_IS_RSRC(inode) ?
+                                               HFSPLUS_TYPE_RSRC :
+                                               HFSPLUS_TYPE_DATA);
        if (!res) {
-               HFSPLUS_I(inode).cached_start = be32_to_cpu(fd->key->ext.start_block);
-               HFSPLUS_I(inode).cached_blocks = hfsplus_ext_block_count(HFSPLUS_I(inode).cached_extents);
+               hip->cached_start = be32_to_cpu(fd->key->ext.start_block);
+               hip->cached_blocks = hfsplus_ext_block_count(hip->cached_extents);
        } else {
-               HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).cached_blocks = 0;
-               HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
+               hip->cached_start = hip->cached_blocks = 0;
+               hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
        }
        return res;
 }
 
 static int hfsplus_ext_read_extent(struct inode *inode, u32 block)
 {
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        struct hfs_find_data fd;
        int res;
 
-       if (block >= HFSPLUS_I(inode).cached_start &&
-           block < HFSPLUS_I(inode).cached_start + HFSPLUS_I(inode).cached_blocks)
+       if (block >= hip->cached_start &&
+           block < hip->cached_start + hip->cached_blocks)
                return 0;
 
-       hfs_find_init(HFSPLUS_SB(inode->i_sb).ext_tree, &fd);
+       hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
        res = __hfsplus_ext_cache_extent(&fd, inode, block);
        hfs_find_exit(&fd);
        return res;
@@ -172,21 +192,21 @@ static int hfsplus_ext_read_extent(struct inode *inode, u32 block)
 int hfsplus_get_block(struct inode *inode, sector_t iblock,
                      struct buffer_head *bh_result, int create)
 {
-       struct super_block *sb;
+       struct super_block *sb = inode->i_sb;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        int res = -EIO;
        u32 ablock, dblock, mask;
        int shift;
 
-       sb = inode->i_sb;
-
        /* Convert inode block to disk allocation block */
-       shift = HFSPLUS_SB(sb).alloc_blksz_shift - sb->s_blocksize_bits;
-       ablock = iblock >> HFSPLUS_SB(sb).fs_shift;
+       shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
+       ablock = iblock >> sbi->fs_shift;
 
-       if (iblock >= HFSPLUS_I(inode).fs_blocks) {
-               if (iblock > HFSPLUS_I(inode).fs_blocks || !create)
+       if (iblock >= hip->fs_blocks) {
+               if (iblock > hip->fs_blocks || !create)
                        return -EIO;
-               if (ablock >= HFSPLUS_I(inode).alloc_blocks) {
+               if (ablock >= hip->alloc_blocks) {
                        res = hfsplus_file_extend(inode);
                        if (res)
                                return res;
@@ -194,33 +214,33 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
        } else
                create = 0;
 
-       if (ablock < HFSPLUS_I(inode).first_blocks) {
-               dblock = hfsplus_ext_find_block(HFSPLUS_I(inode).first_extents, ablock);
+       if (ablock < hip->first_blocks) {
+               dblock = hfsplus_ext_find_block(hip->first_extents, ablock);
                goto done;
        }
 
        if (inode->i_ino == HFSPLUS_EXT_CNID)
                return -EIO;
 
-       mutex_lock(&HFSPLUS_I(inode).extents_lock);
+       mutex_lock(&hip->extents_lock);
        res = hfsplus_ext_read_extent(inode, ablock);
        if (!res) {
-               dblock = hfsplus_ext_find_block(HFSPLUS_I(inode).cached_extents, ablock -
-                                            HFSPLUS_I(inode).cached_start);
+               dblock = hfsplus_ext_find_block(hip->cached_extents,
+                                               ablock - hip->cached_start);
        } else {
-               mutex_unlock(&HFSPLUS_I(inode).extents_lock);
+               mutex_unlock(&hip->extents_lock);
                return -EIO;
        }
-       mutex_unlock(&HFSPLUS_I(inode).extents_lock);
+       mutex_unlock(&hip->extents_lock);
 
 done:
        dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", inode->i_ino, (long long)iblock, dblock);
-       mask = (1 << HFSPLUS_SB(sb).fs_shift) - 1;
-       map_bh(bh_result, sb, (dblock << HFSPLUS_SB(sb).fs_shift) + HFSPLUS_SB(sb).blockoffset + (iblock & mask));
+       mask = (1 << sbi->fs_shift) - 1;
+       map_bh(bh_result, sb, (dblock << sbi->fs_shift) + sbi->blockoffset + (iblock & mask));
        if (create) {
                set_buffer_new(bh_result);
-               HFSPLUS_I(inode).phys_size += sb->s_blocksize;
-               HFSPLUS_I(inode).fs_blocks++;
+               hip->phys_size += sb->s_blocksize;
+               hip->fs_blocks++;
                inode_add_bytes(inode, sb->s_blocksize);
                mark_inode_dirty(inode);
        }
@@ -327,7 +347,7 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw
        if (total_blocks == blocks)
                return 0;
 
-       hfs_find_init(HFSPLUS_SB(sb).ext_tree, &fd);
+       hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
        do {
                res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid,
                                                total_blocks, type);
@@ -348,29 +368,33 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw
 int hfsplus_file_extend(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        u32 start, len, goal;
        int res;
 
-       if (HFSPLUS_SB(sb).alloc_file->i_size * 8 < HFSPLUS_SB(sb).total_blocks - HFSPLUS_SB(sb).free_blocks + 8) {
+       if (sbi->alloc_file->i_size * 8 <
+           sbi->total_blocks - sbi->free_blocks + 8) {
                // extend alloc file
-               printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n", HFSPLUS_SB(sb).alloc_file->i_size * 8,
-                       HFSPLUS_SB(sb).total_blocks, HFSPLUS_SB(sb).free_blocks);
+               printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n",
+                               sbi->alloc_file->i_size * 8,
+                               sbi->total_blocks, sbi->free_blocks);
                return -ENOSPC;
        }
 
-       mutex_lock(&HFSPLUS_I(inode).extents_lock);
-       if (HFSPLUS_I(inode).alloc_blocks == HFSPLUS_I(inode).first_blocks)
-               goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).first_extents);
+       mutex_lock(&hip->extents_lock);
+       if (hip->alloc_blocks == hip->first_blocks)
+               goal = hfsplus_ext_lastblock(hip->first_extents);
        else {
-               res = hfsplus_ext_read_extent(inode, HFSPLUS_I(inode).alloc_blocks);
+               res = hfsplus_ext_read_extent(inode, hip->alloc_blocks);
                if (res)
                        goto out;
-               goal = hfsplus_ext_lastblock(HFSPLUS_I(inode).cached_extents);
+               goal = hfsplus_ext_lastblock(hip->cached_extents);
        }
 
-       len = HFSPLUS_I(inode).clump_blocks;
-       start = hfsplus_block_allocate(sb, HFSPLUS_SB(sb).total_blocks, goal, &len);
-       if (start >= HFSPLUS_SB(sb).total_blocks) {
+       len = hip->clump_blocks;
+       start = hfsplus_block_allocate(sb, sbi->total_blocks, goal, &len);
+       if (start >= sbi->total_blocks) {
                start = hfsplus_block_allocate(sb, goal, 0, &len);
                if (start >= goal) {
                        res = -ENOSPC;
@@ -379,56 +403,56 @@ int hfsplus_file_extend(struct inode *inode)
        }
 
        dprint(DBG_EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
-       if (HFSPLUS_I(inode).alloc_blocks <= HFSPLUS_I(inode).first_blocks) {
-               if (!HFSPLUS_I(inode).first_blocks) {
+
+       if (hip->alloc_blocks <= hip->first_blocks) {
+               if (!hip->first_blocks) {
                        dprint(DBG_EXTENT, "first extents\n");
                        /* no extents yet */
-                       HFSPLUS_I(inode).first_extents[0].start_block = cpu_to_be32(start);
-                       HFSPLUS_I(inode).first_extents[0].block_count = cpu_to_be32(len);
+                       hip->first_extents[0].start_block = cpu_to_be32(start);
+                       hip->first_extents[0].block_count = cpu_to_be32(len);
                        res = 0;
                } else {
                        /* try to append to extents in inode */
-                       res = hfsplus_add_extent(HFSPLUS_I(inode).first_extents,
-                                                HFSPLUS_I(inode).alloc_blocks,
+                       res = hfsplus_add_extent(hip->first_extents,
+                                                hip->alloc_blocks,
                                                 start, len);
                        if (res == -ENOSPC)
                                goto insert_extent;
                }
                if (!res) {
-                       hfsplus_dump_extent(HFSPLUS_I(inode).first_extents);
-                       HFSPLUS_I(inode).first_blocks += len;
+                       hfsplus_dump_extent(hip->first_extents);
+                       hip->first_blocks += len;
                }
        } else {
-               res = hfsplus_add_extent(HFSPLUS_I(inode).cached_extents,
-                                        HFSPLUS_I(inode).alloc_blocks -
-                                        HFSPLUS_I(inode).cached_start,
+               res = hfsplus_add_extent(hip->cached_extents,
+                                        hip->alloc_blocks - hip->cached_start,
                                         start, len);
                if (!res) {
-                       hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents);
-                       HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY;
-                       HFSPLUS_I(inode).cached_blocks += len;
+                       hfsplus_dump_extent(hip->cached_extents);
+                       hip->flags |= HFSPLUS_FLG_EXT_DIRTY;
+                       hip->cached_blocks += len;
                } else if (res == -ENOSPC)
                        goto insert_extent;
        }
 out:
-       mutex_unlock(&HFSPLUS_I(inode).extents_lock);
+       mutex_unlock(&hip->extents_lock);
        if (!res) {
-               HFSPLUS_I(inode).alloc_blocks += len;
+               hip->alloc_blocks += len;
                mark_inode_dirty(inode);
        }
        return res;
 
 insert_extent:
        dprint(DBG_EXTENT, "insert new extent\n");
-       hfsplus_ext_write_extent(inode);
+       hfsplus_ext_write_extent_locked(inode);
 
-       memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec));
-       HFSPLUS_I(inode).cached_extents[0].start_block = cpu_to_be32(start);
-       HFSPLUS_I(inode).cached_extents[0].block_count = cpu_to_be32(len);
-       hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents);
-       HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW;
-       HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).alloc_blocks;
-       HFSPLUS_I(inode).cached_blocks = len;
+       memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
+       hip->cached_extents[0].start_block = cpu_to_be32(start);
+       hip->cached_extents[0].block_count = cpu_to_be32(len);
+       hfsplus_dump_extent(hip->cached_extents);
+       hip->flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW;
+       hip->cached_start = hip->alloc_blocks;
+       hip->cached_blocks = len;
 
        res = 0;
        goto out;
@@ -437,13 +461,15 @@ insert_extent:
 void hfsplus_file_truncate(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        struct hfs_find_data fd;
        u32 alloc_cnt, blk_cnt, start;
        int res;
 
-       dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n", inode->i_ino,
-              (long long)HFSPLUS_I(inode).phys_size, inode->i_size);
-       if (inode->i_size > HFSPLUS_I(inode).phys_size) {
+       dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n",
+               inode->i_ino, (long long)hip->phys_size, inode->i_size);
+
+       if (inode->i_size > hip->phys_size) {
                struct address_space *mapping = inode->i_mapping;
                struct page *page;
                void *fsdata;
@@ -460,47 +486,48 @@ void hfsplus_file_truncate(struct inode *inode)
                        return;
                mark_inode_dirty(inode);
                return;
-       } else if (inode->i_size == HFSPLUS_I(inode).phys_size)
+       } else if (inode->i_size == hip->phys_size)
                return;
 
-       blk_cnt = (inode->i_size + HFSPLUS_SB(sb).alloc_blksz - 1) >> HFSPLUS_SB(sb).alloc_blksz_shift;
-       alloc_cnt = HFSPLUS_I(inode).alloc_blocks;
+       blk_cnt = (inode->i_size + HFSPLUS_SB(sb)->alloc_blksz - 1) >>
+                       HFSPLUS_SB(sb)->alloc_blksz_shift;
+       alloc_cnt = hip->alloc_blocks;
        if (blk_cnt == alloc_cnt)
                goto out;
 
-       mutex_lock(&HFSPLUS_I(inode).extents_lock);
-       hfs_find_init(HFSPLUS_SB(sb).ext_tree, &fd);
+       mutex_lock(&hip->extents_lock);
+       hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
        while (1) {
-               if (alloc_cnt == HFSPLUS_I(inode).first_blocks) {
-                       hfsplus_free_extents(sb, HFSPLUS_I(inode).first_extents,
+               if (alloc_cnt == hip->first_blocks) {
+                       hfsplus_free_extents(sb, hip->first_extents,
                                             alloc_cnt, alloc_cnt - blk_cnt);
-                       hfsplus_dump_extent(HFSPLUS_I(inode).first_extents);
-                       HFSPLUS_I(inode).first_blocks = blk_cnt;
+                       hfsplus_dump_extent(hip->first_extents);
+                       hip->first_blocks = blk_cnt;
                        break;
                }
                res = __hfsplus_ext_cache_extent(&fd, inode, alloc_cnt);
                if (res)
                        break;
-               start = HFSPLUS_I(inode).cached_start;
-               hfsplus_free_extents(sb, HFSPLUS_I(inode).cached_extents,
+               start = hip->cached_start;
+               hfsplus_free_extents(sb, hip->cached_extents,
                                     alloc_cnt - start, alloc_cnt - blk_cnt);
-               hfsplus_dump_extent(HFSPLUS_I(inode).cached_extents);
+               hfsplus_dump_extent(hip->cached_extents);
                if (blk_cnt > start) {
-                       HFSPLUS_I(inode).flags |= HFSPLUS_FLG_EXT_DIRTY;
+                       hip->flags |= HFSPLUS_FLG_EXT_DIRTY;
                        break;
                }
                alloc_cnt = start;
-               HFSPLUS_I(inode).cached_start = HFSPLUS_I(inode).cached_blocks = 0;
-               HFSPLUS_I(inode).flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
+               hip->cached_start = hip->cached_blocks = 0;
+               hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW);
                hfs_brec_remove(&fd);
        }
        hfs_find_exit(&fd);
-       mutex_unlock(&HFSPLUS_I(inode).extents_lock);
+       mutex_unlock(&hip->extents_lock);
 
-       HFSPLUS_I(inode).alloc_blocks = blk_cnt;
+       hip->alloc_blocks = blk_cnt;
 out:
-       HFSPLUS_I(inode).phys_size = inode->i_size;
-       HFSPLUS_I(inode).fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
-       inode_set_bytes(inode, HFSPLUS_I(inode).fs_blocks << sb->s_blocksize_bits);
+       hip->phys_size = inode->i_size;
+       hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+       inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
        mark_inode_dirty(inode);
 }
index dc856be3c2b010854c78da1049b86d2f7ce48147..cb3653efb57a2dcf2285a19fcb7262cb7a1ba509 100644 (file)
@@ -62,7 +62,7 @@ struct hfs_btree {
        unsigned int depth;
 
        //unsigned int map1_size, map_size;
-       struct semaphore tree_lock;
+       struct mutex tree_lock;
 
        unsigned int pages_per_bnode;
        spinlock_t hash_lock;
@@ -121,16 +121,21 @@ struct hfsplus_sb_info {
        u32 sect_count;
        int fs_shift;
 
-       /* Stuff in host order from Vol Header */
+       /* immutable data from the volume header */
        u32 alloc_blksz;
        int alloc_blksz_shift;
        u32 total_blocks;
+       u32 data_clump_blocks, rsrc_clump_blocks;
+
+       /* mutable data from the volume header, protected by alloc_mutex */
        u32 free_blocks;
-       u32 next_alloc;
+       struct mutex alloc_mutex;
+
+       /* mutable data from the volume header, protected by vh_mutex */
        u32 next_cnid;
        u32 file_count;
        u32 folder_count;
-       u32 data_clump_blocks, rsrc_clump_blocks;
+       struct mutex vh_mutex;
 
        /* Config options */
        u32 creator;
@@ -143,40 +148,50 @@ struct hfsplus_sb_info {
        int part, session;
 
        unsigned long flags;
-
-       struct hlist_head rsrc_inodes;
 };
 
-#define HFSPLUS_SB_WRITEBACKUP 0x0001
-#define HFSPLUS_SB_NODECOMPOSE 0x0002
-#define HFSPLUS_SB_FORCE       0x0004
-#define HFSPLUS_SB_HFSX                0x0008
-#define HFSPLUS_SB_CASEFOLD    0x0010
+#define HFSPLUS_SB_WRITEBACKUP 0
+#define HFSPLUS_SB_NODECOMPOSE 1
+#define HFSPLUS_SB_FORCE       2
+#define HFSPLUS_SB_HFSX                3
+#define HFSPLUS_SB_CASEFOLD    4
 
 
 struct hfsplus_inode_info {
-       struct mutex extents_lock;
-       u32 clump_blocks, alloc_blocks;
-       sector_t fs_blocks;
-       /* Allocation extents from catalog record or volume header */
-       hfsplus_extent_rec first_extents;
-       u32 first_blocks;
-       hfsplus_extent_rec cached_extents;
-       u32 cached_start, cached_blocks;
        atomic_t opencnt;
 
-       struct inode *rsrc_inode;
+       /*
+        * Extent allocation information, protected by extents_lock.
+        */
+       u32 first_blocks;
+       u32 clump_blocks;
+       u32 alloc_blocks;
+       u32 cached_start;
+       u32 cached_blocks;
+       hfsplus_extent_rec first_extents;
+       hfsplus_extent_rec cached_extents;
        unsigned long flags;
+       struct mutex extents_lock;
 
+       /*
+        * Immutable data.
+        */
+       struct inode *rsrc_inode;
        __be32 create_date;
-       /* Device number in hfsplus_permissions in catalog */
-       u32 dev;
-       /* BSD system and user file flags */
-       u8 rootflags;
-       u8 userflags;
 
+       /*
+        * Protected by sbi->vh_mutex.
+        */
+       u32 linkid;
+
+       /*
+        * Protected by i_mutex.
+        */
+       sector_t fs_blocks;
+       u8 userflags;           /* BSD user file flags */
        struct list_head open_dir_list;
        loff_t phys_size;
+
        struct inode vfs_inode;
 };
 
@@ -184,8 +199,8 @@ struct hfsplus_inode_info {
 #define HFSPLUS_FLG_EXT_DIRTY  0x0002
 #define HFSPLUS_FLG_EXT_NEW    0x0004
 
-#define HFSPLUS_IS_DATA(inode)   (!(HFSPLUS_I(inode).flags & HFSPLUS_FLG_RSRC))
-#define HFSPLUS_IS_RSRC(inode)   (HFSPLUS_I(inode).flags & HFSPLUS_FLG_RSRC)
+#define HFSPLUS_IS_DATA(inode)   (!(HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC))
+#define HFSPLUS_IS_RSRC(inode)   (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC)
 
 struct hfs_find_data {
        /* filled by caller */
@@ -311,6 +326,7 @@ int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *);
 int hfsplus_delete_cat(u32, struct inode *, struct qstr *);
 int hfsplus_rename_cat(u32, struct inode *, struct qstr *,
                       struct inode *, struct qstr *);
+void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms);
 
 /* dir.c */
 extern const struct inode_operations hfsplus_dir_inode_operations;
@@ -372,26 +388,15 @@ int hfsplus_read_wrapper(struct super_block *);
 int hfs_part_find(struct super_block *, sector_t *, sector_t *);
 
 /* access macros */
-/*
 static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb)
 {
        return sb->s_fs_info;
 }
+
 static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
 {
        return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
 }
-*/
-#define HFSPLUS_SB(super)      (*(struct hfsplus_sb_info *)(super)->s_fs_info)
-#define HFSPLUS_I(inode)       (*list_entry(inode, struct hfsplus_inode_info, vfs_inode))
-
-#if 1
-#define hfsplus_kmap(p)                ({ struct page *__p = (p); kmap(__p); })
-#define hfsplus_kunmap(p)      ({ struct page *__p = (p); kunmap(__p); __p; })
-#else
-#define hfsplus_kmap(p)                kmap(p)
-#define hfsplus_kunmap(p)      kunmap(p)
-#endif
 
 #define sb_bread512(sb, sec, data) ({                  \
        struct buffer_head *__bh;                       \
@@ -419,6 +424,4 @@ static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode)
 #define hfsp_ut2mt(t)          __hfsp_ut2mt((t).tv_sec)
 #define hfsp_now2mt()          __hfsp_ut2mt(get_seconds())
 
-#define kdev_t_to_nr(x)                (x)
-
 #endif
index fe99fe8db61a3cb279885cee2c73cf5743704604..6892899fd6fbbabce55d3fe1f2c8915fe3f33d89 100644 (file)
@@ -200,6 +200,7 @@ struct hfsplus_cat_key {
        struct hfsplus_unistr name;
 } __packed;
 
+#define HFSPLUS_CAT_KEYLEN     (sizeof(struct hfsplus_cat_key))
 
 /* Structs from hfs.h */
 struct hfsp_point {
@@ -323,7 +324,7 @@ struct hfsplus_ext_key {
        __be32 start_block;
 } __packed;
 
-#define HFSPLUS_EXT_KEYLEN 12
+#define HFSPLUS_EXT_KEYLEN     sizeof(struct hfsplus_ext_key)
 
 /* HFS+ generic BTree key */
 typedef union {
index c5a979d62c657a866685dac4743fa01515b1653a..78449280dae08471958a328afca7f225fe9d744f 100644 (file)
@@ -36,7 +36,7 @@ static int hfsplus_write_begin(struct file *file, struct address_space *mapping,
        *pagep = NULL;
        ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
                                hfsplus_get_block,
-                               &HFSPLUS_I(mapping->host).phys_size);
+                               &HFSPLUS_I(mapping->host)->phys_size);
        if (unlikely(ret)) {
                loff_t isize = mapping->host->i_size;
                if (pos + len > isize)
@@ -62,13 +62,13 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask)
 
        switch (inode->i_ino) {
        case HFSPLUS_EXT_CNID:
-               tree = HFSPLUS_SB(sb).ext_tree;
+               tree = HFSPLUS_SB(sb)->ext_tree;
                break;
        case HFSPLUS_CAT_CNID:
-               tree = HFSPLUS_SB(sb).cat_tree;
+               tree = HFSPLUS_SB(sb)->cat_tree;
                break;
        case HFSPLUS_ATTR_CNID:
-               tree = HFSPLUS_SB(sb).attr_tree;
+               tree = HFSPLUS_SB(sb)->attr_tree;
                break;
        default:
                BUG();
@@ -172,12 +172,13 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
        struct hfs_find_data fd;
        struct super_block *sb = dir->i_sb;
        struct inode *inode = NULL;
+       struct hfsplus_inode_info *hip;
        int err;
 
        if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
                goto out;
 
-       inode = HFSPLUS_I(dir).rsrc_inode;
+       inode = HFSPLUS_I(dir)->rsrc_inode;
        if (inode)
                goto out;
 
@@ -185,12 +186,13 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
+       hip = HFSPLUS_I(inode);
        inode->i_ino = dir->i_ino;
-       INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
-       mutex_init(&HFSPLUS_I(inode).extents_lock);
-       HFSPLUS_I(inode).flags = HFSPLUS_FLG_RSRC;
+       INIT_LIST_HEAD(&hip->open_dir_list);
+       mutex_init(&hip->extents_lock);
+       hip->flags = HFSPLUS_FLG_RSRC;
 
-       hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
+       hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
        err = hfsplus_find_cat(sb, dir->i_ino, &fd);
        if (!err)
                err = hfsplus_cat_read_inode(inode, &fd);
@@ -199,10 +201,18 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent
                iput(inode);
                return ERR_PTR(err);
        }
-       HFSPLUS_I(inode).rsrc_inode = dir;
-       HFSPLUS_I(dir).rsrc_inode = inode;
+       hip->rsrc_inode = dir;
+       HFSPLUS_I(dir)->rsrc_inode = inode;
        igrab(dir);
-       hlist_add_head(&inode->i_hash, &HFSPLUS_SB(sb).rsrc_inodes);
+
+       /*
+        * __mark_inode_dirty expects inodes to be hashed.  Since we don't
+        * want resource fork inodes in the regular inode space, we make them
+        * appear hashed, but do not put on any lists.  hlist_del()
+        * will work fine and require no locking.
+        */
+       inode->i_hash.pprev = &inode->i_hash.next;
+
        mark_inode_dirty(inode);
 out:
        d_add(dentry, inode);
@@ -211,30 +221,27 @@ out:
 
 static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir)
 {
-       struct super_block *sb = inode->i_sb;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
        u16 mode;
 
        mode = be16_to_cpu(perms->mode);
 
        inode->i_uid = be32_to_cpu(perms->owner);
        if (!inode->i_uid && !mode)
-               inode->i_uid = HFSPLUS_SB(sb).uid;
+               inode->i_uid = sbi->uid;
 
        inode->i_gid = be32_to_cpu(perms->group);
        if (!inode->i_gid && !mode)
-               inode->i_gid = HFSPLUS_SB(sb).gid;
+               inode->i_gid = sbi->gid;
 
        if (dir) {
-               mode = mode ? (mode & S_IALLUGO) :
-                       (S_IRWXUGO & ~(HFSPLUS_SB(sb).umask));
+               mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask));
                mode |= S_IFDIR;
        } else if (!mode)
-               mode = S_IFREG | ((S_IRUGO|S_IWUGO) &
-                       ~(HFSPLUS_SB(sb).umask));
+               mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask));
        inode->i_mode = mode;
 
-       HFSPLUS_I(inode).rootflags = perms->rootflags;
-       HFSPLUS_I(inode).userflags = perms->userflags;
+       HFSPLUS_I(inode)->userflags = perms->userflags;
        if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
                inode->i_flags |= S_IMMUTABLE;
        else
@@ -245,30 +252,13 @@ static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, i
                inode->i_flags &= ~S_APPEND;
 }
 
-static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
-{
-       if (inode->i_flags & S_IMMUTABLE)
-               perms->rootflags |= HFSPLUS_FLG_IMMUTABLE;
-       else
-               perms->rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
-       if (inode->i_flags & S_APPEND)
-               perms->rootflags |= HFSPLUS_FLG_APPEND;
-       else
-               perms->rootflags &= ~HFSPLUS_FLG_APPEND;
-       perms->userflags = HFSPLUS_I(inode).userflags;
-       perms->mode = cpu_to_be16(inode->i_mode);
-       perms->owner = cpu_to_be32(inode->i_uid);
-       perms->group = cpu_to_be32(inode->i_gid);
-       perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
-}
-
 static int hfsplus_file_open(struct inode *inode, struct file *file)
 {
        if (HFSPLUS_IS_RSRC(inode))
-               inode = HFSPLUS_I(inode).rsrc_inode;
+               inode = HFSPLUS_I(inode)->rsrc_inode;
        if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
                return -EOVERFLOW;
-       atomic_inc(&HFSPLUS_I(inode).opencnt);
+       atomic_inc(&HFSPLUS_I(inode)->opencnt);
        return 0;
 }
 
@@ -277,12 +267,13 @@ static int hfsplus_file_release(struct inode *inode, struct file *file)
        struct super_block *sb = inode->i_sb;
 
        if (HFSPLUS_IS_RSRC(inode))
-               inode = HFSPLUS_I(inode).rsrc_inode;
-       if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) {
+               inode = HFSPLUS_I(inode)->rsrc_inode;
+       if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) {
                mutex_lock(&inode->i_mutex);
                hfsplus_file_truncate(inode);
                if (inode->i_flags & S_DEAD) {
-                       hfsplus_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL);
+                       hfsplus_delete_cat(inode->i_ino,
+                                          HFSPLUS_SB(sb)->hidden_dir, NULL);
                        hfsplus_delete_inode(inode);
                }
                mutex_unlock(&inode->i_mutex);
@@ -361,47 +352,52 @@ static const struct file_operations hfsplus_file_operations = {
 
 struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
 {
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        struct inode *inode = new_inode(sb);
+       struct hfsplus_inode_info *hip;
+
        if (!inode)
                return NULL;
 
-       inode->i_ino = HFSPLUS_SB(sb).next_cnid++;
+       inode->i_ino = sbi->next_cnid++;
        inode->i_mode = mode;
        inode->i_uid = current_fsuid();
        inode->i_gid = current_fsgid();
        inode->i_nlink = 1;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
-       INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
-       mutex_init(&HFSPLUS_I(inode).extents_lock);
-       atomic_set(&HFSPLUS_I(inode).opencnt, 0);
-       HFSPLUS_I(inode).flags = 0;
-       memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec));
-       memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec));
-       HFSPLUS_I(inode).alloc_blocks = 0;
-       HFSPLUS_I(inode).first_blocks = 0;
-       HFSPLUS_I(inode).cached_start = 0;
-       HFSPLUS_I(inode).cached_blocks = 0;
-       HFSPLUS_I(inode).phys_size = 0;
-       HFSPLUS_I(inode).fs_blocks = 0;
-       HFSPLUS_I(inode).rsrc_inode = NULL;
+
+       hip = HFSPLUS_I(inode);
+       INIT_LIST_HEAD(&hip->open_dir_list);
+       mutex_init(&hip->extents_lock);
+       atomic_set(&hip->opencnt, 0);
+       hip->flags = 0;
+       memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
+       memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
+       hip->alloc_blocks = 0;
+       hip->first_blocks = 0;
+       hip->cached_start = 0;
+       hip->cached_blocks = 0;
+       hip->phys_size = 0;
+       hip->fs_blocks = 0;
+       hip->rsrc_inode = NULL;
        if (S_ISDIR(inode->i_mode)) {
                inode->i_size = 2;
-               HFSPLUS_SB(sb).folder_count++;
+               sbi->folder_count++;
                inode->i_op = &hfsplus_dir_inode_operations;
                inode->i_fop = &hfsplus_dir_operations;
        } else if (S_ISREG(inode->i_mode)) {
-               HFSPLUS_SB(sb).file_count++;
+               sbi->file_count++;
                inode->i_op = &hfsplus_file_inode_operations;
                inode->i_fop = &hfsplus_file_operations;
                inode->i_mapping->a_ops = &hfsplus_aops;
-               HFSPLUS_I(inode).clump_blocks = HFSPLUS_SB(sb).data_clump_blocks;
+               hip->clump_blocks = sbi->data_clump_blocks;
        } else if (S_ISLNK(inode->i_mode)) {
-               HFSPLUS_SB(sb).file_count++;
+               sbi->file_count++;
                inode->i_op = &page_symlink_inode_operations;
                inode->i_mapping->a_ops = &hfsplus_aops;
-               HFSPLUS_I(inode).clump_blocks = 1;
+               hip->clump_blocks = 1;
        } else
-               HFSPLUS_SB(sb).file_count++;
+               sbi->file_count++;
        insert_inode_hash(inode);
        mark_inode_dirty(inode);
        sb->s_dirt = 1;
@@ -414,11 +410,11 @@ void hfsplus_delete_inode(struct inode *inode)
        struct super_block *sb = inode->i_sb;
 
        if (S_ISDIR(inode->i_mode)) {
-               HFSPLUS_SB(sb).folder_count--;
+               HFSPLUS_SB(sb)->folder_count--;
                sb->s_dirt = 1;
                return;
        }
-       HFSPLUS_SB(sb).file_count--;
+       HFSPLUS_SB(sb)->file_count--;
        if (S_ISREG(inode->i_mode)) {
                if (!inode->i_nlink) {
                        inode->i_size = 0;
@@ -434,34 +430,39 @@ void hfsplus_delete_inode(struct inode *inode)
 void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
 {
        struct super_block *sb = inode->i_sb;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        u32 count;
        int i;
 
-       memcpy(&HFSPLUS_I(inode).first_extents, &fork->extents,
-              sizeof(hfsplus_extent_rec));
+       memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec));
        for (count = 0, i = 0; i < 8; i++)
                count += be32_to_cpu(fork->extents[i].block_count);
-       HFSPLUS_I(inode).first_blocks = count;
-       memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec));
-       HFSPLUS_I(inode).cached_start = 0;
-       HFSPLUS_I(inode).cached_blocks = 0;
-
-       HFSPLUS_I(inode).alloc_blocks = be32_to_cpu(fork->total_blocks);
-       inode->i_size = HFSPLUS_I(inode).phys_size = be64_to_cpu(fork->total_size);
-       HFSPLUS_I(inode).fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
-       inode_set_bytes(inode, HFSPLUS_I(inode).fs_blocks << sb->s_blocksize_bits);
-       HFSPLUS_I(inode).clump_blocks = be32_to_cpu(fork->clump_size) >> HFSPLUS_SB(sb).alloc_blksz_shift;
-       if (!HFSPLUS_I(inode).clump_blocks)
-               HFSPLUS_I(inode).clump_blocks = HFSPLUS_IS_RSRC(inode) ? HFSPLUS_SB(sb).rsrc_clump_blocks :
-                               HFSPLUS_SB(sb).data_clump_blocks;
+       hip->first_blocks = count;
+       memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
+       hip->cached_start = 0;
+       hip->cached_blocks = 0;
+
+       hip->alloc_blocks = be32_to_cpu(fork->total_blocks);
+       hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size);
+       hip->fs_blocks =
+               (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
+       inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
+       hip->clump_blocks =
+               be32_to_cpu(fork->clump_size) >> sbi->alloc_blksz_shift;
+       if (!hip->clump_blocks) {
+               hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ?
+                       sbi->rsrc_clump_blocks :
+                       sbi->data_clump_blocks;
+       }
 }
 
 void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
 {
-       memcpy(&fork->extents, &HFSPLUS_I(inode).first_extents,
+       memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
               sizeof(hfsplus_extent_rec));
        fork->total_size = cpu_to_be64(inode->i_size);
-       fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode).alloc_blocks);
+       fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks);
 }
 
 int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
@@ -472,7 +473,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
 
        type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
 
-       HFSPLUS_I(inode).dev = 0;
+       HFSPLUS_I(inode)->linkid = 0;
        if (type == HFSPLUS_FOLDER) {
                struct hfsplus_cat_folder *folder = &entry.folder;
 
@@ -486,8 +487,8 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
                inode->i_atime = hfsp_mt2ut(folder->access_date);
                inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
                inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
-               HFSPLUS_I(inode).create_date = folder->create_date;
-               HFSPLUS_I(inode).fs_blocks = 0;
+               HFSPLUS_I(inode)->create_date = folder->create_date;
+               HFSPLUS_I(inode)->fs_blocks = 0;
                inode->i_op = &hfsplus_dir_inode_operations;
                inode->i_fop = &hfsplus_dir_operations;
        } else if (type == HFSPLUS_FILE) {
@@ -518,7 +519,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
                inode->i_atime = hfsp_mt2ut(file->access_date);
                inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
                inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date);
-               HFSPLUS_I(inode).create_date = file->create_date;
+               HFSPLUS_I(inode)->create_date = file->create_date;
        } else {
                printk(KERN_ERR "hfs: bad catalog entry used to create inode\n");
                res = -EIO;
@@ -533,12 +534,12 @@ int hfsplus_cat_write_inode(struct inode *inode)
        hfsplus_cat_entry entry;
 
        if (HFSPLUS_IS_RSRC(inode))
-               main_inode = HFSPLUS_I(inode).rsrc_inode;
+               main_inode = HFSPLUS_I(inode)->rsrc_inode;
 
        if (!main_inode->i_nlink)
                return 0;
 
-       if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb).cat_tree, &fd))
+       if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd))
                /* panic? */
                return -EIO;
 
@@ -554,7 +555,7 @@ int hfsplus_cat_write_inode(struct inode *inode)
                hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
                                        sizeof(struct hfsplus_cat_folder));
                /* simple node checks? */
-               hfsplus_set_perms(inode, &folder->permissions);
+               hfsplus_cat_set_perms(inode, &folder->permissions);
                folder->access_date = hfsp_ut2mt(inode->i_atime);
                folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
                folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
@@ -576,11 +577,7 @@ int hfsplus_cat_write_inode(struct inode *inode)
                hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
                                        sizeof(struct hfsplus_cat_file));
                hfsplus_inode_write_fork(inode, &file->data_fork);
-               if (S_ISREG(inode->i_mode))
-                       HFSPLUS_I(inode).dev = inode->i_nlink;
-               if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
-                       HFSPLUS_I(inode).dev = kdev_t_to_nr(inode->i_rdev);
-               hfsplus_set_perms(inode, &file->permissions);
+               hfsplus_cat_set_perms(inode, &file->permissions);
                if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
                        file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
                else
index ac405f09902651838979e322931ba7a1f1441633..5b4667e08ef7789e49c274758a28d11ef86d5fde 100644 (file)
 #include <linux/mount.h>
 #include <linux/sched.h>
 #include <linux/xattr.h>
-#include <linux/smp_lock.h>
 #include <asm/uaccess.h>
 #include "hfsplus_fs.h"
 
-long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
 {
-       struct inode *inode = filp->f_path.dentry->d_inode;
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
+       unsigned int flags = 0;
+
+       if (inode->i_flags & S_IMMUTABLE)
+               flags |= FS_IMMUTABLE_FL;
+       if (inode->i_flags |= S_APPEND)
+               flags |= FS_APPEND_FL;
+       if (hip->userflags & HFSPLUS_FLG_NODUMP)
+               flags |= FS_NODUMP_FL;
+
+       return put_user(flags, user_flags);
+}
+
+static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
+{
+       struct inode *inode = file->f_path.dentry->d_inode;
+       struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
        unsigned int flags;
+       int err = 0;
 
-       lock_kernel();
-       switch (cmd) {
-       case HFSPLUS_IOC_EXT2_GETFLAGS:
-               flags = 0;
-               if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE)
-                       flags |= FS_IMMUTABLE_FL; /* EXT2_IMMUTABLE_FL */
-               if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND)
-                       flags |= FS_APPEND_FL; /* EXT2_APPEND_FL */
-               if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP)
-                       flags |= FS_NODUMP_FL; /* EXT2_NODUMP_FL */
-               return put_user(flags, (int __user *)arg);
-       case HFSPLUS_IOC_EXT2_SETFLAGS: {
-               int err = 0;
-               err = mnt_want_write(filp->f_path.mnt);
-               if (err) {
-                       unlock_kernel();
-                       return err;
-               }
+       err = mnt_want_write(file->f_path.mnt);
+       if (err)
+               goto out;
 
-               if (!is_owner_or_cap(inode)) {
-                       err = -EACCES;
-                       goto setflags_out;
-               }
-               if (get_user(flags, (int __user *)arg)) {
-                       err = -EFAULT;
-                       goto setflags_out;
-               }
-               if (flags & (FS_IMMUTABLE_FL|FS_APPEND_FL) ||
-                   HFSPLUS_I(inode).rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) {
-                       if (!capable(CAP_LINUX_IMMUTABLE)) {
-                               err = -EPERM;
-                               goto setflags_out;
-                       }
-               }
+       if (!is_owner_or_cap(inode)) {
+               err = -EACCES;
+               goto out_drop_write;
+       }
 
-               /* don't silently ignore unsupported ext2 flags */
-               if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
-                       err = -EOPNOTSUPP;
-                       goto setflags_out;
-               }
-               if (flags & FS_IMMUTABLE_FL) { /* EXT2_IMMUTABLE_FL */
-                       inode->i_flags |= S_IMMUTABLE;
-                       HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_IMMUTABLE;
-               } else {
-                       inode->i_flags &= ~S_IMMUTABLE;
-                       HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
-               }
-               if (flags & FS_APPEND_FL) { /* EXT2_APPEND_FL */
-                       inode->i_flags |= S_APPEND;
-                       HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_APPEND;
-               } else {
-                       inode->i_flags &= ~S_APPEND;
-                       HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_APPEND;
+       if (get_user(flags, user_flags)) {
+               err = -EFAULT;
+               goto out_drop_write;
+       }
+
+       mutex_lock(&inode->i_mutex);
+
+       if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) ||
+           inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
+               if (!capable(CAP_LINUX_IMMUTABLE)) {
+                       err = -EPERM;
+                       goto out_unlock_inode;
                }
-               if (flags & FS_NODUMP_FL) /* EXT2_NODUMP_FL */
-                       HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP;
-               else
-                       HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP;
-
-               inode->i_ctime = CURRENT_TIME_SEC;
-               mark_inode_dirty(inode);
-setflags_out:
-               mnt_drop_write(filp->f_path.mnt);
-               unlock_kernel();
-               return err;
        }
+
+       /* don't silently ignore unsupported ext2 flags */
+       if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
+               err = -EOPNOTSUPP;
+               goto out_unlock_inode;
+       }
+
+       if (flags & FS_IMMUTABLE_FL)
+               inode->i_flags |= S_IMMUTABLE;
+       else
+               inode->i_flags &= ~S_IMMUTABLE;
+
+       if (flags & FS_APPEND_FL)
+               inode->i_flags |= S_APPEND;
+       else
+               inode->i_flags &= ~S_APPEND;
+
+       if (flags & FS_NODUMP_FL)
+               hip->userflags |= HFSPLUS_FLG_NODUMP;
+       else
+               hip->userflags &= ~HFSPLUS_FLG_NODUMP;
+
+       inode->i_ctime = CURRENT_TIME_SEC;
+       mark_inode_dirty(inode);
+
+out_unlock_inode:
+       mutex_lock(&inode->i_mutex);
+out_drop_write:
+       mnt_drop_write(file->f_path.mnt);
+out:
+       return err;
+}
+
+long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       void __user *argp = (void __user *)arg;
+
+       switch (cmd) {
+       case HFSPLUS_IOC_EXT2_GETFLAGS:
+               return hfsplus_ioctl_getflags(file, argp);
+       case HFSPLUS_IOC_EXT2_SETFLAGS:
+               return hfsplus_ioctl_setflags(file, argp);
        default:
-               unlock_kernel();
                return -ENOTTY;
        }
 }
@@ -110,7 +125,7 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
        if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
                return -EOPNOTSUPP;
 
-       res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd);
+       res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
        if (res)
                return res;
        res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
@@ -153,7 +168,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
                return -EOPNOTSUPP;
 
        if (size) {
-               res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd);
+               res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
                if (res)
                        return res;
                res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
@@ -177,7 +192,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
                } else
                        res = size ? -ERANGE : 4;
        } else
-               res = -ENODATA;
+               res = -EOPNOTSUPP;
 out:
        if (size)
                hfs_find_exit(&fd);
index 572628b4b07d23af08f98ca7b757c85acfbcbc0c..f9ab276a4d8de9e15d2acf49a358da1a9ff10fe6 100644 (file)
@@ -143,13 +143,13 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
                        kfree(p);
                        break;
                case opt_decompose:
-                       sbi->flags &= ~HFSPLUS_SB_NODECOMPOSE;
+                       clear_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
                        break;
                case opt_nodecompose:
-                       sbi->flags |= HFSPLUS_SB_NODECOMPOSE;
+                       set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags);
                        break;
                case opt_force:
-                       sbi->flags |= HFSPLUS_SB_FORCE;
+                       set_bit(HFSPLUS_SB_FORCE, &sbi->flags);
                        break;
                default:
                        return 0;
@@ -171,7 +171,7 @@ done:
 
 int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
 {
-       struct hfsplus_sb_info *sbi = &HFSPLUS_SB(mnt->mnt_sb);
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(mnt->mnt_sb);
 
        if (sbi->creator != HFSPLUS_DEF_CR_TYPE)
                seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator);
@@ -184,7 +184,7 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt)
                seq_printf(seq, ",session=%u", sbi->session);
        if (sbi->nls)
                seq_printf(seq, ",nls=%s", sbi->nls->charset);
-       if (sbi->flags & HFSPLUS_SB_NODECOMPOSE)
+       if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags))
                seq_printf(seq, ",nodecompose");
        return 0;
 }
index 1528a6fd02992f1858ee254fe01039520da77bd4..208b16c645cc234c6f5ce1b15fbd5b49ba802ee8 100644 (file)
@@ -74,6 +74,7 @@ struct old_pmap {
 int hfs_part_find(struct super_block *sb,
                  sector_t *part_start, sector_t *part_size)
 {
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        struct buffer_head *bh;
        __be16 *data;
        int i, size, res;
@@ -95,7 +96,7 @@ int hfs_part_find(struct super_block *sb,
                for (i = 0; i < size; p++, i++) {
                        if (p->pdStart && p->pdSize &&
                            p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ &&
-                           (HFSPLUS_SB(sb).part < 0 || HFSPLUS_SB(sb).part == i)) {
+                           (sbi->part < 0 || sbi->part == i)) {
                                *part_start += be32_to_cpu(p->pdStart);
                                *part_size = be32_to_cpu(p->pdSize);
                                res = 0;
@@ -111,7 +112,7 @@ int hfs_part_find(struct super_block *sb,
                size = be32_to_cpu(pm->pmMapBlkCnt);
                for (i = 0; i < size;) {
                        if (!memcmp(pm->pmPartType,"Apple_HFS", 9) &&
-                           (HFSPLUS_SB(sb).part < 0 || HFSPLUS_SB(sb).part == i)) {
+                           (sbi->part < 0 || sbi->part == i)) {
                                *part_start += be32_to_cpu(pm->pmPyPartStart);
                                *part_size = be32_to_cpu(pm->pmPartBlkCnt);
                                res = 0;
index 3b55c050c74274710fa95cad827edf6abd6b8316..9a88d7536103e2c1c70f3824b42d367d3eac848f 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/pagemap.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/vfs.h>
 #include <linux/nls.h>
 
@@ -21,40 +20,11 @@ static void hfsplus_destroy_inode(struct inode *inode);
 
 #include "hfsplus_fs.h"
 
-struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
+static int hfsplus_system_read_inode(struct inode *inode)
 {
-       struct hfs_find_data fd;
-       struct hfsplus_vh *vhdr;
-       struct inode *inode;
-       long err = -EIO;
-
-       inode = iget_locked(sb, ino);
-       if (!inode)
-               return ERR_PTR(-ENOMEM);
-       if (!(inode->i_state & I_NEW))
-               return inode;
+       struct hfsplus_vh *vhdr = HFSPLUS_SB(inode->i_sb)->s_vhdr;
 
-       INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
-       mutex_init(&HFSPLUS_I(inode).extents_lock);
-       HFSPLUS_I(inode).flags = 0;
-       HFSPLUS_I(inode).rsrc_inode = NULL;
-       atomic_set(&HFSPLUS_I(inode).opencnt, 0);
-
-       if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) {
-       read_inode:
-               hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd);
-               err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
-               if (!err)
-                       err = hfsplus_cat_read_inode(inode, &fd);
-               hfs_find_exit(&fd);
-               if (err)
-                       goto bad_inode;
-               goto done;
-       }
-       vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr;
-       switch(inode->i_ino) {
-       case HFSPLUS_ROOT_CNID:
-               goto read_inode;
+       switch (inode->i_ino) {
        case HFSPLUS_EXT_CNID:
                hfsplus_inode_read_fork(inode, &vhdr->ext_file);
                inode->i_mapping->a_ops = &hfsplus_btree_aops;
@@ -75,74 +45,101 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
                inode->i_mapping->a_ops = &hfsplus_btree_aops;
                break;
        default:
-               goto bad_inode;
+               return -EIO;
+       }
+
+       return 0;
+}
+
+struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
+{
+       struct hfs_find_data fd;
+       struct inode *inode;
+       int err;
+
+       inode = iget_locked(sb, ino);
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
+       mutex_init(&HFSPLUS_I(inode)->extents_lock);
+       HFSPLUS_I(inode)->flags = 0;
+       HFSPLUS_I(inode)->rsrc_inode = NULL;
+       atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
+
+       if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
+           inode->i_ino == HFSPLUS_ROOT_CNID) {
+               hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
+               err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
+               if (!err)
+                       err = hfsplus_cat_read_inode(inode, &fd);
+               hfs_find_exit(&fd);
+       } else {
+               err = hfsplus_system_read_inode(inode);
+       }
+
+       if (err) {
+               iget_failed(inode);
+               return ERR_PTR(err);
        }
 
-done:
        unlock_new_inode(inode);
        return inode;
-
-bad_inode:
-       iget_failed(inode);
-       return ERR_PTR(err);
 }
 
-static int hfsplus_write_inode(struct inode *inode,
-               struct writeback_control *wbc)
+static int hfsplus_system_write_inode(struct inode *inode)
 {
-       struct hfsplus_vh *vhdr;
-       int ret = 0;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
+       struct hfsplus_vh *vhdr = sbi->s_vhdr;
+       struct hfsplus_fork_raw *fork;
+       struct hfs_btree *tree = NULL;
 
-       dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
-       hfsplus_ext_write_extent(inode);
-       if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID) {
-               return hfsplus_cat_write_inode(inode);
-       }
-       vhdr = HFSPLUS_SB(inode->i_sb).s_vhdr;
        switch (inode->i_ino) {
-       case HFSPLUS_ROOT_CNID:
-               ret = hfsplus_cat_write_inode(inode);
-               break;
        case HFSPLUS_EXT_CNID:
-               if (vhdr->ext_file.total_size != cpu_to_be64(inode->i_size)) {
-                       HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
-                       inode->i_sb->s_dirt = 1;
-               }
-               hfsplus_inode_write_fork(inode, &vhdr->ext_file);
-               hfs_btree_write(HFSPLUS_SB(inode->i_sb).ext_tree);
+               fork = &vhdr->ext_file;
+               tree = sbi->ext_tree;
                break;
        case HFSPLUS_CAT_CNID:
-               if (vhdr->cat_file.total_size != cpu_to_be64(inode->i_size)) {
-                       HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
-                       inode->i_sb->s_dirt = 1;
-               }
-               hfsplus_inode_write_fork(inode, &vhdr->cat_file);
-               hfs_btree_write(HFSPLUS_SB(inode->i_sb).cat_tree);
+               fork = &vhdr->cat_file;
+               tree = sbi->cat_tree;
                break;
        case HFSPLUS_ALLOC_CNID:
-               if (vhdr->alloc_file.total_size != cpu_to_be64(inode->i_size)) {
-                       HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
-                       inode->i_sb->s_dirt = 1;
-               }
-               hfsplus_inode_write_fork(inode, &vhdr->alloc_file);
+               fork = &vhdr->alloc_file;
                break;
        case HFSPLUS_START_CNID:
-               if (vhdr->start_file.total_size != cpu_to_be64(inode->i_size)) {
-                       HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
-                       inode->i_sb->s_dirt = 1;
-               }
-               hfsplus_inode_write_fork(inode, &vhdr->start_file);
+               fork = &vhdr->start_file;
                break;
        case HFSPLUS_ATTR_CNID:
-               if (vhdr->attr_file.total_size != cpu_to_be64(inode->i_size)) {
-                       HFSPLUS_SB(inode->i_sb).flags |= HFSPLUS_SB_WRITEBACKUP;
-                       inode->i_sb->s_dirt = 1;
-               }
-               hfsplus_inode_write_fork(inode, &vhdr->attr_file);
-               hfs_btree_write(HFSPLUS_SB(inode->i_sb).attr_tree);
-               break;
+               fork = &vhdr->attr_file;
+               tree = sbi->attr_tree;
+       default:
+               return -EIO;
+       }
+
+       if (fork->total_size != cpu_to_be64(inode->i_size)) {
+               set_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags);
+               inode->i_sb->s_dirt = 1;
        }
-       return ret;
+       hfsplus_inode_write_fork(inode, fork);
+       if (tree)
+               hfs_btree_write(tree);
+       return 0;
+}
+
+static int hfsplus_write_inode(struct inode *inode,
+               struct writeback_control *wbc)
+{
+       dprint(DBG_INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
+
+       hfsplus_ext_write_extent(inode);
+
+       if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
+           inode->i_ino == HFSPLUS_ROOT_CNID)
+               return hfsplus_cat_write_inode(inode);
+       else
+               return hfsplus_system_write_inode(inode);
 }
 
 static void hfsplus_evict_inode(struct inode *inode)
@@ -151,51 +148,53 @@ static void hfsplus_evict_inode(struct inode *inode)
        truncate_inode_pages(&inode->i_data, 0);
        end_writeback(inode);
        if (HFSPLUS_IS_RSRC(inode)) {
-               HFSPLUS_I(HFSPLUS_I(inode).rsrc_inode).rsrc_inode = NULL;
-               iput(HFSPLUS_I(inode).rsrc_inode);
+               HFSPLUS_I(HFSPLUS_I(inode)->rsrc_inode)->rsrc_inode = NULL;
+               iput(HFSPLUS_I(inode)->rsrc_inode);
        }
 }
 
 int hfsplus_sync_fs(struct super_block *sb, int wait)
 {
-       struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+       struct hfsplus_vh *vhdr = sbi->s_vhdr;
 
        dprint(DBG_SUPER, "hfsplus_write_super\n");
 
-       lock_super(sb);
+       mutex_lock(&sbi->vh_mutex);
+       mutex_lock(&sbi->alloc_mutex);
        sb->s_dirt = 0;
 
-       vhdr->free_blocks = cpu_to_be32(HFSPLUS_SB(sb).free_blocks);
-       vhdr->next_alloc = cpu_to_be32(HFSPLUS_SB(sb).next_alloc);
-       vhdr->next_cnid = cpu_to_be32(HFSPLUS_SB(sb).next_cnid);
-       vhdr->folder_count = cpu_to_be32(HFSPLUS_SB(sb).folder_count);
-       vhdr->file_count = cpu_to_be32(HFSPLUS_SB(sb).file_count);
+       vhdr->free_blocks = cpu_to_be32(sbi->free_blocks);
+       vhdr->next_cnid = cpu_to_be32(sbi->next_cnid);
+       vhdr->folder_count = cpu_to_be32(sbi->folder_count);
+       vhdr->file_count = cpu_to_be32(sbi->file_count);
 
-       mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
-       if (HFSPLUS_SB(sb).flags & HFSPLUS_SB_WRITEBACKUP) {
-               if (HFSPLUS_SB(sb).sect_count) {
+       mark_buffer_dirty(sbi->s_vhbh);
+       if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
+               if (sbi->sect_count) {
                        struct buffer_head *bh;
                        u32 block, offset;
 
-                       block = HFSPLUS_SB(sb).blockoffset;
-                       block += (HFSPLUS_SB(sb).sect_count - 2) >> (sb->s_blocksize_bits - 9);
-                       offset = ((HFSPLUS_SB(sb).sect_count - 2) << 9) & (sb->s_blocksize - 1);
-                       printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n", HFSPLUS_SB(sb).blockoffset,
-                               HFSPLUS_SB(sb).sect_count, block, offset);
+                       block = sbi->blockoffset;
+                       block += (sbi->sect_count - 2) >> (sb->s_blocksize_bits - 9);
+                       offset = ((sbi->sect_count - 2) << 9) & (sb->s_blocksize - 1);
+                       printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n",
+                                         sbi->blockoffset, sbi->sect_count,
+                                         block, offset);
                        bh = sb_bread(sb, block);
                        if (bh) {
                                vhdr = (struct hfsplus_vh *)(bh->b_data + offset);
                                if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) {
-                                       memcpy(vhdr, HFSPLUS_SB(sb).s_vhdr, sizeof(*vhdr));
+                                       memcpy(vhdr, sbi->s_vhdr, sizeof(*vhdr));
                                        mark_buffer_dirty(bh);
                                        brelse(bh);
                                } else
                                        printk(KERN_WARNING "hfs: backup not found!\n");
                        }
                }
-               HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP;
        }
-       unlock_super(sb);
+       mutex_unlock(&sbi->alloc_mutex);
+       mutex_unlock(&sbi->vh_mutex);
        return 0;
 }
 
@@ -209,48 +208,48 @@ static void hfsplus_write_super(struct super_block *sb)
 
 static void hfsplus_put_super(struct super_block *sb)
 {
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
+
        dprint(DBG_SUPER, "hfsplus_put_super\n");
+
        if (!sb->s_fs_info)
                return;
 
-       lock_kernel();
-
        if (sb->s_dirt)
                hfsplus_write_super(sb);
-       if (!(sb->s_flags & MS_RDONLY) && HFSPLUS_SB(sb).s_vhdr) {
-               struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
+       if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
+               struct hfsplus_vh *vhdr = sbi->s_vhdr;
 
                vhdr->modify_date = hfsp_now2mt();
                vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT);
                vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT);
-               mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
-               sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh);
+               mark_buffer_dirty(sbi->s_vhbh);
+               sync_dirty_buffer(sbi->s_vhbh);
        }
 
-       hfs_btree_close(HFSPLUS_SB(sb).cat_tree);
-       hfs_btree_close(HFSPLUS_SB(sb).ext_tree);
-       iput(HFSPLUS_SB(sb).alloc_file);
-       iput(HFSPLUS_SB(sb).hidden_dir);
-       brelse(HFSPLUS_SB(sb).s_vhbh);
-       unload_nls(HFSPLUS_SB(sb).nls);
+       hfs_btree_close(sbi->cat_tree);
+       hfs_btree_close(sbi->ext_tree);
+       iput(sbi->alloc_file);
+       iput(sbi->hidden_dir);
+       brelse(sbi->s_vhbh);
+       unload_nls(sbi->nls);
        kfree(sb->s_fs_info);
        sb->s_fs_info = NULL;
-
-       unlock_kernel();
 }
 
 static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
 {
        struct super_block *sb = dentry->d_sb;
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        buf->f_type = HFSPLUS_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
-       buf->f_blocks = HFSPLUS_SB(sb).total_blocks << HFSPLUS_SB(sb).fs_shift;
-       buf->f_bfree = HFSPLUS_SB(sb).free_blocks << HFSPLUS_SB(sb).fs_shift;
+       buf->f_blocks = sbi->total_blocks << sbi->fs_shift;
+       buf->f_bfree = sbi->free_blocks << sbi->fs_shift;
        buf->f_bavail = buf->f_bfree;
        buf->f_files = 0xFFFFFFFF;
-       buf->f_ffree = 0xFFFFFFFF - HFSPLUS_SB(sb).next_cnid;
+       buf->f_ffree = 0xFFFFFFFF - sbi->next_cnid;
        buf->f_fsid.val[0] = (u32)id;
        buf->f_fsid.val[1] = (u32)(id >> 32);
        buf->f_namelen = HFSPLUS_MAX_STRLEN;
@@ -263,11 +262,11 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
                return 0;
        if (!(*flags & MS_RDONLY)) {
-               struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr;
+               struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr;
                struct hfsplus_sb_info sbi;
 
                memset(&sbi, 0, sizeof(struct hfsplus_sb_info));
-               sbi.nls = HFSPLUS_SB(sb).nls;
+               sbi.nls = HFSPLUS_SB(sb)->nls;
                if (!hfsplus_parse_options(data, &sbi))
                        return -EINVAL;
 
@@ -276,7 +275,7 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
                               "running fsck.hfsplus is recommended.  leaving read-only.\n");
                        sb->s_flags |= MS_RDONLY;
                        *flags |= MS_RDONLY;
-               } else if (sbi.flags & HFSPLUS_SB_FORCE) {
+               } else if (test_bit(HFSPLUS_SB_FORCE, &sbi.flags)) {
                        /* nothing */
                } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
                        printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n");
@@ -320,7 +319,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
 
        sb->s_fs_info = sbi;
-       INIT_HLIST_HEAD(&sbi->rsrc_inodes);
+       mutex_init(&sbi->alloc_mutex);
+       mutex_init(&sbi->vh_mutex);
        hfsplus_fill_defaults(sbi);
        if (!hfsplus_parse_options(data, sbi)) {
                printk(KERN_ERR "hfs: unable to parse mount options\n");
@@ -344,7 +344,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                err = -EINVAL;
                goto cleanup;
        }
-       vhdr = HFSPLUS_SB(sb).s_vhdr;
+       vhdr = sbi->s_vhdr;
 
        /* Copy parts of the volume header into the superblock */
        sb->s_magic = HFSPLUS_VOLHEAD_SIG;
@@ -353,18 +353,19 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                printk(KERN_ERR "hfs: wrong filesystem version\n");
                goto cleanup;
        }
-       HFSPLUS_SB(sb).total_blocks = be32_to_cpu(vhdr->total_blocks);
-       HFSPLUS_SB(sb).free_blocks = be32_to_cpu(vhdr->free_blocks);
-       HFSPLUS_SB(sb).next_alloc = be32_to_cpu(vhdr->next_alloc);
-       HFSPLUS_SB(sb).next_cnid = be32_to_cpu(vhdr->next_cnid);
-       HFSPLUS_SB(sb).file_count = be32_to_cpu(vhdr->file_count);
-       HFSPLUS_SB(sb).folder_count = be32_to_cpu(vhdr->folder_count);
-       HFSPLUS_SB(sb).data_clump_blocks = be32_to_cpu(vhdr->data_clump_sz) >> HFSPLUS_SB(sb).alloc_blksz_shift;
-       if (!HFSPLUS_SB(sb).data_clump_blocks)
-               HFSPLUS_SB(sb).data_clump_blocks = 1;
-       HFSPLUS_SB(sb).rsrc_clump_blocks = be32_to_cpu(vhdr->rsrc_clump_sz) >> HFSPLUS_SB(sb).alloc_blksz_shift;
-       if (!HFSPLUS_SB(sb).rsrc_clump_blocks)
-               HFSPLUS_SB(sb).rsrc_clump_blocks = 1;
+       sbi->total_blocks = be32_to_cpu(vhdr->total_blocks);
+       sbi->free_blocks = be32_to_cpu(vhdr->free_blocks);
+       sbi->next_cnid = be32_to_cpu(vhdr->next_cnid);
+       sbi->file_count = be32_to_cpu(vhdr->file_count);
+       sbi->folder_count = be32_to_cpu(vhdr->folder_count);
+       sbi->data_clump_blocks =
+               be32_to_cpu(vhdr->data_clump_sz) >> sbi->alloc_blksz_shift;
+       if (!sbi->data_clump_blocks)
+               sbi->data_clump_blocks = 1;
+       sbi->rsrc_clump_blocks =
+               be32_to_cpu(vhdr->rsrc_clump_sz) >> sbi->alloc_blksz_shift;
+       if (!sbi->rsrc_clump_blocks)
+               sbi->rsrc_clump_blocks = 1;
 
        /* Set up operations so we can load metadata */
        sb->s_op = &hfsplus_sops;
@@ -374,7 +375,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, "
                       "running fsck.hfsplus is recommended.  mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
-       } else if (sbi->flags & HFSPLUS_SB_FORCE) {
+       } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) {
                /* nothing */
        } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
                printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n");
@@ -384,16 +385,15 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                       "use the force option at your own risk, mounting read-only.\n");
                sb->s_flags |= MS_RDONLY;
        }
-       sbi->flags &= ~HFSPLUS_SB_FORCE;
 
        /* Load metadata objects (B*Trees) */
-       HFSPLUS_SB(sb).ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
-       if (!HFSPLUS_SB(sb).ext_tree) {
+       sbi->ext_tree = hfs_btree_open(sb, HFSPLUS_EXT_CNID);
+       if (!sbi->ext_tree) {
                printk(KERN_ERR "hfs: failed to load extents file\n");
                goto cleanup;
        }
-       HFSPLUS_SB(sb).cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID);
-       if (!HFSPLUS_SB(sb).cat_tree) {
+       sbi->cat_tree = hfs_btree_open(sb, HFSPLUS_CAT_CNID);
+       if (!sbi->cat_tree) {
                printk(KERN_ERR "hfs: failed to load catalog file\n");
                goto cleanup;
        }
@@ -404,7 +404,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                err = PTR_ERR(inode);
                goto cleanup;
        }
-       HFSPLUS_SB(sb).alloc_file = inode;
+       sbi->alloc_file = inode;
 
        /* Load the root directory */
        root = hfsplus_iget(sb, HFSPLUS_ROOT_CNID);
@@ -423,7 +423,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
 
        str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1;
        str.name = HFSP_HIDDENDIR_NAME;
-       hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
+       hfs_find_init(sbi->cat_tree, &fd);
        hfsplus_cat_build_key(sb, fd.search_key, HFSPLUS_ROOT_CNID, &str);
        if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
                hfs_find_exit(&fd);
@@ -434,7 +434,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
                        err = PTR_ERR(inode);
                        goto cleanup;
                }
-               HFSPLUS_SB(sb).hidden_dir = inode;
+               sbi->hidden_dir = inode;
        } else
                hfs_find_exit(&fd);
 
@@ -449,15 +449,19 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
        be32_add_cpu(&vhdr->write_count, 1);
        vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
        vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
-       mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
-       sync_dirty_buffer(HFSPLUS_SB(sb).s_vhbh);
+       mark_buffer_dirty(sbi->s_vhbh);
+       sync_dirty_buffer(sbi->s_vhbh);
 
-       if (!HFSPLUS_SB(sb).hidden_dir) {
+       if (!sbi->hidden_dir) {
                printk(KERN_DEBUG "hfs: create hidden dir...\n");
-               HFSPLUS_SB(sb).hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
-               hfsplus_create_cat(HFSPLUS_SB(sb).hidden_dir->i_ino, sb->s_root->d_inode,
-                                  &str, HFSPLUS_SB(sb).hidden_dir);
-               mark_inode_dirty(HFSPLUS_SB(sb).hidden_dir);
+
+               mutex_lock(&sbi->vh_mutex);
+               sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
+               hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode,
+                                  &str, sbi->hidden_dir);
+               mutex_unlock(&sbi->vh_mutex);
+
+               mark_inode_dirty(sbi->hidden_dir);
        }
 out:
        unload_nls(sbi->nls);
@@ -486,7 +490,7 @@ static struct inode *hfsplus_alloc_inode(struct super_block *sb)
 
 static void hfsplus_destroy_inode(struct inode *inode)
 {
-       kmem_cache_free(hfsplus_inode_cachep, &HFSPLUS_I(inode));
+       kmem_cache_free(hfsplus_inode_cachep, HFSPLUS_I(inode));
 }
 
 #define HFSPLUS_INODE_SIZE     sizeof(struct hfsplus_inode_info)
index 628ccf6fa402500aa15d7d53969b0f62b6ea5188..b66d67de882c3d098d661f54cbc2b19983bab32b 100644 (file)
@@ -121,7 +121,7 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
 int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p)
 {
        const hfsplus_unichr *ip;
-       struct nls_table *nls = HFSPLUS_SB(sb).nls;
+       struct nls_table *nls = HFSPLUS_SB(sb)->nls;
        u8 *op;
        u16 cc, c0, c1;
        u16 *ce1, *ce2;
@@ -132,7 +132,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c
        ustrlen = be16_to_cpu(ustr->length);
        len = *len_p;
        ce1 = NULL;
-       compose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+       compose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
 
        while (ustrlen > 0) {
                c0 = be16_to_cpu(*ip++);
@@ -246,7 +246,7 @@ out:
 static inline int asc2unichar(struct super_block *sb, const char *astr, int len,
                              wchar_t *uc)
 {
-       int size = HFSPLUS_SB(sb).nls->char2uni(astr, len, uc);
+       int size = HFSPLUS_SB(sb)->nls->char2uni(astr, len, uc);
        if (size <= 0) {
                *uc = '?';
                size = 1;
@@ -293,7 +293,7 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
        u16 *dstr, outlen = 0;
        wchar_t c;
 
-       decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+       decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
        while (outlen < HFSPLUS_MAX_STRLEN && len > 0) {
                size = asc2unichar(sb, astr, len, &c);
 
@@ -330,8 +330,8 @@ int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str)
        wchar_t c;
        u16 c2;
 
-       casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD);
-       decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+       casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
+       decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
        hash = init_name_hash();
        astr = str->name;
        len = str->len;
@@ -373,8 +373,8 @@ int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *
        u16 c1, c2;
        wchar_t c;
 
-       casefold = (HFSPLUS_SB(sb).flags & HFSPLUS_SB_CASEFOLD);
-       decompose = !(HFSPLUS_SB(sb).flags & HFSPLUS_SB_NODECOMPOSE);
+       casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
+       decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags);
        astr1 = s1->name;
        len1 = s1->len;
        astr2 = s2->name;
index bed78ac8f6d1f5e530a93c0afac22e1cfdf2178a..8972c20b3216941a88eb3deffa591d89ea3c114a 100644 (file)
@@ -65,8 +65,8 @@ static int hfsplus_get_last_session(struct super_block *sb,
        *start = 0;
        *size = sb->s_bdev->bd_inode->i_size >> 9;
 
-       if (HFSPLUS_SB(sb).session >= 0) {
-               te.cdte_track = HFSPLUS_SB(sb).session;
+       if (HFSPLUS_SB(sb)->session >= 0) {
+               te.cdte_track = HFSPLUS_SB(sb)->session;
                te.cdte_format = CDROM_LBA;
                res = ioctl_by_bdev(sb->s_bdev, CDROMREADTOCENTRY, (unsigned long)&te);
                if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) {
@@ -87,6 +87,7 @@ static int hfsplus_get_last_session(struct super_block *sb,
 /* Takes in super block, returns true if good data read */
 int hfsplus_read_wrapper(struct super_block *sb)
 {
+       struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
        struct buffer_head *bh;
        struct hfsplus_vh *vhdr;
        struct hfsplus_wd wd;
@@ -122,7 +123,7 @@ int hfsplus_read_wrapper(struct super_block *sb)
                if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
                        break;
                if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) {
-                       HFSPLUS_SB(sb).flags |= HFSPLUS_SB_HFSX;
+                       set_bit(HFSPLUS_SB_HFSX, &sbi->flags);
                        break;
                }
                brelse(bh);
@@ -143,11 +144,11 @@ int hfsplus_read_wrapper(struct super_block *sb)
        if (blocksize < HFSPLUS_SECTOR_SIZE ||
            ((blocksize - 1) & blocksize))
                return -EINVAL;
-       HFSPLUS_SB(sb).alloc_blksz = blocksize;
-       HFSPLUS_SB(sb).alloc_blksz_shift = 0;
+       sbi->alloc_blksz = blocksize;
+       sbi->alloc_blksz_shift = 0;
        while ((blocksize >>= 1) != 0)
-               HFSPLUS_SB(sb).alloc_blksz_shift++;
-       blocksize = min(HFSPLUS_SB(sb).alloc_blksz, (u32)PAGE_SIZE);
+               sbi->alloc_blksz_shift++;
+       blocksize = min(sbi->alloc_blksz, (u32)PAGE_SIZE);
 
        /* align block size to block offset */
        while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1))
@@ -158,23 +159,26 @@ int hfsplus_read_wrapper(struct super_block *sb)
                return -EINVAL;
        }
 
-       HFSPLUS_SB(sb).blockoffset = part_start >>
-                       (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT);
-       HFSPLUS_SB(sb).sect_count = part_size;
-       HFSPLUS_SB(sb).fs_shift = HFSPLUS_SB(sb).alloc_blksz_shift -
-                       sb->s_blocksize_bits;
+       sbi->blockoffset =
+               part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT);
+       sbi->sect_count = part_size;
+       sbi->fs_shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits;
 
        bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr);
        if (!bh)
                return -EIO;
 
        /* should still be the same... */
-       if (vhdr->signature != (HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX ?
-                               cpu_to_be16(HFSPLUS_VOLHEAD_SIGX) :
-                               cpu_to_be16(HFSPLUS_VOLHEAD_SIG)))
-               goto error;
-       HFSPLUS_SB(sb).s_vhbh = bh;
-       HFSPLUS_SB(sb).s_vhdr = vhdr;
+       if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) {
+               if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX))
+                       goto error;
+       } else {
+               if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIG))
+                       goto error;
+       }
+
+       sbi->s_vhbh = bh;
+       sbi->s_vhdr = vhdr;
 
        return 0;
  error:
index 0e8014ea6b94ad8985f1b0b842f2cea550578e67..262419f83d800bfb6e4bbfb0ca93e3af2c3f64be 100644 (file)
@@ -1371,6 +1371,10 @@ int jbd2_journal_check_used_features (journal_t *journal, unsigned long compat,
 
        if (!compat && !ro && !incompat)
                return 1;
+       /* Load journal superblock if it is not loaded yet. */
+       if (journal->j_format_version == 0 &&
+           journal_get_superblock(journal) != 0)
+               return 0;
        if (journal->j_format_version == 1)
                return 0;
 
index 0a9da95317f76a6ffdebb9120a3e71dc0ff4cf72..62baa0387d6e03869e726b89ffaddccce4fc090c 100644 (file)
@@ -913,6 +913,35 @@ int generic_file_fsync(struct file *file, int datasync)
 }
 EXPORT_SYMBOL(generic_file_fsync);
 
+/**
+ * generic_check_addressable - Check addressability of file system
+ * @blocksize_bits:    log of file system block size
+ * @num_blocks:                number of blocks in file system
+ *
+ * Determine whether a file system with @num_blocks blocks (and a
+ * block size of 2**@blocksize_bits) is addressable by the sector_t
+ * and page cache of the system.  Return 0 if so and -EFBIG otherwise.
+ */
+int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks)
+{
+       u64 last_fs_block = num_blocks - 1;
+       u64 last_fs_page =
+               last_fs_block >> (PAGE_CACHE_SHIFT - blocksize_bits);
+
+       if (unlikely(num_blocks == 0))
+               return 0;
+
+       if ((blocksize_bits < 9) || (blocksize_bits > PAGE_CACHE_SHIFT))
+               return -EINVAL;
+
+       if ((last_fs_block > (sector_t)(~0ULL) >> (blocksize_bits - 9)) ||
+           (last_fs_page > (pgoff_t)(~0ULL))) {
+               return -EFBIG;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(generic_check_addressable);
+
 /*
  * No-op implementation of ->fsync for in-memory filesystems.
  */
index 0de69c9a08be0e4732925f9cd049fc927b6bb851..5cfeee11815881b04a3250d42a72838e40289200 100644 (file)
@@ -883,8 +883,8 @@ struct ocfs2_write_ctxt {
         * out in so that future reads from that region will get
         * zero's.
         */
-       struct page                     *w_pages[OCFS2_MAX_CTXT_PAGES];
        unsigned int                    w_num_pages;
+       struct page                     *w_pages[OCFS2_MAX_CTXT_PAGES];
        struct page                     *w_target_page;
 
        /*
@@ -1642,7 +1642,8 @@ static int ocfs2_zero_tail(struct inode *inode, struct buffer_head *di_bh,
        return ret;
 }
 
-int ocfs2_write_begin_nolock(struct address_space *mapping,
+int ocfs2_write_begin_nolock(struct file *filp,
+                            struct address_space *mapping,
                             loff_t pos, unsigned len, unsigned flags,
                             struct page **pagep, void **fsdata,
                             struct buffer_head *di_bh, struct page *mmap_page)
@@ -1692,7 +1693,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
                mlog_errno(ret);
                goto out;
        } else if (ret == 1) {
-               ret = ocfs2_refcount_cow(inode, di_bh,
+               ret = ocfs2_refcount_cow(inode, filp, di_bh,
                                         wc->w_cpos, wc->w_clen, UINT_MAX);
                if (ret) {
                        mlog_errno(ret);
@@ -1854,7 +1855,7 @@ static int ocfs2_write_begin(struct file *file, struct address_space *mapping,
         */
        down_write(&OCFS2_I(inode)->ip_alloc_sem);
 
-       ret = ocfs2_write_begin_nolock(mapping, pos, len, flags, pagep,
+       ret = ocfs2_write_begin_nolock(file, mapping, pos, len, flags, pagep,
                                       fsdata, di_bh, NULL);
        if (ret) {
                mlog_errno(ret);
index c48e93ffc513025b737ea38d59b63a886c0b0b88..7606f663da6d1e1181dac172736ed9dfbbb3fd84 100644 (file)
@@ -48,7 +48,8 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
                           loff_t pos, unsigned len, unsigned copied,
                           struct page *page, void *fsdata);
 
-int ocfs2_write_begin_nolock(struct address_space *mapping,
+int ocfs2_write_begin_nolock(struct file *filp,
+                            struct address_space *mapping,
                             loff_t pos, unsigned len, unsigned flags,
                             struct page **pagep, void **fsdata,
                             struct buffer_head *di_bh, struct page *mmap_page);
index 41d5f1f92d56f60a45f6066d875598bda7caddf2..52c7557f3e25ad4cce288883ed070eb48f970a4e 100644 (file)
@@ -62,10 +62,51 @@ static unsigned long o2hb_live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
 static LIST_HEAD(o2hb_node_events);
 static DECLARE_WAIT_QUEUE_HEAD(o2hb_steady_queue);
 
+/*
+ * In global heartbeat, we maintain a series of region bitmaps.
+ *     - o2hb_region_bitmap allows us to limit the region number to max region.
+ *     - o2hb_live_region_bitmap tracks live regions (seen steady iterations).
+ *     - o2hb_quorum_region_bitmap tracks live regions that have seen all nodes
+ *             heartbeat on it.
+ *     - o2hb_failed_region_bitmap tracks the regions that have seen io timeouts.
+ */
+static unsigned long o2hb_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)];
+static unsigned long o2hb_live_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)];
+static unsigned long o2hb_quorum_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)];
+static unsigned long o2hb_failed_region_bitmap[BITS_TO_LONGS(O2NM_MAX_REGIONS)];
+
+#define O2HB_DB_TYPE_LIVENODES         0
+#define O2HB_DB_TYPE_LIVEREGIONS       1
+#define O2HB_DB_TYPE_QUORUMREGIONS     2
+#define O2HB_DB_TYPE_FAILEDREGIONS     3
+#define O2HB_DB_TYPE_REGION_LIVENODES  4
+#define O2HB_DB_TYPE_REGION_NUMBER     5
+#define O2HB_DB_TYPE_REGION_ELAPSED_TIME       6
+struct o2hb_debug_buf {
+       int db_type;
+       int db_size;
+       int db_len;
+       void *db_data;
+};
+
+static struct o2hb_debug_buf *o2hb_db_livenodes;
+static struct o2hb_debug_buf *o2hb_db_liveregions;
+static struct o2hb_debug_buf *o2hb_db_quorumregions;
+static struct o2hb_debug_buf *o2hb_db_failedregions;
+
 #define O2HB_DEBUG_DIR                 "o2hb"
 #define O2HB_DEBUG_LIVENODES           "livenodes"
+#define O2HB_DEBUG_LIVEREGIONS         "live_regions"
+#define O2HB_DEBUG_QUORUMREGIONS       "quorum_regions"
+#define O2HB_DEBUG_FAILEDREGIONS       "failed_regions"
+#define O2HB_DEBUG_REGION_NUMBER       "num"
+#define O2HB_DEBUG_REGION_ELAPSED_TIME "elapsed_time_in_ms"
+
 static struct dentry *o2hb_debug_dir;
 static struct dentry *o2hb_debug_livenodes;
+static struct dentry *o2hb_debug_liveregions;
+static struct dentry *o2hb_debug_quorumregions;
+static struct dentry *o2hb_debug_failedregions;
 
 static LIST_HEAD(o2hb_all_regions);
 
@@ -77,7 +118,19 @@ static struct o2hb_callback *hbcall_from_type(enum o2hb_callback_type type);
 
 #define O2HB_DEFAULT_BLOCK_BITS       9
 
+enum o2hb_heartbeat_modes {
+       O2HB_HEARTBEAT_LOCAL            = 0,
+       O2HB_HEARTBEAT_GLOBAL,
+       O2HB_HEARTBEAT_NUM_MODES,
+};
+
+char *o2hb_heartbeat_mode_desc[O2HB_HEARTBEAT_NUM_MODES] = {
+               "local",        /* O2HB_HEARTBEAT_LOCAL */
+               "global",       /* O2HB_HEARTBEAT_GLOBAL */
+};
+
 unsigned int o2hb_dead_threshold = O2HB_DEFAULT_DEAD_THRESHOLD;
+unsigned int o2hb_heartbeat_mode = O2HB_HEARTBEAT_LOCAL;
 
 /* Only sets a new threshold if there are no active regions.
  *
@@ -94,6 +147,22 @@ static void o2hb_dead_threshold_set(unsigned int threshold)
        }
 }
 
+static int o2hb_global_hearbeat_mode_set(unsigned int hb_mode)
+{
+       int ret = -1;
+
+       if (hb_mode < O2HB_HEARTBEAT_NUM_MODES) {
+               spin_lock(&o2hb_live_lock);
+               if (list_empty(&o2hb_all_regions)) {
+                       o2hb_heartbeat_mode = hb_mode;
+                       ret = 0;
+               }
+               spin_unlock(&o2hb_live_lock);
+       }
+
+       return ret;
+}
+
 struct o2hb_node_event {
        struct list_head        hn_item;
        enum o2hb_callback_type hn_event_type;
@@ -135,6 +204,18 @@ struct o2hb_region {
        struct block_device     *hr_bdev;
        struct o2hb_disk_slot   *hr_slots;
 
+       /* live node map of this region */
+       unsigned long           hr_live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
+       unsigned int            hr_region_num;
+
+       struct dentry           *hr_debug_dir;
+       struct dentry           *hr_debug_livenodes;
+       struct dentry           *hr_debug_regnum;
+       struct dentry           *hr_debug_elapsed_time;
+       struct o2hb_debug_buf   *hr_db_livenodes;
+       struct o2hb_debug_buf   *hr_db_regnum;
+       struct o2hb_debug_buf   *hr_db_elapsed_time;
+
        /* let the person setting up hb wait for it to return until it
         * has reached a 'steady' state.  This will be fixed when we have
         * a more complete api that doesn't lead to this sort of fragility. */
@@ -163,8 +244,19 @@ struct o2hb_bio_wait_ctxt {
        int               wc_error;
 };
 
+static int o2hb_pop_count(void *map, int count)
+{
+       int i = -1, pop = 0;
+
+       while ((i = find_next_bit(map, count, i + 1)) < count)
+               pop++;
+       return pop;
+}
+
 static void o2hb_write_timeout(struct work_struct *work)
 {
+       int failed, quorum;
+       unsigned long flags;
        struct o2hb_region *reg =
                container_of(work, struct o2hb_region,
                             hr_write_timeout_work.work);
@@ -172,6 +264,28 @@ static void o2hb_write_timeout(struct work_struct *work)
        mlog(ML_ERROR, "Heartbeat write timeout to device %s after %u "
             "milliseconds\n", reg->hr_dev_name,
             jiffies_to_msecs(jiffies - reg->hr_last_timeout_start));
+
+       if (o2hb_global_heartbeat_active()) {
+               spin_lock_irqsave(&o2hb_live_lock, flags);
+               if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap))
+                       set_bit(reg->hr_region_num, o2hb_failed_region_bitmap);
+               failed = o2hb_pop_count(&o2hb_failed_region_bitmap,
+                                       O2NM_MAX_REGIONS);
+               quorum = o2hb_pop_count(&o2hb_quorum_region_bitmap,
+                                       O2NM_MAX_REGIONS);
+               spin_unlock_irqrestore(&o2hb_live_lock, flags);
+
+               mlog(ML_HEARTBEAT, "Number of regions %d, failed regions %d\n",
+                    quorum, failed);
+
+               /*
+                * Fence if the number of failed regions >= half the number
+                * of  quorum regions
+                */
+               if ((failed << 1) < quorum)
+                       return;
+       }
+
        o2quo_disk_timeout();
 }
 
@@ -180,6 +294,11 @@ static void o2hb_arm_write_timeout(struct o2hb_region *reg)
        mlog(ML_HEARTBEAT, "Queue write timeout for %u ms\n",
             O2HB_MAX_WRITE_TIMEOUT_MS);
 
+       if (o2hb_global_heartbeat_active()) {
+               spin_lock(&o2hb_live_lock);
+               clear_bit(reg->hr_region_num, o2hb_failed_region_bitmap);
+               spin_unlock(&o2hb_live_lock);
+       }
        cancel_delayed_work(&reg->hr_write_timeout_work);
        reg->hr_last_timeout_start = jiffies;
        schedule_delayed_work(&reg->hr_write_timeout_work,
@@ -513,6 +632,8 @@ static void o2hb_queue_node_event(struct o2hb_node_event *event,
 {
        assert_spin_locked(&o2hb_live_lock);
 
+       BUG_ON((!node) && (type != O2HB_NODE_DOWN_CB));
+
        event->hn_event_type = type;
        event->hn_node = node;
        event->hn_node_num = node_num;
@@ -554,6 +675,35 @@ static void o2hb_shutdown_slot(struct o2hb_disk_slot *slot)
        o2nm_node_put(node);
 }
 
+static void o2hb_set_quorum_device(struct o2hb_region *reg,
+                                  struct o2hb_disk_slot *slot)
+{
+       assert_spin_locked(&o2hb_live_lock);
+
+       if (!o2hb_global_heartbeat_active())
+               return;
+
+       if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap))
+               return;
+
+       /*
+        * A region can be added to the quorum only when it sees all
+        * live nodes heartbeat on it. In other words, the region has been
+        * added to all nodes.
+        */
+       if (memcmp(reg->hr_live_node_bitmap, o2hb_live_node_bitmap,
+                  sizeof(o2hb_live_node_bitmap)))
+               return;
+
+       if (slot->ds_changed_samples < O2HB_LIVE_THRESHOLD)
+               return;
+
+       printk(KERN_NOTICE "o2hb: Region %s is now a quorum device\n",
+              config_item_name(&reg->hr_item));
+
+       set_bit(reg->hr_region_num, o2hb_quorum_region_bitmap);
+}
+
 static int o2hb_check_slot(struct o2hb_region *reg,
                           struct o2hb_disk_slot *slot)
 {
@@ -565,14 +715,22 @@ static int o2hb_check_slot(struct o2hb_region *reg,
        u64 cputime;
        unsigned int dead_ms = o2hb_dead_threshold * O2HB_REGION_TIMEOUT_MS;
        unsigned int slot_dead_ms;
+       int tmp;
 
        memcpy(hb_block, slot->ds_raw_block, reg->hr_block_bytes);
 
-       /* Is this correct? Do we assume that the node doesn't exist
-        * if we're not configured for him? */
+       /*
+        * If a node is no longer configured but is still in the livemap, we
+        * may need to clear that bit from the livemap.
+        */
        node = o2nm_get_node_by_num(slot->ds_node_num);
-       if (!node)
-               return 0;
+       if (!node) {
+               spin_lock(&o2hb_live_lock);
+               tmp = test_bit(slot->ds_node_num, o2hb_live_node_bitmap);
+               spin_unlock(&o2hb_live_lock);
+               if (!tmp)
+                       return 0;
+       }
 
        if (!o2hb_verify_crc(reg, hb_block)) {
                /* all paths from here will drop o2hb_live_lock for
@@ -639,8 +797,12 @@ fire_callbacks:
                mlog(ML_HEARTBEAT, "Node %d (id 0x%llx) joined my region\n",
                     slot->ds_node_num, (long long)slot->ds_last_generation);
 
+               set_bit(slot->ds_node_num, reg->hr_live_node_bitmap);
+
                /* first on the list generates a callback */
                if (list_empty(&o2hb_live_slots[slot->ds_node_num])) {
+                       mlog(ML_HEARTBEAT, "o2hb: Add node %d to live nodes "
+                            "bitmap\n", slot->ds_node_num);
                        set_bit(slot->ds_node_num, o2hb_live_node_bitmap);
 
                        o2hb_queue_node_event(&event, O2HB_NODE_UP_CB, node,
@@ -684,13 +846,18 @@ fire_callbacks:
                mlog(ML_HEARTBEAT, "Node %d left my region\n",
                     slot->ds_node_num);
 
+               clear_bit(slot->ds_node_num, reg->hr_live_node_bitmap);
+
                /* last off the live_slot generates a callback */
                list_del_init(&slot->ds_live_item);
                if (list_empty(&o2hb_live_slots[slot->ds_node_num])) {
+                       mlog(ML_HEARTBEAT, "o2hb: Remove node %d from live "
+                            "nodes bitmap\n", slot->ds_node_num);
                        clear_bit(slot->ds_node_num, o2hb_live_node_bitmap);
 
-                       o2hb_queue_node_event(&event, O2HB_NODE_DOWN_CB, node,
-                                             slot->ds_node_num);
+                       /* node can be null */
+                       o2hb_queue_node_event(&event, O2HB_NODE_DOWN_CB,
+                                             node, slot->ds_node_num);
 
                        changed = 1;
                }
@@ -706,11 +873,14 @@ fire_callbacks:
                slot->ds_equal_samples = 0;
        }
 out:
+       o2hb_set_quorum_device(reg, slot);
+
        spin_unlock(&o2hb_live_lock);
 
        o2hb_run_event_list(&event);
 
-       o2nm_node_put(node);
+       if (node)
+               o2nm_node_put(node);
        return changed;
 }
 
@@ -737,6 +907,7 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
 {
        int i, ret, highest_node, change = 0;
        unsigned long configured_nodes[BITS_TO_LONGS(O2NM_MAX_NODES)];
+       unsigned long live_node_bitmap[BITS_TO_LONGS(O2NM_MAX_NODES)];
        struct o2hb_bio_wait_ctxt write_wc;
 
        ret = o2nm_configured_node_map(configured_nodes,
@@ -746,6 +917,17 @@ static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
                return ret;
        }
 
+       /*
+        * If a node is not configured but is in the livemap, we still need
+        * to read the slot so as to be able to remove it from the livemap.
+        */
+       o2hb_fill_node_map(live_node_bitmap, sizeof(live_node_bitmap));
+       i = -1;
+       while ((i = find_next_bit(live_node_bitmap,
+                                 O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES) {
+               set_bit(i, configured_nodes);
+       }
+
        highest_node = o2hb_highest_node(configured_nodes, O2NM_MAX_NODES);
        if (highest_node >= O2NM_MAX_NODES) {
                mlog(ML_NOTICE, "ocfs2_heartbeat: no configured nodes found!\n");
@@ -917,21 +1099,59 @@ static int o2hb_thread(void *data)
 #ifdef CONFIG_DEBUG_FS
 static int o2hb_debug_open(struct inode *inode, struct file *file)
 {
+       struct o2hb_debug_buf *db = inode->i_private;
+       struct o2hb_region *reg;
        unsigned long map[BITS_TO_LONGS(O2NM_MAX_NODES)];
        char *buf = NULL;
        int i = -1;
        int out = 0;
 
+       /* max_nodes should be the largest bitmap we pass here */
+       BUG_ON(sizeof(map) < db->db_size);
+
        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
        if (!buf)
                goto bail;
 
-       o2hb_fill_node_map(map, sizeof(map));
+       switch (db->db_type) {
+       case O2HB_DB_TYPE_LIVENODES:
+       case O2HB_DB_TYPE_LIVEREGIONS:
+       case O2HB_DB_TYPE_QUORUMREGIONS:
+       case O2HB_DB_TYPE_FAILEDREGIONS:
+               spin_lock(&o2hb_live_lock);
+               memcpy(map, db->db_data, db->db_size);
+               spin_unlock(&o2hb_live_lock);
+               break;
+
+       case O2HB_DB_TYPE_REGION_LIVENODES:
+               spin_lock(&o2hb_live_lock);
+               reg = (struct o2hb_region *)db->db_data;
+               memcpy(map, reg->hr_live_node_bitmap, db->db_size);
+               spin_unlock(&o2hb_live_lock);
+               break;
+
+       case O2HB_DB_TYPE_REGION_NUMBER:
+               reg = (struct o2hb_region *)db->db_data;
+               out += snprintf(buf + out, PAGE_SIZE - out, "%d\n",
+                               reg->hr_region_num);
+               goto done;
+
+       case O2HB_DB_TYPE_REGION_ELAPSED_TIME:
+               reg = (struct o2hb_region *)db->db_data;
+               out += snprintf(buf + out, PAGE_SIZE - out, "%u\n",
+                               jiffies_to_msecs(jiffies -
+                                                reg->hr_last_timeout_start));
+               goto done;
+
+       default:
+               goto done;
+       }
 
-       while ((i = find_next_bit(map, O2NM_MAX_NODES, i + 1)) < O2NM_MAX_NODES)
+       while ((i = find_next_bit(map, db->db_len, i + 1)) < db->db_len)
                out += snprintf(buf + out, PAGE_SIZE - out, "%d ", i);
        out += snprintf(buf + out, PAGE_SIZE - out, "\n");
 
+done:
        i_size_write(inode, out);
 
        file->private_data = buf;
@@ -978,10 +1198,104 @@ static const struct file_operations o2hb_debug_fops = {
 
 void o2hb_exit(void)
 {
-       if (o2hb_debug_livenodes)
-               debugfs_remove(o2hb_debug_livenodes);
-       if (o2hb_debug_dir)
-               debugfs_remove(o2hb_debug_dir);
+       kfree(o2hb_db_livenodes);
+       kfree(o2hb_db_liveregions);
+       kfree(o2hb_db_quorumregions);
+       kfree(o2hb_db_failedregions);
+       debugfs_remove(o2hb_debug_failedregions);
+       debugfs_remove(o2hb_debug_quorumregions);
+       debugfs_remove(o2hb_debug_liveregions);
+       debugfs_remove(o2hb_debug_livenodes);
+       debugfs_remove(o2hb_debug_dir);
+}
+
+static struct dentry *o2hb_debug_create(const char *name, struct dentry *dir,
+                                       struct o2hb_debug_buf **db, int db_len,
+                                       int type, int size, int len, void *data)
+{
+       *db = kmalloc(db_len, GFP_KERNEL);
+       if (!*db)
+               return NULL;
+
+       (*db)->db_type = type;
+       (*db)->db_size = size;
+       (*db)->db_len = len;
+       (*db)->db_data = data;
+
+       return debugfs_create_file(name, S_IFREG|S_IRUSR, dir, *db,
+                                  &o2hb_debug_fops);
+}
+
+static int o2hb_debug_init(void)
+{
+       int ret = -ENOMEM;
+
+       o2hb_debug_dir = debugfs_create_dir(O2HB_DEBUG_DIR, NULL);
+       if (!o2hb_debug_dir) {
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       o2hb_debug_livenodes = o2hb_debug_create(O2HB_DEBUG_LIVENODES,
+                                                o2hb_debug_dir,
+                                                &o2hb_db_livenodes,
+                                                sizeof(*o2hb_db_livenodes),
+                                                O2HB_DB_TYPE_LIVENODES,
+                                                sizeof(o2hb_live_node_bitmap),
+                                                O2NM_MAX_NODES,
+                                                o2hb_live_node_bitmap);
+       if (!o2hb_debug_livenodes) {
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       o2hb_debug_liveregions = o2hb_debug_create(O2HB_DEBUG_LIVEREGIONS,
+                                                  o2hb_debug_dir,
+                                                  &o2hb_db_liveregions,
+                                                  sizeof(*o2hb_db_liveregions),
+                                                  O2HB_DB_TYPE_LIVEREGIONS,
+                                                  sizeof(o2hb_live_region_bitmap),
+                                                  O2NM_MAX_REGIONS,
+                                                  o2hb_live_region_bitmap);
+       if (!o2hb_debug_liveregions) {
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       o2hb_debug_quorumregions =
+                       o2hb_debug_create(O2HB_DEBUG_QUORUMREGIONS,
+                                         o2hb_debug_dir,
+                                         &o2hb_db_quorumregions,
+                                         sizeof(*o2hb_db_quorumregions),
+                                         O2HB_DB_TYPE_QUORUMREGIONS,
+                                         sizeof(o2hb_quorum_region_bitmap),
+                                         O2NM_MAX_REGIONS,
+                                         o2hb_quorum_region_bitmap);
+       if (!o2hb_debug_quorumregions) {
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       o2hb_debug_failedregions =
+                       o2hb_debug_create(O2HB_DEBUG_FAILEDREGIONS,
+                                         o2hb_debug_dir,
+                                         &o2hb_db_failedregions,
+                                         sizeof(*o2hb_db_failedregions),
+                                         O2HB_DB_TYPE_FAILEDREGIONS,
+                                         sizeof(o2hb_failed_region_bitmap),
+                                         O2NM_MAX_REGIONS,
+                                         o2hb_failed_region_bitmap);
+       if (!o2hb_debug_failedregions) {
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       ret = 0;
+bail:
+       if (ret)
+               o2hb_exit();
+
+       return ret;
 }
 
 int o2hb_init(void)
@@ -997,24 +1311,12 @@ int o2hb_init(void)
        INIT_LIST_HEAD(&o2hb_node_events);
 
        memset(o2hb_live_node_bitmap, 0, sizeof(o2hb_live_node_bitmap));
+       memset(o2hb_region_bitmap, 0, sizeof(o2hb_region_bitmap));
+       memset(o2hb_live_region_bitmap, 0, sizeof(o2hb_live_region_bitmap));
+       memset(o2hb_quorum_region_bitmap, 0, sizeof(o2hb_quorum_region_bitmap));
+       memset(o2hb_failed_region_bitmap, 0, sizeof(o2hb_failed_region_bitmap));
 
-       o2hb_debug_dir = debugfs_create_dir(O2HB_DEBUG_DIR, NULL);
-       if (!o2hb_debug_dir) {
-               mlog_errno(-ENOMEM);
-               return -ENOMEM;
-       }
-
-       o2hb_debug_livenodes = debugfs_create_file(O2HB_DEBUG_LIVENODES,
-                                                  S_IFREG|S_IRUSR,
-                                                  o2hb_debug_dir, NULL,
-                                                  &o2hb_debug_fops);
-       if (!o2hb_debug_livenodes) {
-               mlog_errno(-ENOMEM);
-               debugfs_remove(o2hb_debug_dir);
-               return -ENOMEM;
-       }
-
-       return 0;
+       return o2hb_debug_init();
 }
 
 /* if we're already in a callback then we're already serialized by the sem */
@@ -1078,6 +1380,13 @@ static void o2hb_region_release(struct config_item *item)
        if (reg->hr_slots)
                kfree(reg->hr_slots);
 
+       kfree(reg->hr_db_regnum);
+       kfree(reg->hr_db_livenodes);
+       debugfs_remove(reg->hr_debug_livenodes);
+       debugfs_remove(reg->hr_debug_regnum);
+       debugfs_remove(reg->hr_debug_elapsed_time);
+       debugfs_remove(reg->hr_debug_dir);
+
        spin_lock(&o2hb_live_lock);
        list_del(&reg->hr_all_item);
        spin_unlock(&o2hb_live_lock);
@@ -1441,6 +1750,8 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
        /* Ok, we were woken.  Make sure it wasn't by drop_item() */
        spin_lock(&o2hb_live_lock);
        hb_task = reg->hr_task;
+       if (o2hb_global_heartbeat_active())
+               set_bit(reg->hr_region_num, o2hb_live_region_bitmap);
        spin_unlock(&o2hb_live_lock);
 
        if (hb_task)
@@ -1448,6 +1759,10 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
        else
                ret = -EIO;
 
+       if (hb_task && o2hb_global_heartbeat_active())
+               printk(KERN_NOTICE "o2hb: Heartbeat started on region %s\n",
+                      config_item_name(&reg->hr_item));
+
 out:
        if (filp)
                fput(filp);
@@ -1586,21 +1901,94 @@ static struct o2hb_heartbeat_group *to_o2hb_heartbeat_group(struct config_group
                : NULL;
 }
 
+static int o2hb_debug_region_init(struct o2hb_region *reg, struct dentry *dir)
+{
+       int ret = -ENOMEM;
+
+       reg->hr_debug_dir =
+               debugfs_create_dir(config_item_name(&reg->hr_item), dir);
+       if (!reg->hr_debug_dir) {
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       reg->hr_debug_livenodes =
+                       o2hb_debug_create(O2HB_DEBUG_LIVENODES,
+                                         reg->hr_debug_dir,
+                                         &(reg->hr_db_livenodes),
+                                         sizeof(*(reg->hr_db_livenodes)),
+                                         O2HB_DB_TYPE_REGION_LIVENODES,
+                                         sizeof(reg->hr_live_node_bitmap),
+                                         O2NM_MAX_NODES, reg);
+       if (!reg->hr_debug_livenodes) {
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       reg->hr_debug_regnum =
+                       o2hb_debug_create(O2HB_DEBUG_REGION_NUMBER,
+                                         reg->hr_debug_dir,
+                                         &(reg->hr_db_regnum),
+                                         sizeof(*(reg->hr_db_regnum)),
+                                         O2HB_DB_TYPE_REGION_NUMBER,
+                                         0, O2NM_MAX_NODES, reg);
+       if (!reg->hr_debug_regnum) {
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       reg->hr_debug_elapsed_time =
+                       o2hb_debug_create(O2HB_DEBUG_REGION_ELAPSED_TIME,
+                                         reg->hr_debug_dir,
+                                         &(reg->hr_db_elapsed_time),
+                                         sizeof(*(reg->hr_db_elapsed_time)),
+                                         O2HB_DB_TYPE_REGION_ELAPSED_TIME,
+                                         0, 0, reg);
+       if (!reg->hr_debug_elapsed_time) {
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       ret = 0;
+bail:
+       return ret;
+}
+
 static struct config_item *o2hb_heartbeat_group_make_item(struct config_group *group,
                                                          const char *name)
 {
        struct o2hb_region *reg = NULL;
+       int ret;
 
        reg = kzalloc(sizeof(struct o2hb_region), GFP_KERNEL);
        if (reg == NULL)
                return ERR_PTR(-ENOMEM);
 
-       config_item_init_type_name(&reg->hr_item, name, &o2hb_region_type);
+       if (strlen(name) > O2HB_MAX_REGION_NAME_LEN)
+               return ERR_PTR(-ENAMETOOLONG);
 
        spin_lock(&o2hb_live_lock);
+       reg->hr_region_num = 0;
+       if (o2hb_global_heartbeat_active()) {
+               reg->hr_region_num = find_first_zero_bit(o2hb_region_bitmap,
+                                                        O2NM_MAX_REGIONS);
+               if (reg->hr_region_num >= O2NM_MAX_REGIONS) {
+                       spin_unlock(&o2hb_live_lock);
+                       return ERR_PTR(-EFBIG);
+               }
+               set_bit(reg->hr_region_num, o2hb_region_bitmap);
+       }
        list_add_tail(&reg->hr_all_item, &o2hb_all_regions);
        spin_unlock(&o2hb_live_lock);
 
+       config_item_init_type_name(&reg->hr_item, name, &o2hb_region_type);
+
+       ret = o2hb_debug_region_init(reg, o2hb_debug_dir);
+       if (ret) {
+               config_item_put(&reg->hr_item);
+               return ERR_PTR(ret);
+       }
+
        return &reg->hr_item;
 }
 
@@ -1612,6 +2000,10 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
 
        /* stop the thread when the user removes the region dir */
        spin_lock(&o2hb_live_lock);
+       if (o2hb_global_heartbeat_active()) {
+               clear_bit(reg->hr_region_num, o2hb_region_bitmap);
+               clear_bit(reg->hr_region_num, o2hb_live_region_bitmap);
+       }
        hb_task = reg->hr_task;
        reg->hr_task = NULL;
        spin_unlock(&o2hb_live_lock);
@@ -1628,6 +2020,9 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
                wake_up(&o2hb_steady_queue);
        }
 
+       if (o2hb_global_heartbeat_active())
+               printk(KERN_NOTICE "o2hb: Heartbeat stopped on region %s\n",
+                      config_item_name(&reg->hr_item));
        config_item_put(item);
 }
 
@@ -1688,6 +2083,41 @@ static ssize_t o2hb_heartbeat_group_threshold_store(struct o2hb_heartbeat_group
        return count;
 }
 
+static
+ssize_t o2hb_heartbeat_group_mode_show(struct o2hb_heartbeat_group *group,
+                                      char *page)
+{
+       return sprintf(page, "%s\n",
+                      o2hb_heartbeat_mode_desc[o2hb_heartbeat_mode]);
+}
+
+static
+ssize_t o2hb_heartbeat_group_mode_store(struct o2hb_heartbeat_group *group,
+                                       const char *page, size_t count)
+{
+       unsigned int i;
+       int ret;
+       size_t len;
+
+       len = (page[count - 1] == '\n') ? count - 1 : count;
+       if (!len)
+               return -EINVAL;
+
+       for (i = 0; i < O2HB_HEARTBEAT_NUM_MODES; ++i) {
+               if (strnicmp(page, o2hb_heartbeat_mode_desc[i], len))
+                       continue;
+
+               ret = o2hb_global_hearbeat_mode_set(i);
+               if (!ret)
+                       printk(KERN_NOTICE "o2hb: Heartbeat mode set to %s\n",
+                              o2hb_heartbeat_mode_desc[i]);
+               return count;
+       }
+
+       return -EINVAL;
+
+}
+
 static struct o2hb_heartbeat_group_attribute o2hb_heartbeat_group_attr_threshold = {
        .attr   = { .ca_owner = THIS_MODULE,
                    .ca_name = "dead_threshold",
@@ -1696,8 +2126,17 @@ static struct o2hb_heartbeat_group_attribute o2hb_heartbeat_group_attr_threshold
        .store  = o2hb_heartbeat_group_threshold_store,
 };
 
+static struct o2hb_heartbeat_group_attribute o2hb_heartbeat_group_attr_mode = {
+       .attr   = { .ca_owner = THIS_MODULE,
+               .ca_name = "mode",
+               .ca_mode = S_IRUGO | S_IWUSR },
+       .show   = o2hb_heartbeat_group_mode_show,
+       .store  = o2hb_heartbeat_group_mode_store,
+};
+
 static struct configfs_attribute *o2hb_heartbeat_group_attrs[] = {
        &o2hb_heartbeat_group_attr_threshold.attr,
+       &o2hb_heartbeat_group_attr_mode.attr,
        NULL,
 };
 
@@ -1963,3 +2402,34 @@ void o2hb_stop_all_regions(void)
        spin_unlock(&o2hb_live_lock);
 }
 EXPORT_SYMBOL_GPL(o2hb_stop_all_regions);
+
+int o2hb_get_all_regions(char *region_uuids, u8 max_regions)
+{
+       struct o2hb_region *reg;
+       int numregs = 0;
+       char *p;
+
+       spin_lock(&o2hb_live_lock);
+
+       p = region_uuids;
+       list_for_each_entry(reg, &o2hb_all_regions, hr_all_item) {
+               mlog(0, "Region: %s\n", config_item_name(&reg->hr_item));
+               if (numregs < max_regions) {
+                       memcpy(p, config_item_name(&reg->hr_item),
+                              O2HB_MAX_REGION_NAME_LEN);
+                       p += O2HB_MAX_REGION_NAME_LEN;
+               }
+               numregs++;
+       }
+
+       spin_unlock(&o2hb_live_lock);
+
+       return numregs;
+}
+EXPORT_SYMBOL_GPL(o2hb_get_all_regions);
+
+int o2hb_global_heartbeat_active(void)
+{
+       return (o2hb_heartbeat_mode == O2HB_HEARTBEAT_GLOBAL);
+}
+EXPORT_SYMBOL(o2hb_global_heartbeat_active);
index 2f1649253b497bed42fc14ef87685e59377dc2be..00ad8e8fea510ede2cf33d48eecf9178d65a9605 100644 (file)
@@ -31,6 +31,8 @@
 
 #define O2HB_REGION_TIMEOUT_MS         2000
 
+#define O2HB_MAX_REGION_NAME_LEN       32
+
 /* number of changes to be seen as live */
 #define O2HB_LIVE_THRESHOLD       2
 /* number of equal samples to be seen as dead */
@@ -81,5 +83,7 @@ int o2hb_check_node_heartbeating(u8 node_num);
 int o2hb_check_node_heartbeating_from_callback(u8 node_num);
 int o2hb_check_local_node_heartbeating(void);
 void o2hb_stop_all_regions(void);
+int o2hb_get_all_regions(char *region_uuids, u8 numregions);
+int o2hb_global_heartbeat_active(void);
 
 #endif /* O2CLUSTER_HEARTBEAT_H */
index fd96e2a2fa56556018d5ebc56ba0bc1a610f7e1e..ea2ed9f56c94ad0654a5f79259e50a1f046bed97 100644 (file)
 #define ML_ERROR       0x0000000100000000ULL /* sent to KERN_ERR */
 #define ML_NOTICE      0x0000000200000000ULL /* setn to KERN_NOTICE */
 #define ML_KTHREAD     0x0000000400000000ULL /* kernel thread activity */
-#define        ML_RESERVATIONS 0x0000000800000000ULL /* ocfs2 alloc reservations */
+#define ML_RESERVATIONS        0x0000000800000000ULL /* ocfs2 alloc reservations */
+#define ML_CLUSTER     0x0000001000000000ULL /* cluster stack */
 
 #define MLOG_INITIAL_AND_MASK (ML_ERROR|ML_NOTICE)
 #define MLOG_INITIAL_NOT_MASK (ML_ENTRY|ML_EXIT)
index ed0c9f367fed03fe0114b6956b6bb4a34ade5b77..bb240647ca5f5e0f47f52c43860ae7d1c3be435a 100644 (file)
@@ -711,6 +711,8 @@ static struct config_item *o2nm_node_group_make_item(struct config_group *group,
        config_item_init_type_name(&node->nd_item, name, &o2nm_node_type);
        spin_lock_init(&node->nd_lock);
 
+       mlog(ML_CLUSTER, "o2nm: Registering node %s\n", name);
+
        return &node->nd_item;
 }
 
@@ -744,6 +746,9 @@ static void o2nm_node_group_drop_item(struct config_group *group,
        }
        write_unlock(&cluster->cl_nodes_lock);
 
+       mlog(ML_CLUSTER, "o2nm: Unregistered node %s\n",
+            config_item_name(&node->nd_item));
+
        config_item_put(item);
 }
 
index 5b9854bad571c26d561ea2969d69f7693f759c5a..49b594325bec50c958d9f82a93d3deae3448fb01 100644 (file)
 /* host name, group name, cluster name all 64 bytes */
 #define O2NM_MAX_NAME_LEN        64    // __NEW_UTS_LEN
 
+/*
+ * Maximum number of global heartbeat regions allowed.
+ * **CAUTION**  Changing this number will break dlm compatibility.
+ */
+#define O2NM_MAX_REGIONS       32
+
 #endif /* _OCFS2_NODEMANAGER_H */
index cbe2f057cc2826cb6af4ed833319fe27c4bd565f..9aa426e4212330994255aaa25c85a9f60ec3874b 100644 (file)
@@ -1696,6 +1696,9 @@ static void o2net_hb_node_down_cb(struct o2nm_node *node, int node_num,
 {
        o2quo_hb_down(node_num);
 
+       if (!node)
+               return;
+
        if (node_num != o2nm_this_node())
                o2net_disconnect_node(node);
 
@@ -1709,6 +1712,8 @@ static void o2net_hb_node_up_cb(struct o2nm_node *node, int node_num,
 
        o2quo_hb_up(node_num);
 
+       BUG_ON(!node);
+
        /* ensure an immediate connect attempt */
        nn->nn_last_connect_attempt = jiffies -
                (msecs_to_jiffies(o2net_reconnect_delay()) + 1);
index b4957c7d9fe2262a203a3efb3573eda9ed3d2638..edaded48e7e9f083ac7c67e72a9f031123f7844a 100644 (file)
 #include "inode.h"
 #include "super.h"
 
+void ocfs2_dentry_attach_gen(struct dentry *dentry)
+{
+       unsigned long gen =
+               OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen;
+       BUG_ON(dentry->d_inode);
+       dentry->d_fsdata = (void *)gen;
+}
+
 
 static int ocfs2_dentry_revalidate(struct dentry *dentry,
                                   struct nameidata *nd)
@@ -51,11 +59,20 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry,
        mlog_entry("(0x%p, '%.*s')\n", dentry,
                   dentry->d_name.len, dentry->d_name.name);
 
-       /* Never trust a negative dentry - force a new lookup. */
+       /* For a negative dentry -
+        * check the generation number of the parent and compare with the
+        * one stored in the inode.
+        */
        if (inode == NULL) {
-               mlog(0, "negative dentry: %.*s\n", dentry->d_name.len,
-                    dentry->d_name.name);
-               goto bail;
+               unsigned long gen = (unsigned long) dentry->d_fsdata;
+               unsigned long pgen =
+                       OCFS2_I(dentry->d_parent->d_inode)->ip_dir_lock_gen;
+               mlog(0, "negative dentry: %.*s parent gen: %lu "
+                       "dentry gen: %lu\n",
+                       dentry->d_name.len, dentry->d_name.name, pgen, gen);
+               if (gen != pgen)
+                       goto bail;
+               goto valid;
        }
 
        BUG_ON(!osb);
@@ -96,6 +113,7 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry,
                goto bail;
        }
 
+valid:
        ret = 1;
 
 bail:
@@ -227,6 +245,12 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
        if (!inode)
                return 0;
 
+       if (!dentry->d_inode && dentry->d_fsdata) {
+               /* Converting a negative dentry to positive
+                  Clear dentry->d_fsdata */
+               dentry->d_fsdata = dl = NULL;
+       }
+
        if (dl) {
                mlog_bug_on_msg(dl->dl_parent_blkno != parent_blkno,
                                " \"%.*s\": old parent: %llu, new: %llu\n",
@@ -452,6 +476,7 @@ static void ocfs2_dentry_iput(struct dentry *dentry, struct inode *inode)
 
 out:
        iput(inode);
+       ocfs2_dentry_attach_gen(dentry);
 }
 
 /*
index f5dd1789acf1b4527373217ce7c6b0374695eb17..b79eff709958f806ce92f937cbfd7730e4d36a29 100644 (file)
@@ -64,5 +64,6 @@ void ocfs2_dentry_move(struct dentry *dentry, struct dentry *target,
                       struct inode *old_dir, struct inode *new_dir);
 
 extern spinlock_t dentry_attach_lock;
+void ocfs2_dentry_attach_gen(struct dentry *dentry);
 
 #endif /* OCFS2_DCACHE_H */
index 765298908f1d3905bbabf3c5e597a8bf72ebd4a9..b36d0bf77a5a4ca5fa1de836dca82037d4f0c491 100644 (file)
@@ -445,7 +445,9 @@ enum {
        DLM_LOCK_REQUEST_MSG,    /* 515 */
        DLM_RECO_DATA_DONE_MSG,  /* 516 */
        DLM_BEGIN_RECO_MSG,      /* 517 */
-       DLM_FINALIZE_RECO_MSG    /* 518 */
+       DLM_FINALIZE_RECO_MSG,   /* 518 */
+       DLM_QUERY_REGION,        /* 519 */
+       DLM_QUERY_NODEINFO,      /* 520 */
 };
 
 struct dlm_reco_node_data
@@ -727,6 +729,31 @@ struct dlm_cancel_join
        u8 domain[O2NM_MAX_NAME_LEN];
 };
 
+struct dlm_query_region {
+       u8 qr_node;
+       u8 qr_numregions;
+       u8 qr_namelen;
+       u8 pad1;
+       u8 qr_domain[O2NM_MAX_NAME_LEN];
+       u8 qr_regions[O2HB_MAX_REGION_NAME_LEN * O2NM_MAX_REGIONS];
+};
+
+struct dlm_node_info {
+       u8 ni_nodenum;
+       u8 pad1;
+       u16 ni_ipv4_port;
+       u32 ni_ipv4_address;
+};
+
+struct dlm_query_nodeinfo {
+       u8 qn_nodenum;
+       u8 qn_numnodes;
+       u8 qn_namelen;
+       u8 pad1;
+       u8 qn_domain[O2NM_MAX_NAME_LEN];
+       struct dlm_node_info qn_nodes[O2NM_MAX_NODES];
+};
+
 struct dlm_exit_domain
 {
        u8 node_idx;
index 901ca52bf86b293639ea39c8e1f460b66bc1f265..272ec8631a514fdb9ae45d5ef07390e18da07ac4 100644 (file)
@@ -493,7 +493,7 @@ static int debug_mle_print(struct dlm_ctxt *dlm, struct debug_buffer *db)
        struct hlist_head *bucket;
        struct hlist_node *list;
        int i, out = 0;
-       unsigned long total = 0, longest = 0, bktcnt;
+       unsigned long total = 0, longest = 0, bucket_count = 0;
 
        out += snprintf(db->buf + out, db->len - out,
                        "Dumping MLEs for Domain: %s\n", dlm->name);
@@ -505,13 +505,13 @@ static int debug_mle_print(struct dlm_ctxt *dlm, struct debug_buffer *db)
                        mle = hlist_entry(list, struct dlm_master_list_entry,
                                          master_hash_node);
                        ++total;
-                       ++bktcnt;
+                       ++bucket_count;
                        if (db->len - out < 200)
                                continue;
                        out += dump_mle(mle, db->buf + out, db->len - out);
                }
-               longest = max(longest, bktcnt);
-               bktcnt = 0;
+               longest = max(longest, bucket_count);
+               bucket_count = 0;
        }
        spin_unlock(&dlm->master_lock);
 
@@ -782,7 +782,9 @@ static int debug_state_print(struct dlm_ctxt *dlm, struct debug_buffer *db)
 
        /* Domain: xxxxxxxxxx  Key: 0xdfbac769 */
        out += snprintf(db->buf + out, db->len - out,
-                       "Domain: %s  Key: 0x%08x\n", dlm->name, dlm->key);
+                       "Domain: %s  Key: 0x%08x  Protocol: %d.%d\n",
+                       dlm->name, dlm->key, dlm->dlm_locking_proto.pv_major,
+                       dlm->dlm_locking_proto.pv_minor);
 
        /* Thread Pid: xxx  Node: xxx  State: xxxxx */
        out += snprintf(db->buf + out, db->len - out,
index 11a5c87fd7f7c00de41c61c00fae625e46675973..58a93b953735ebcaeda134794195449da4e98a53 100644 (file)
@@ -128,10 +128,14 @@ static DECLARE_WAIT_QUEUE_HEAD(dlm_domain_events);
  * will have a negotiated version with the same major number and a minor
  * number equal or smaller.  The dlm_ctxt->dlm_locking_proto field should
  * be used to determine what a running domain is actually using.
+ *
+ * New in version 1.1:
+ *     - Message DLM_QUERY_REGION added to support global heartbeat
+ *     - Message DLM_QUERY_NODEINFO added to allow online node removes
  */
 static const struct dlm_protocol_version dlm_protocol = {
        .pv_major = 1,
-       .pv_minor = 0,
+       .pv_minor = 1,
 };
 
 #define DLM_DOMAIN_BACKOFF_MS 200
@@ -142,6 +146,8 @@ static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data,
                                     void **ret_data);
 static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data,
                                   void **ret_data);
+static int dlm_query_region_handler(struct o2net_msg *msg, u32 len,
+                                   void *data, void **ret_data);
 static int dlm_exit_domain_handler(struct o2net_msg *msg, u32 len, void *data,
                                   void **ret_data);
 static int dlm_protocol_compare(struct dlm_protocol_version *existing,
@@ -921,6 +927,370 @@ static int dlm_assert_joined_handler(struct o2net_msg *msg, u32 len, void *data,
        return 0;
 }
 
+static int dlm_match_regions(struct dlm_ctxt *dlm,
+                            struct dlm_query_region *qr)
+{
+       char *local = NULL, *remote = qr->qr_regions;
+       char *l, *r;
+       int localnr, i, j, foundit;
+       int status = 0;
+
+       if (!o2hb_global_heartbeat_active()) {
+               if (qr->qr_numregions) {
+                       mlog(ML_ERROR, "Domain %s: Joining node %d has global "
+                            "heartbeat enabled but local node %d does not\n",
+                            qr->qr_domain, qr->qr_node, dlm->node_num);
+                       status = -EINVAL;
+               }
+               goto bail;
+       }
+
+       if (o2hb_global_heartbeat_active() && !qr->qr_numregions) {
+               mlog(ML_ERROR, "Domain %s: Local node %d has global "
+                    "heartbeat enabled but joining node %d does not\n",
+                    qr->qr_domain, dlm->node_num, qr->qr_node);
+               status = -EINVAL;
+               goto bail;
+       }
+
+       r = remote;
+       for (i = 0; i < qr->qr_numregions; ++i) {
+               mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, r);
+               r += O2HB_MAX_REGION_NAME_LEN;
+       }
+
+       local = kmalloc(sizeof(qr->qr_regions), GFP_KERNEL);
+       if (!local) {
+               status = -ENOMEM;
+               goto bail;
+       }
+
+       localnr = o2hb_get_all_regions(local, O2NM_MAX_REGIONS);
+
+       /* compare local regions with remote */
+       l = local;
+       for (i = 0; i < localnr; ++i) {
+               foundit = 0;
+               r = remote;
+               for (j = 0; j <= qr->qr_numregions; ++j) {
+                       if (!memcmp(l, r, O2HB_MAX_REGION_NAME_LEN)) {
+                               foundit = 1;
+                               break;
+                       }
+                       r += O2HB_MAX_REGION_NAME_LEN;
+               }
+               if (!foundit) {
+                       status = -EINVAL;
+                       mlog(ML_ERROR, "Domain %s: Region '%.*s' registered "
+                            "in local node %d but not in joining node %d\n",
+                            qr->qr_domain, O2HB_MAX_REGION_NAME_LEN, l,
+                            dlm->node_num, qr->qr_node);
+                       goto bail;
+               }
+               l += O2HB_MAX_REGION_NAME_LEN;
+       }
+
+       /* compare remote with local regions */
+       r = remote;
+       for (i = 0; i < qr->qr_numregions; ++i) {
+               foundit = 0;
+               l = local;
+               for (j = 0; j < localnr; ++j) {
+                       if (!memcmp(r, l, O2HB_MAX_REGION_NAME_LEN)) {
+                               foundit = 1;
+                               break;
+                       }
+                       l += O2HB_MAX_REGION_NAME_LEN;
+               }
+               if (!foundit) {
+                       status = -EINVAL;
+                       mlog(ML_ERROR, "Domain %s: Region '%.*s' registered "
+                            "in joining node %d but not in local node %d\n",
+                            qr->qr_domain, O2HB_MAX_REGION_NAME_LEN, r,
+                            qr->qr_node, dlm->node_num);
+                       goto bail;
+               }
+               r += O2HB_MAX_REGION_NAME_LEN;
+       }
+
+bail:
+       kfree(local);
+
+       return status;
+}
+
+static int dlm_send_regions(struct dlm_ctxt *dlm, unsigned long *node_map)
+{
+       struct dlm_query_region *qr = NULL;
+       int status, ret = 0, i;
+       char *p;
+
+       if (find_next_bit(node_map, O2NM_MAX_NODES, 0) >= O2NM_MAX_NODES)
+               goto bail;
+
+       qr = kzalloc(sizeof(struct dlm_query_region), GFP_KERNEL);
+       if (!qr) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       qr->qr_node = dlm->node_num;
+       qr->qr_namelen = strlen(dlm->name);
+       memcpy(qr->qr_domain, dlm->name, qr->qr_namelen);
+       /* if local hb, the numregions will be zero */
+       if (o2hb_global_heartbeat_active())
+               qr->qr_numregions = o2hb_get_all_regions(qr->qr_regions,
+                                                        O2NM_MAX_REGIONS);
+
+       p = qr->qr_regions;
+       for (i = 0; i < qr->qr_numregions; ++i, p += O2HB_MAX_REGION_NAME_LEN)
+               mlog(0, "Region %.*s\n", O2HB_MAX_REGION_NAME_LEN, p);
+
+       i = -1;
+       while ((i = find_next_bit(node_map, O2NM_MAX_NODES,
+                                 i + 1)) < O2NM_MAX_NODES) {
+               if (i == dlm->node_num)
+                       continue;
+
+               mlog(0, "Sending regions to node %d\n", i);
+
+               ret = o2net_send_message(DLM_QUERY_REGION, DLM_MOD_KEY, qr,
+                                        sizeof(struct dlm_query_region),
+                                        i, &status);
+               if (ret >= 0)
+                       ret = status;
+               if (ret) {
+                       mlog(ML_ERROR, "Region mismatch %d, node %d\n",
+                            ret, i);
+                       break;
+               }
+       }
+
+bail:
+       kfree(qr);
+       return ret;
+}
+
+static int dlm_query_region_handler(struct o2net_msg *msg, u32 len,
+                                   void *data, void **ret_data)
+{
+       struct dlm_query_region *qr;
+       struct dlm_ctxt *dlm = NULL;
+       int status = 0;
+       int locked = 0;
+
+       qr = (struct dlm_query_region *) msg->buf;
+
+       mlog(0, "Node %u queries hb regions on domain %s\n", qr->qr_node,
+            qr->qr_domain);
+
+       status = -EINVAL;
+
+       spin_lock(&dlm_domain_lock);
+       dlm = __dlm_lookup_domain_full(qr->qr_domain, qr->qr_namelen);
+       if (!dlm) {
+               mlog(ML_ERROR, "Node %d queried hb regions on domain %s "
+                    "before join domain\n", qr->qr_node, qr->qr_domain);
+               goto bail;
+       }
+
+       spin_lock(&dlm->spinlock);
+       locked = 1;
+       if (dlm->joining_node != qr->qr_node) {
+               mlog(ML_ERROR, "Node %d queried hb regions on domain %s "
+                    "but joining node is %d\n", qr->qr_node, qr->qr_domain,
+                    dlm->joining_node);
+               goto bail;
+       }
+
+       /* Support for global heartbeat was added in 1.1 */
+       if (dlm->dlm_locking_proto.pv_major == 1 &&
+           dlm->dlm_locking_proto.pv_minor == 0) {
+               mlog(ML_ERROR, "Node %d queried hb regions on domain %s "
+                    "but active dlm protocol is %d.%d\n", qr->qr_node,
+                    qr->qr_domain, dlm->dlm_locking_proto.pv_major,
+                    dlm->dlm_locking_proto.pv_minor);
+               goto bail;
+       }
+
+       status = dlm_match_regions(dlm, qr);
+
+bail:
+       if (locked)
+               spin_unlock(&dlm->spinlock);
+       spin_unlock(&dlm_domain_lock);
+
+       return status;
+}
+
+static int dlm_match_nodes(struct dlm_ctxt *dlm, struct dlm_query_nodeinfo *qn)
+{
+       struct o2nm_node *local;
+       struct dlm_node_info *remote;
+       int i, j;
+       int status = 0;
+
+       for (j = 0; j < qn->qn_numnodes; ++j)
+               mlog(0, "Node %3d, %pI4:%u\n", qn->qn_nodes[j].ni_nodenum,
+                    &(qn->qn_nodes[j].ni_ipv4_address),
+                    ntohs(qn->qn_nodes[j].ni_ipv4_port));
+
+       for (i = 0; i < O2NM_MAX_NODES && !status; ++i) {
+               local = o2nm_get_node_by_num(i);
+               remote = NULL;
+               for (j = 0; j < qn->qn_numnodes; ++j) {
+                       if (qn->qn_nodes[j].ni_nodenum == i) {
+                               remote = &(qn->qn_nodes[j]);
+                               break;
+                       }
+               }
+
+               if (!local && !remote)
+                       continue;
+
+               if ((local && !remote) || (!local && remote))
+                       status = -EINVAL;
+
+               if (!status &&
+                   ((remote->ni_nodenum != local->nd_num) ||
+                    (remote->ni_ipv4_port != local->nd_ipv4_port) ||
+                    (remote->ni_ipv4_address != local->nd_ipv4_address)))
+                       status = -EINVAL;
+
+               if (status) {
+                       if (remote && !local)
+                               mlog(ML_ERROR, "Domain %s: Node %d (%pI4:%u) "
+                                    "registered in joining node %d but not in "
+                                    "local node %d\n", qn->qn_domain,
+                                    remote->ni_nodenum,
+                                    &(remote->ni_ipv4_address),
+                                    ntohs(remote->ni_ipv4_port),
+                                    qn->qn_nodenum, dlm->node_num);
+                       if (local && !remote)
+                               mlog(ML_ERROR, "Domain %s: Node %d (%pI4:%u) "
+                                    "registered in local node %d but not in "
+                                    "joining node %d\n", qn->qn_domain,
+                                    local->nd_num, &(local->nd_ipv4_address),
+                                    ntohs(local->nd_ipv4_port),
+                                    dlm->node_num, qn->qn_nodenum);
+                       BUG_ON((!local && !remote));
+               }
+
+               if (local)
+                       o2nm_node_put(local);
+       }
+
+       return status;
+}
+
+static int dlm_send_nodeinfo(struct dlm_ctxt *dlm, unsigned long *node_map)
+{
+       struct dlm_query_nodeinfo *qn = NULL;
+       struct o2nm_node *node;
+       int ret = 0, status, count, i;
+
+       if (find_next_bit(node_map, O2NM_MAX_NODES, 0) >= O2NM_MAX_NODES)
+               goto bail;
+
+       qn = kzalloc(sizeof(struct dlm_query_nodeinfo), GFP_KERNEL);
+       if (!qn) {
+               ret = -ENOMEM;
+               mlog_errno(ret);
+               goto bail;
+       }
+
+       for (i = 0, count = 0; i < O2NM_MAX_NODES; ++i) {
+               node = o2nm_get_node_by_num(i);
+               if (!node)
+                       continue;
+               qn->qn_nodes[count].ni_nodenum = node->nd_num;
+               qn->qn_nodes[count].ni_ipv4_port = node->nd_ipv4_port;
+               qn->qn_nodes[count].ni_ipv4_address = node->nd_ipv4_address;
+               mlog(0, "Node %3d, %pI4:%u\n", node->nd_num,
+                    &(node->nd_ipv4_address), ntohs(node->nd_ipv4_port));
+               ++count;
+               o2nm_node_put(node);
+       }
+
+       qn->qn_nodenum = dlm->node_num;
+       qn->qn_numnodes = count;
+       qn->qn_namelen = strlen(dlm->name);
+       memcpy(qn->qn_domain, dlm->name, qn->qn_namelen);
+
+       i = -1;
+       while ((i = find_next_bit(node_map, O2NM_MAX_NODES,
+                                 i + 1)) < O2NM_MAX_NODES) {
+               if (i == dlm->node_num)
+                       continue;
+
+               mlog(0, "Sending nodeinfo to node %d\n", i);
+
+               ret = o2net_send_message(DLM_QUERY_NODEINFO, DLM_MOD_KEY,
+                                        qn, sizeof(struct dlm_query_nodeinfo),
+                                        i, &status);
+               if (ret >= 0)
+                       ret = status;
+               if (ret) {
+                       mlog(ML_ERROR, "node mismatch %d, node %d\n", ret, i);
+                       break;
+               }
+       }
+
+bail:
+       kfree(qn);
+       return ret;
+}
+
+static int dlm_query_nodeinfo_handler(struct o2net_msg *msg, u32 len,
+                                     void *data, void **ret_data)
+{
+       struct dlm_query_nodeinfo *qn;
+       struct dlm_ctxt *dlm = NULL;
+       int locked = 0, status = -EINVAL;
+
+       qn = (struct dlm_query_nodeinfo *) msg->buf;
+
+       mlog(0, "Node %u queries nodes on domain %s\n", qn->qn_nodenum,
+            qn->qn_domain);
+
+       spin_lock(&dlm_domain_lock);
+       dlm = __dlm_lookup_domain_full(qn->qn_domain, qn->qn_namelen);
+       if (!dlm) {
+               mlog(ML_ERROR, "Node %d queried nodes on domain %s before "
+                    "join domain\n", qn->qn_nodenum, qn->qn_domain);
+               goto bail;
+       }
+
+       spin_lock(&dlm->spinlock);
+       locked = 1;
+       if (dlm->joining_node != qn->qn_nodenum) {
+               mlog(ML_ERROR, "Node %d queried nodes on domain %s but "
+                    "joining node is %d\n", qn->qn_nodenum, qn->qn_domain,
+                    dlm->joining_node);
+               goto bail;
+       }
+
+       /* Support for node query was added in 1.1 */
+       if (dlm->dlm_locking_proto.pv_major == 1 &&
+           dlm->dlm_locking_proto.pv_minor == 0) {
+               mlog(ML_ERROR, "Node %d queried nodes on domain %s "
+                    "but active dlm protocol is %d.%d\n", qn->qn_nodenum,
+                    qn->qn_domain, dlm->dlm_locking_proto.pv_major,
+                    dlm->dlm_locking_proto.pv_minor);
+               goto bail;
+       }
+
+       status = dlm_match_nodes(dlm, qn);
+
+bail:
+       if (locked)
+               spin_unlock(&dlm->spinlock);
+       spin_unlock(&dlm_domain_lock);
+
+       return status;
+}
+
 static int dlm_cancel_join_handler(struct o2net_msg *msg, u32 len, void *data,
                                   void **ret_data)
 {
@@ -1241,6 +1611,20 @@ static int dlm_try_to_join_domain(struct dlm_ctxt *dlm)
        set_bit(dlm->node_num, dlm->domain_map);
        spin_unlock(&dlm->spinlock);
 
+       /* Support for global heartbeat and node info was added in 1.1 */
+       if (dlm_protocol.pv_major > 1 || dlm_protocol.pv_minor > 0) {
+               status = dlm_send_nodeinfo(dlm, ctxt->yes_resp_map);
+               if (status) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+               status = dlm_send_regions(dlm, ctxt->yes_resp_map);
+               if (status) {
+                       mlog_errno(status);
+                       goto bail;
+               }
+       }
+
        dlm_send_join_asserts(dlm, ctxt->yes_resp_map);
 
        /* Joined state *must* be set before the joining node
@@ -1807,7 +2191,21 @@ static int dlm_register_net_handlers(void)
                                        sizeof(struct dlm_cancel_join),
                                        dlm_cancel_join_handler,
                                        NULL, NULL, &dlm_join_handlers);
+       if (status)
+               goto bail;
+
+       status = o2net_register_handler(DLM_QUERY_REGION, DLM_MOD_KEY,
+                                       sizeof(struct dlm_query_region),
+                                       dlm_query_region_handler,
+                                       NULL, NULL, &dlm_join_handlers);
 
+       if (status)
+               goto bail;
+
+       status = o2net_register_handler(DLM_QUERY_NODEINFO, DLM_MOD_KEY,
+                                       sizeof(struct dlm_query_nodeinfo),
+                                       dlm_query_nodeinfo_handler,
+                                       NULL, NULL, &dlm_join_handlers);
 bail:
        if (status < 0)
                dlm_unregister_net_handlers();
index 5e02a893f46ea5e1e4fa5a5c0313b5d7356e1526..e8d94d722ecb8b6dc7aad1ceaa749c99d51cf8a6 100644 (file)
@@ -3635,10 +3635,18 @@ static int ocfs2_data_convert_worker(struct ocfs2_lock_res *lockres,
 {
        struct inode *inode;
        struct address_space *mapping;
+       struct ocfs2_inode_info *oi;
 
                inode = ocfs2_lock_res_inode(lockres);
        mapping = inode->i_mapping;
 
+       if (S_ISDIR(inode->i_mode)) {
+               oi = OCFS2_I(inode);
+               oi->ip_dir_lock_gen++;
+               mlog(0, "generation: %u\n", oi->ip_dir_lock_gen);
+               goto out;
+       }
+
        if (!S_ISREG(inode->i_mode))
                goto out;
 
index 9a03c151b5ceabc169215d99777abb92e2d2ad36..9e8cc4346b761e6246494416787b5b78c193f01e 100644 (file)
 
 #include "buffer_head_io.h"
 
-static int ocfs2_sync_inode(struct inode *inode)
-{
-       filemap_fdatawrite(inode->i_mapping);
-       return sync_mapping_buffers(inode->i_mapping);
-}
-
 static int ocfs2_init_file_private(struct inode *inode, struct file *file)
 {
        struct ocfs2_file_private *fp;
@@ -180,16 +174,12 @@ static int ocfs2_sync_file(struct file *file, int datasync)
 {
        int err = 0;
        journal_t *journal;
-       struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = file->f_mapping->host;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
-       mlog_entry("(0x%p, 0x%p, %d, '%.*s')\n", file, dentry, datasync,
-                  dentry->d_name.len, dentry->d_name.name);
-
-       err = ocfs2_sync_inode(dentry->d_inode);
-       if (err)
-               goto bail;
+       mlog_entry("(0x%p, %d, 0x%p, '%.*s')\n", file, datasync,
+                  file->f_path.dentry, file->f_path.dentry->d_name.len,
+                  file->f_path.dentry->d_name.name);
 
        if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) {
                /*
@@ -370,7 +360,7 @@ static int ocfs2_cow_file_pos(struct inode *inode,
        if (!(ext_flags & OCFS2_EXT_REFCOUNTED))
                goto out;
 
-       return ocfs2_refcount_cow(inode, fe_bh, cpos, 1, cpos+1);
+       return ocfs2_refcount_cow(inode, NULL, fe_bh, cpos, 1, cpos+1);
 
 out:
        return status;
@@ -913,8 +903,8 @@ static int ocfs2_zero_extend_get_range(struct inode *inode,
                zero_clusters = last_cpos - zero_cpos;
 
        if (needs_cow) {
-               rc = ocfs2_refcount_cow(inode, di_bh, zero_cpos, zero_clusters,
-                                       UINT_MAX);
+               rc = ocfs2_refcount_cow(inode, NULL, di_bh, zero_cpos,
+                                       zero_clusters, UINT_MAX);
                if (rc) {
                        mlog_errno(rc);
                        goto out;
@@ -2062,6 +2052,7 @@ out:
 }
 
 static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
+                                           struct file *file,
                                            loff_t pos, size_t count,
                                            int *meta_level)
 {
@@ -2079,7 +2070,7 @@ static int ocfs2_prepare_inode_for_refcount(struct inode *inode,
 
        *meta_level = 1;
 
-       ret = ocfs2_refcount_cow(inode, di_bh, cpos, clusters, UINT_MAX);
+       ret = ocfs2_refcount_cow(inode, file, di_bh, cpos, clusters, UINT_MAX);
        if (ret)
                mlog_errno(ret);
 out:
@@ -2087,7 +2078,7 @@ out:
        return ret;
 }
 
-static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
+static int ocfs2_prepare_inode_for_write(struct file *file,
                                         loff_t *ppos,
                                         size_t count,
                                         int appending,
@@ -2095,6 +2086,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
                                         int *has_refcount)
 {
        int ret = 0, meta_level = 0;
+       struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
        loff_t saved_pos, end;
 
@@ -2150,6 +2142,7 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
                        meta_level = -1;
 
                        ret = ocfs2_prepare_inode_for_refcount(inode,
+                                                              file,
                                                               saved_pos,
                                                               count,
                                                               &meta_level);
@@ -2232,6 +2225,8 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_path.dentry->d_inode;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+       int full_coherency = !(osb->s_mount_opt &
+                              OCFS2_MOUNT_COHERENCY_BUFFERED);
 
        mlog_entry("(0x%p, %u, '%.*s')\n", file,
                   (unsigned int)nr_segs,
@@ -2255,16 +2250,39 @@ relock:
                have_alloc_sem = 1;
        }
 
-       /* concurrent O_DIRECT writes are allowed */
-       rw_level = !direct_io;
+       /*
+        * Concurrent O_DIRECT writes are allowed with
+        * mount_option "coherency=buffered".
+        */
+       rw_level = (!direct_io || full_coherency);
+
        ret = ocfs2_rw_lock(inode, rw_level);
        if (ret < 0) {
                mlog_errno(ret);
                goto out_sems;
        }
 
+       /*
+        * O_DIRECT writes with "coherency=full" need to take EX cluster
+        * inode_lock to guarantee coherency.
+        */
+       if (direct_io && full_coherency) {
+               /*
+                * We need to take and drop the inode lock to force
+                * other nodes to drop their caches.  Buffered I/O
+                * already does this in write_begin().
+                */
+               ret = ocfs2_inode_lock(inode, NULL, 1);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out_sems;
+               }
+
+               ocfs2_inode_unlock(inode, 1);
+       }
+
        can_do_direct = direct_io;
-       ret = ocfs2_prepare_inode_for_write(file->f_path.dentry, ppos,
+       ret = ocfs2_prepare_inode_for_write(file, ppos,
                                            iocb->ki_left, appending,
                                            &can_do_direct, &has_refcount);
        if (ret < 0) {
@@ -2312,17 +2330,6 @@ relock:
                written = generic_file_direct_write(iocb, iov, &nr_segs, *ppos,
                                                    ppos, count, ocount);
                if (written < 0) {
-                       /*
-                        * direct write may have instantiated a few
-                        * blocks outside i_size. Trim these off again.
-                        * Don't need i_size_read because we hold i_mutex.
-                        *
-                        * XXX(truncate): this looks buggy because ocfs2 did not
-                        * actually implement ->truncate.  Take a look at
-                        * the new truncate sequence and update this accordingly
-                        */
-                       if (*ppos + count > inode->i_size)
-                               truncate_setsize(inode, inode->i_size);
                        ret = written;
                        goto out_dio;
                }
@@ -2394,7 +2401,7 @@ static int ocfs2_splice_to_file(struct pipe_inode_info *pipe,
 {
        int ret;
 
-       ret = ocfs2_prepare_inode_for_write(out->f_path.dentry, &sd->pos,
+       ret = ocfs2_prepare_inode_for_write(out, &sd->pos,
                                            sd->total_len, 0, NULL, NULL);
        if (ret < 0) {
                mlog_errno(ret);
index eece3e05d9d0124d04b81c940c1289f876e700bb..f935fd6600dd1e07e7625161671758795ce477b0 100644 (file)
@@ -335,6 +335,7 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
                    else
                            inode->i_fop = &ocfs2_dops_no_plocks;
                    i_size_write(inode, le64_to_cpu(fe->i_size));
+                   OCFS2_I(inode)->ip_dir_lock_gen = 1;
                    break;
            case S_IFLNK:
                    if (ocfs2_inode_is_fast_symlink(inode))
index 6de5a869db300061e23e3e924a0517460f660e3d..1c508b149b3ac1bd4325fd33a9aae6bdb70e024a 100644 (file)
@@ -46,30 +46,28 @@ struct ocfs2_inode_info
        /* These fields are protected by ip_lock */
        spinlock_t                      ip_lock;
        u32                             ip_open_count;
-       u32                             ip_clusters;
        struct list_head                ip_io_markers;
+       u32                             ip_clusters;
 
+       u16                             ip_dyn_features;
        struct mutex                    ip_io_mutex;
-
        u32                             ip_flags; /* see below */
        u32                             ip_attr; /* inode attributes */
-       u16                             ip_dyn_features;
 
        /* protected by recovery_lock. */
        struct inode                    *ip_next_orphan;
 
-       u32                             ip_dir_start_lookup;
-
        struct ocfs2_caching_info       ip_metadata_cache;
-
        struct ocfs2_extent_map         ip_extent_map;
-
        struct inode                    vfs_inode;
        struct jbd2_inode               ip_jinode;
 
+       u32                             ip_dir_start_lookup;
+
        /* Only valid if the inode is the dir. */
        u32                             ip_last_used_slot;
        u64                             ip_last_used_group;
+       u32                             ip_dir_lock_gen;
 
        struct ocfs2_alloc_reservation  ip_la_data_resv;
 };
index 7d9d9c132cef3a5d59a412aa4d0d3c26c10a5fb0..7a48681961521a957e1947ba9abdbb8d290f9cde 100644 (file)
 
 #include <linux/ext2_fs.h>
 
+#define o2info_from_user(a, b) \
+               copy_from_user(&(a), (b), sizeof(a))
+#define o2info_to_user(a, b)   \
+               copy_to_user((typeof(a) __user *)b, &(a), sizeof(a))
+
+/*
+ * This call is void because we are already reporting an error that may
+ * be -EFAULT.  The error will be returned from the ioctl(2) call.  It's
+ * just a best-effort to tell userspace that this request caused the error.
+ */
+static inline void __o2info_set_request_error(struct ocfs2_info_request *kreq,
+                                       struct ocfs2_info_request __user *req)
+{
+       kreq->ir_flags |= OCFS2_INFO_FL_ERROR;
+       (void)put_user(kreq->ir_flags, (__u32 __user *)&(req->ir_flags));
+}
+
+#define o2info_set_request_error(a, b) \
+               __o2info_set_request_error((struct ocfs2_info_request *)&(a), b)
+
 static int ocfs2_get_inode_attr(struct inode *inode, unsigned *flags)
 {
        int status;
@@ -109,6 +129,328 @@ bail:
        return status;
 }
 
+int ocfs2_info_handle_blocksize(struct inode *inode,
+                               struct ocfs2_info_request __user *req)
+{
+       int status = -EFAULT;
+       struct ocfs2_info_blocksize oib;
+
+       if (o2info_from_user(oib, req))
+               goto bail;
+
+       oib.ib_blocksize = inode->i_sb->s_blocksize;
+       oib.ib_req.ir_flags |= OCFS2_INFO_FL_FILLED;
+
+       if (o2info_to_user(oib, req))
+               goto bail;
+
+       status = 0;
+bail:
+       if (status)
+               o2info_set_request_error(oib, req);
+
+       return status;
+}
+
+int ocfs2_info_handle_clustersize(struct inode *inode,
+                                 struct ocfs2_info_request __user *req)
+{
+       int status = -EFAULT;
+       struct ocfs2_info_clustersize oic;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (o2info_from_user(oic, req))
+               goto bail;
+
+       oic.ic_clustersize = osb->s_clustersize;
+       oic.ic_req.ir_flags |= OCFS2_INFO_FL_FILLED;
+
+       if (o2info_to_user(oic, req))
+               goto bail;
+
+       status = 0;
+bail:
+       if (status)
+               o2info_set_request_error(oic, req);
+
+       return status;
+}
+
+int ocfs2_info_handle_maxslots(struct inode *inode,
+                              struct ocfs2_info_request __user *req)
+{
+       int status = -EFAULT;
+       struct ocfs2_info_maxslots oim;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (o2info_from_user(oim, req))
+               goto bail;
+
+       oim.im_max_slots = osb->max_slots;
+       oim.im_req.ir_flags |= OCFS2_INFO_FL_FILLED;
+
+       if (o2info_to_user(oim, req))
+               goto bail;
+
+       status = 0;
+bail:
+       if (status)
+               o2info_set_request_error(oim, req);
+
+       return status;
+}
+
+int ocfs2_info_handle_label(struct inode *inode,
+                           struct ocfs2_info_request __user *req)
+{
+       int status = -EFAULT;
+       struct ocfs2_info_label oil;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (o2info_from_user(oil, req))
+               goto bail;
+
+       memcpy(oil.il_label, osb->vol_label, OCFS2_MAX_VOL_LABEL_LEN);
+       oil.il_req.ir_flags |= OCFS2_INFO_FL_FILLED;
+
+       if (o2info_to_user(oil, req))
+               goto bail;
+
+       status = 0;
+bail:
+       if (status)
+               o2info_set_request_error(oil, req);
+
+       return status;
+}
+
+int ocfs2_info_handle_uuid(struct inode *inode,
+                          struct ocfs2_info_request __user *req)
+{
+       int status = -EFAULT;
+       struct ocfs2_info_uuid oiu;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (o2info_from_user(oiu, req))
+               goto bail;
+
+       memcpy(oiu.iu_uuid_str, osb->uuid_str, OCFS2_TEXT_UUID_LEN + 1);
+       oiu.iu_req.ir_flags |= OCFS2_INFO_FL_FILLED;
+
+       if (o2info_to_user(oiu, req))
+               goto bail;
+
+       status = 0;
+bail:
+       if (status)
+               o2info_set_request_error(oiu, req);
+
+       return status;
+}
+
+int ocfs2_info_handle_fs_features(struct inode *inode,
+                                 struct ocfs2_info_request __user *req)
+{
+       int status = -EFAULT;
+       struct ocfs2_info_fs_features oif;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (o2info_from_user(oif, req))
+               goto bail;
+
+       oif.if_compat_features = osb->s_feature_compat;
+       oif.if_incompat_features = osb->s_feature_incompat;
+       oif.if_ro_compat_features = osb->s_feature_ro_compat;
+       oif.if_req.ir_flags |= OCFS2_INFO_FL_FILLED;
+
+       if (o2info_to_user(oif, req))
+               goto bail;
+
+       status = 0;
+bail:
+       if (status)
+               o2info_set_request_error(oif, req);
+
+       return status;
+}
+
+int ocfs2_info_handle_journal_size(struct inode *inode,
+                                  struct ocfs2_info_request __user *req)
+{
+       int status = -EFAULT;
+       struct ocfs2_info_journal_size oij;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       if (o2info_from_user(oij, req))
+               goto bail;
+
+       oij.ij_journal_size = osb->journal->j_inode->i_size;
+
+       oij.ij_req.ir_flags |= OCFS2_INFO_FL_FILLED;
+
+       if (o2info_to_user(oij, req))
+               goto bail;
+
+       status = 0;
+bail:
+       if (status)
+               o2info_set_request_error(oij, req);
+
+       return status;
+}
+
+int ocfs2_info_handle_unknown(struct inode *inode,
+                             struct ocfs2_info_request __user *req)
+{
+       int status = -EFAULT;
+       struct ocfs2_info_request oir;
+
+       if (o2info_from_user(oir, req))
+               goto bail;
+
+       oir.ir_flags &= ~OCFS2_INFO_FL_FILLED;
+
+       if (o2info_to_user(oir, req))
+               goto bail;
+
+       status = 0;
+bail:
+       if (status)
+               o2info_set_request_error(oir, req);
+
+       return status;
+}
+
+/*
+ * Validate and distinguish OCFS2_IOC_INFO requests.
+ *
+ * - validate the magic number.
+ * - distinguish different requests.
+ * - validate size of different requests.
+ */
+int ocfs2_info_handle_request(struct inode *inode,
+                             struct ocfs2_info_request __user *req)
+{
+       int status = -EFAULT;
+       struct ocfs2_info_request oir;
+
+       if (o2info_from_user(oir, req))
+               goto bail;
+
+       status = -EINVAL;
+       if (oir.ir_magic != OCFS2_INFO_MAGIC)
+               goto bail;
+
+       switch (oir.ir_code) {
+       case OCFS2_INFO_BLOCKSIZE:
+               if (oir.ir_size == sizeof(struct ocfs2_info_blocksize))
+                       status = ocfs2_info_handle_blocksize(inode, req);
+               break;
+       case OCFS2_INFO_CLUSTERSIZE:
+               if (oir.ir_size == sizeof(struct ocfs2_info_clustersize))
+                       status = ocfs2_info_handle_clustersize(inode, req);
+               break;
+       case OCFS2_INFO_MAXSLOTS:
+               if (oir.ir_size == sizeof(struct ocfs2_info_maxslots))
+                       status = ocfs2_info_handle_maxslots(inode, req);
+               break;
+       case OCFS2_INFO_LABEL:
+               if (oir.ir_size == sizeof(struct ocfs2_info_label))
+                       status = ocfs2_info_handle_label(inode, req);
+               break;
+       case OCFS2_INFO_UUID:
+               if (oir.ir_size == sizeof(struct ocfs2_info_uuid))
+                       status = ocfs2_info_handle_uuid(inode, req);
+               break;
+       case OCFS2_INFO_FS_FEATURES:
+               if (oir.ir_size == sizeof(struct ocfs2_info_fs_features))
+                       status = ocfs2_info_handle_fs_features(inode, req);
+               break;
+       case OCFS2_INFO_JOURNAL_SIZE:
+               if (oir.ir_size == sizeof(struct ocfs2_info_journal_size))
+                       status = ocfs2_info_handle_journal_size(inode, req);
+               break;
+       default:
+               status = ocfs2_info_handle_unknown(inode, req);
+               break;
+       }
+
+bail:
+       return status;
+}
+
+int ocfs2_get_request_ptr(struct ocfs2_info *info, int idx,
+                         u64 *req_addr, int compat_flag)
+{
+       int status = -EFAULT;
+       u64 __user *bp = NULL;
+
+       if (compat_flag) {
+#ifdef CONFIG_COMPAT
+               /*
+                * pointer bp stores the base address of a pointers array,
+                * which collects all addresses of separate request.
+                */
+               bp = (u64 __user *)(unsigned long)compat_ptr(info->oi_requests);
+#else
+               BUG();
+#endif
+       } else
+               bp = (u64 __user *)(unsigned long)(info->oi_requests);
+
+       if (o2info_from_user(*req_addr, bp + idx))
+               goto bail;
+
+       status = 0;
+bail:
+       return status;
+}
+
+/*
+ * OCFS2_IOC_INFO handles an array of requests passed from userspace.
+ *
+ * ocfs2_info_handle() recevies a large info aggregation, grab and
+ * validate the request count from header, then break it into small
+ * pieces, later specific handlers can handle them one by one.
+ *
+ * Idea here is to make each separate request small enough to ensure
+ * a better backward&forward compatibility, since a small piece of
+ * request will be less likely to be broken if disk layout get changed.
+ */
+int ocfs2_info_handle(struct inode *inode, struct ocfs2_info *info,
+                     int compat_flag)
+{
+       int i, status = 0;
+       u64 req_addr;
+       struct ocfs2_info_request __user *reqp;
+
+       if ((info->oi_count > OCFS2_INFO_MAX_REQUEST) ||
+           (!info->oi_requests)) {
+               status = -EINVAL;
+               goto bail;
+       }
+
+       for (i = 0; i < info->oi_count; i++) {
+
+               status = ocfs2_get_request_ptr(info, i, &req_addr, compat_flag);
+               if (status)
+                       break;
+
+               reqp = (struct ocfs2_info_request *)(unsigned long)req_addr;
+               if (!reqp) {
+                       status = -EINVAL;
+                       goto bail;
+               }
+
+               status = ocfs2_info_handle_request(inode, reqp);
+               if (status)
+                       break;
+       }
+
+bail:
+       return status;
+}
+
 long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct inode *inode = filp->f_path.dentry->d_inode;
@@ -120,6 +462,7 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        struct reflink_arguments args;
        const char *old_path, *new_path;
        bool preserve;
+       struct ocfs2_info info;
 
        switch (cmd) {
        case OCFS2_IOC_GETFLAGS:
@@ -174,6 +517,12 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                preserve = (args.preserve != 0);
 
                return ocfs2_reflink_ioctl(inode, old_path, new_path, preserve);
+       case OCFS2_IOC_INFO:
+               if (copy_from_user(&info, (struct ocfs2_info __user *)arg,
+                                  sizeof(struct ocfs2_info)))
+                       return -EFAULT;
+
+               return ocfs2_info_handle(inode, &info, 0);
        default:
                return -ENOTTY;
        }
@@ -185,6 +534,7 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
        bool preserve;
        struct reflink_arguments args;
        struct inode *inode = file->f_path.dentry->d_inode;
+       struct ocfs2_info info;
 
        switch (cmd) {
        case OCFS2_IOC32_GETFLAGS:
@@ -209,6 +559,12 @@ long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 
                return ocfs2_reflink_ioctl(inode, compat_ptr(args.old_path),
                                           compat_ptr(args.new_path), preserve);
+       case OCFS2_IOC_INFO:
+               if (copy_from_user(&info, (struct ocfs2_info __user *)arg,
+                                  sizeof(struct ocfs2_info)))
+                       return -EFAULT;
+
+               return ocfs2_info_handle(inode, &info, 1);
        default:
                return -ENOIOCTLCMD;
        }
index 9b57c0350ff9337b20a9c96869e209c925246c4f..faa2303dbf0a4b5bd0b21a013abee4af82dda47f 100644 (file)
@@ -301,7 +301,6 @@ static int ocfs2_commit_cache(struct ocfs2_super *osb)
 {
        int status = 0;
        unsigned int flushed;
-       unsigned long old_id;
        struct ocfs2_journal *journal = NULL;
 
        mlog_entry_void();
@@ -326,7 +325,7 @@ static int ocfs2_commit_cache(struct ocfs2_super *osb)
                goto finally;
        }
 
-       old_id = ocfs2_inc_trans_id(journal);
+       ocfs2_inc_trans_id(journal);
 
        flushed = atomic_read(&journal->j_num_trans);
        atomic_set(&journal->j_num_trans, 0);
@@ -342,9 +341,6 @@ finally:
        return status;
 }
 
-/* pass it NULL and it will allocate a new handle object for you.  If
- * you pass it a handle however, it may still return error, in which
- * case it has free'd the passed handle for you. */
 handle_t *ocfs2_start_trans(struct ocfs2_super *osb, int max_buffs)
 {
        journal_t *journal = osb->journal->j_journal;
@@ -1888,6 +1884,8 @@ void ocfs2_queue_orphan_scan(struct ocfs2_super *osb)
 
        os = &osb->osb_orphan_scan;
 
+       mlog(0, "Begin orphan scan\n");
+
        if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE)
                goto out;
 
@@ -1920,6 +1918,7 @@ void ocfs2_queue_orphan_scan(struct ocfs2_super *osb)
 unlock:
        ocfs2_orphan_scan_unlock(osb, seqno);
 out:
+       mlog(0, "Orphan scan completed\n");
        return;
 }
 
index b5baaa8e710f234b08878c111d84ffe55f52df7d..43e56b97f9c016c923614f887bcce3e9ba58da04 100644 (file)
@@ -67,11 +67,12 @@ struct ocfs2_journal {
        struct buffer_head        *j_bh;      /* Journal disk inode block */
        atomic_t                  j_num_trans; /* Number of transactions
                                                * currently in the system. */
+       spinlock_t                j_lock;
        unsigned long             j_trans_id;
        struct rw_semaphore       j_trans_barrier;
        wait_queue_head_t         j_checkpointed;
 
-       spinlock_t                j_lock;
+       /* both fields protected by j_lock*/
        struct list_head          j_la_cleanups;
        struct work_struct        j_recovery_work;
 };
index 4c18f4ad93b43cae6e5ddcd5a2781fbc79292484..7e32db9c2c993b38e67f5d1282525f0a089b54b0 100644 (file)
@@ -59,10 +59,11 @@ static int ocfs2_fault(struct vm_area_struct *area, struct vm_fault *vmf)
        return ret;
 }
 
-static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
+static int __ocfs2_page_mkwrite(struct file *file, struct buffer_head *di_bh,
                                struct page *page)
 {
        int ret;
+       struct inode *inode = file->f_path.dentry->d_inode;
        struct address_space *mapping = inode->i_mapping;
        loff_t pos = page_offset(page);
        unsigned int len = PAGE_CACHE_SIZE;
@@ -111,7 +112,7 @@ static int __ocfs2_page_mkwrite(struct inode *inode, struct buffer_head *di_bh,
        if (page->index == last_index)
                len = ((size - 1) & ~PAGE_CACHE_MASK) + 1;
 
-       ret = ocfs2_write_begin_nolock(mapping, pos, len, 0, &locked_page,
+       ret = ocfs2_write_begin_nolock(file, mapping, pos, len, 0, &locked_page,
                                       &fsdata, di_bh, page);
        if (ret) {
                if (ret != -ENOSPC)
@@ -159,7 +160,7 @@ static int ocfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
         */
        down_write(&OCFS2_I(inode)->ip_alloc_sem);
 
-       ret = __ocfs2_page_mkwrite(inode, di_bh, page);
+       ret = __ocfs2_page_mkwrite(vma->vm_file, di_bh, page);
 
        up_write(&OCFS2_I(inode)->ip_alloc_sem);
 
index a00dda2e4f16698e5c7d8e0946ba1f09506651c6..e7bde21149aee4f4e1dfed501069358927a064d7 100644 (file)
@@ -171,7 +171,8 @@ bail_add:
                        ret = ERR_PTR(status);
                        goto bail_unlock;
                }
-       }
+       } else
+               ocfs2_dentry_attach_gen(dentry);
 
 bail_unlock:
        /* Don't drop the cluster lock until *after* the d_add --
index c67003b6b5a257d9e914ff1088d132425d8a2cba..d8408217e3bd0657a3446f77a56833a20f03ad52 100644 (file)
@@ -150,26 +150,33 @@ typedef void (*ocfs2_lock_callback)(int status, unsigned long data);
 struct ocfs2_lock_res {
        void                    *l_priv;
        struct ocfs2_lock_res_ops *l_ops;
-       spinlock_t               l_lock;
+
 
        struct list_head         l_blocked_list;
        struct list_head         l_mask_waiters;
 
-       enum ocfs2_lock_type     l_type;
        unsigned long            l_flags;
        char                     l_name[OCFS2_LOCK_ID_MAX_LEN];
-       int                      l_level;
        unsigned int             l_ro_holders;
        unsigned int             l_ex_holders;
-       struct ocfs2_dlm_lksb    l_lksb;
+       unsigned char            l_level;
+
+       /* Data packed - type enum ocfs2_lock_type */
+       unsigned char            l_type;
 
        /* used from AST/BAST funcs. */
-       enum ocfs2_ast_action    l_action;
-       enum ocfs2_unlock_action l_unlock_action;
-       int                      l_requested;
-       int                      l_blocking;
+       /* Data packed - enum type ocfs2_ast_action */
+       unsigned char            l_action;
+       /* Data packed - enum type ocfs2_unlock_action */
+       unsigned char            l_unlock_action;
+       unsigned char            l_requested;
+       unsigned char            l_blocking;
        unsigned int             l_pending_gen;
 
+       spinlock_t               l_lock;
+
+       struct ocfs2_dlm_lksb    l_lksb;
+
        wait_queue_head_t        l_event;
 
        struct list_head         l_debug_list;
@@ -243,7 +250,7 @@ enum ocfs2_local_alloc_state
 
 enum ocfs2_mount_options
 {
-       OCFS2_MOUNT_HB_LOCAL   = 1 << 0, /* Heartbeat started in local mode */
+       OCFS2_MOUNT_HB_LOCAL = 1 << 0, /* Local heartbeat */
        OCFS2_MOUNT_BARRIER = 1 << 1,   /* Use block barriers */
        OCFS2_MOUNT_NOINTR  = 1 << 2,   /* Don't catch signals */
        OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */
@@ -256,6 +263,10 @@ enum ocfs2_mount_options
                                                   control lists */
        OCFS2_MOUNT_USRQUOTA = 1 << 10, /* We support user quotas */
        OCFS2_MOUNT_GRPQUOTA = 1 << 11, /* We support group quotas */
+       OCFS2_MOUNT_COHERENCY_BUFFERED = 1 << 12, /* Allow concurrent O_DIRECT
+                                                    writes */
+       OCFS2_MOUNT_HB_NONE = 1 << 13, /* No heartbeat */
+       OCFS2_MOUNT_HB_GLOBAL = 1 << 14, /* Global heartbeat */
 };
 
 #define OCFS2_OSB_SOFT_RO                      0x0001
@@ -277,7 +288,8 @@ struct ocfs2_super
        struct super_block *sb;
        struct inode *root_inode;
        struct inode *sys_root_inode;
-       struct inode *system_inodes[NUM_SYSTEM_INODES];
+       struct inode *global_system_inodes[NUM_GLOBAL_SYSTEM_INODES];
+       struct inode **local_system_inodes;
 
        struct ocfs2_slot_info *slot_info;
 
@@ -368,6 +380,8 @@ struct ocfs2_super
        struct ocfs2_alloc_stats alloc_stats;
        char dev_str[20];               /* "major,minor" of the device */
 
+       u8 osb_stackflags;
+
        char osb_cluster_stack[OCFS2_STACK_LABEL_LEN + 1];
        struct ocfs2_cluster_connection *cconn;
        struct ocfs2_lock_res osb_super_lockres;
@@ -601,10 +615,35 @@ static inline int ocfs2_is_soft_readonly(struct ocfs2_super *osb)
        return ret;
 }
 
-static inline int ocfs2_userspace_stack(struct ocfs2_super *osb)
+static inline int ocfs2_clusterinfo_valid(struct ocfs2_super *osb)
 {
        return (osb->s_feature_incompat &
-               OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK);
+               (OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK |
+                OCFS2_FEATURE_INCOMPAT_CLUSTERINFO));
+}
+
+static inline int ocfs2_userspace_stack(struct ocfs2_super *osb)
+{
+       if (ocfs2_clusterinfo_valid(osb) &&
+           memcmp(osb->osb_cluster_stack, OCFS2_CLASSIC_CLUSTER_STACK,
+                  OCFS2_STACK_LABEL_LEN))
+               return 1;
+       return 0;
+}
+
+static inline int ocfs2_o2cb_stack(struct ocfs2_super *osb)
+{
+       if (ocfs2_clusterinfo_valid(osb) &&
+           !memcmp(osb->osb_cluster_stack, OCFS2_CLASSIC_CLUSTER_STACK,
+                  OCFS2_STACK_LABEL_LEN))
+               return 1;
+       return 0;
+}
+
+static inline int ocfs2_cluster_o2cb_global_heartbeat(struct ocfs2_super *osb)
+{
+       return ocfs2_o2cb_stack(osb) &&
+               (osb->osb_stackflags & OCFS2_CLUSTER_O2CB_GLOBAL_HEARTBEAT);
 }
 
 static inline int ocfs2_mount_local(struct ocfs2_super *osb)
index fa31d05e41b7e558fa24df43682dbd107b568c76..c2e4f8222e2f0ac707de217555bee7edd51f76d6 100644 (file)
                                         | OCFS2_FEATURE_INCOMPAT_META_ECC \
                                         | OCFS2_FEATURE_INCOMPAT_INDEXED_DIRS \
                                         | OCFS2_FEATURE_INCOMPAT_REFCOUNT_TREE \
-                                        | OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG)
+                                        | OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG  \
+                                        | OCFS2_FEATURE_INCOMPAT_CLUSTERINFO)
 #define OCFS2_FEATURE_RO_COMPAT_SUPP   (OCFS2_FEATURE_RO_COMPAT_UNWRITTEN \
                                         | OCFS2_FEATURE_RO_COMPAT_USRQUOTA \
                                         | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)
 /* Discontigous block groups */
 #define OCFS2_FEATURE_INCOMPAT_DISCONTIG_BG    0x2000
 
+/*
+ * Incompat bit to indicate useable clusterinfo with stackflags for all
+ * cluster stacks (userspace adnd o2cb). If this bit is set,
+ * INCOMPAT_USERSPACE_STACK becomes superfluous and thus should not be set.
+ */
+#define OCFS2_FEATURE_INCOMPAT_CLUSTERINFO     0x4000
+
 /*
  * backup superblock flag is used to indicate that this volume
  * has backup superblocks.
 #define OCFS2_VOL_UUID_LEN             16
 #define OCFS2_MAX_VOL_LABEL_LEN                64
 
-/* The alternate, userspace stack fields */
+/* The cluster stack fields */
 #define OCFS2_STACK_LABEL_LEN          4
 #define OCFS2_CLUSTER_NAME_LEN         16
 
+/* Classic (historically speaking) cluster stack */
+#define OCFS2_CLASSIC_CLUSTER_STACK    "o2cb"
+
 /* Journal limits (in bytes) */
 #define OCFS2_MIN_JOURNAL_SIZE         (4 * 1024 * 1024)
 
  */
 #define OCFS2_MIN_XATTR_INLINE_SIZE     256
 
+/*
+ * Cluster info flags (ocfs2_cluster_info.ci_stackflags)
+ */
+#define OCFS2_CLUSTER_O2CB_GLOBAL_HEARTBEAT    (0x01)
+
 struct ocfs2_system_inode_info {
        char    *si_name;
        int     si_iflags;
@@ -322,6 +338,7 @@ enum {
        USER_QUOTA_SYSTEM_INODE,
        GROUP_QUOTA_SYSTEM_INODE,
 #define OCFS2_LAST_GLOBAL_SYSTEM_INODE GROUP_QUOTA_SYSTEM_INODE
+#define OCFS2_FIRST_LOCAL_SYSTEM_INODE ORPHAN_DIR_SYSTEM_INODE
        ORPHAN_DIR_SYSTEM_INODE,
        EXTENT_ALLOC_SYSTEM_INODE,
        INODE_ALLOC_SYSTEM_INODE,
@@ -330,8 +347,12 @@ enum {
        TRUNCATE_LOG_SYSTEM_INODE,
        LOCAL_USER_QUOTA_SYSTEM_INODE,
        LOCAL_GROUP_QUOTA_SYSTEM_INODE,
+#define OCFS2_LAST_LOCAL_SYSTEM_INODE LOCAL_GROUP_QUOTA_SYSTEM_INODE
        NUM_SYSTEM_INODES
 };
+#define NUM_GLOBAL_SYSTEM_INODES OCFS2_LAST_GLOBAL_SYSTEM_INODE
+#define NUM_LOCAL_SYSTEM_INODES        \
+               (NUM_SYSTEM_INODES - OCFS2_FIRST_LOCAL_SYSTEM_INODE)
 
 static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = {
        /* Global system inodes (single copy) */
@@ -360,6 +381,7 @@ static struct ocfs2_system_inode_info ocfs2_system_inodes[NUM_SYSTEM_INODES] = {
 /* Parameter passed from mount.ocfs2 to module */
 #define OCFS2_HB_NONE                  "heartbeat=none"
 #define OCFS2_HB_LOCAL                 "heartbeat=local"
+#define OCFS2_HB_GLOBAL                        "heartbeat=global"
 
 /*
  * OCFS2 directory file types.  Only the low 3 bits are used.  The
@@ -566,9 +588,21 @@ struct ocfs2_slot_map_extended {
  */
 };
 
+/*
+ * ci_stackflags is only valid if the incompat bit
+ * OCFS2_FEATURE_INCOMPAT_CLUSTERINFO is set.
+ */
 struct ocfs2_cluster_info {
 /*00*/ __u8   ci_stack[OCFS2_STACK_LABEL_LEN];
-       __le32 ci_reserved;
+       union {
+               __le32 ci_reserved;
+               struct {
+                       __u8 ci_stackflags;
+                       __u8 ci_reserved1;
+                       __u8 ci_reserved2;
+                       __u8 ci_reserved3;
+               };
+       };
 /*08*/ __u8   ci_cluster[OCFS2_CLUSTER_NAME_LEN];
 /*18*/
 };
@@ -605,9 +639,9 @@ struct ocfs2_super_block {
                                         * group header */
 /*50*/ __u8  s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */
 /*90*/ __u8  s_uuid[OCFS2_VOL_UUID_LEN];       /* 128-bit uuid */
-/*A0*/  struct ocfs2_cluster_info s_cluster_info; /* Selected userspace
-                                                    stack.  Only valid
-                                                    with INCOMPAT flag. */
+/*A0*/  struct ocfs2_cluster_info s_cluster_info; /* Only valid if either
+                                                    userspace or clusterinfo
+                                                    INCOMPAT flag set. */
 /*B8*/ __le16 s_xattr_inline_size;     /* extended attribute inline size
                                           for this fs*/
        __le16 s_reserved0;
index 5d241505690b71e2ec0b259cbc39f1ed46d683d5..b46f39bf7438d5048dd5637d5762b4d6c44990e4 100644 (file)
@@ -76,4 +76,99 @@ struct reflink_arguments {
 };
 #define OCFS2_IOC_REFLINK      _IOW('o', 4, struct reflink_arguments)
 
+/* Following definitions dedicated for ocfs2_info_request ioctls. */
+#define OCFS2_INFO_MAX_REQUEST         (50)
+#define OCFS2_TEXT_UUID_LEN            (OCFS2_VOL_UUID_LEN * 2)
+
+/* Magic number of all requests */
+#define OCFS2_INFO_MAGIC               (0x4F32494E)
+
+/*
+ * Always try to separate info request into small pieces to
+ * guarantee the backward&forward compatibility.
+ */
+struct ocfs2_info {
+       __u64 oi_requests;      /* Array of __u64 pointers to requests */
+       __u32 oi_count;         /* Number of requests in info_requests */
+       __u32 oi_pad;
+};
+
+struct ocfs2_info_request {
+/*00*/ __u32 ir_magic; /* Magic number */
+       __u32 ir_code;  /* Info request code */
+       __u32 ir_size;  /* Size of request */
+       __u32 ir_flags; /* Request flags */
+/*10*/                 /* Request specific fields */
+};
+
+struct ocfs2_info_clustersize {
+       struct ocfs2_info_request ic_req;
+       __u32 ic_clustersize;
+       __u32 ic_pad;
+};
+
+struct ocfs2_info_blocksize {
+       struct ocfs2_info_request ib_req;
+       __u32 ib_blocksize;
+       __u32 ib_pad;
+};
+
+struct ocfs2_info_maxslots {
+       struct ocfs2_info_request im_req;
+       __u32 im_max_slots;
+       __u32 im_pad;
+};
+
+struct ocfs2_info_label {
+       struct ocfs2_info_request il_req;
+       __u8    il_label[OCFS2_MAX_VOL_LABEL_LEN];
+} __attribute__ ((packed));
+
+struct ocfs2_info_uuid {
+       struct ocfs2_info_request iu_req;
+       __u8    iu_uuid_str[OCFS2_TEXT_UUID_LEN + 1];
+} __attribute__ ((packed));
+
+struct ocfs2_info_fs_features {
+       struct ocfs2_info_request if_req;
+       __u32 if_compat_features;
+       __u32 if_incompat_features;
+       __u32 if_ro_compat_features;
+       __u32 if_pad;
+};
+
+struct ocfs2_info_journal_size {
+       struct ocfs2_info_request ij_req;
+       __u64 ij_journal_size;
+};
+
+/* Codes for ocfs2_info_request */
+enum ocfs2_info_type {
+       OCFS2_INFO_CLUSTERSIZE = 1,
+       OCFS2_INFO_BLOCKSIZE,
+       OCFS2_INFO_MAXSLOTS,
+       OCFS2_INFO_LABEL,
+       OCFS2_INFO_UUID,
+       OCFS2_INFO_FS_FEATURES,
+       OCFS2_INFO_JOURNAL_SIZE,
+       OCFS2_INFO_NUM_TYPES
+};
+
+/* Flags for struct ocfs2_info_request */
+/* Filled by the caller */
+#define OCFS2_INFO_FL_NON_COHERENT     (0x00000001)    /* Cluster coherency not
+                                                          required. This is a hint.
+                                                          It is up to ocfs2 whether
+                                                          the request can be fulfilled
+                                                          without locking. */
+/* Filled by ocfs2 */
+#define OCFS2_INFO_FL_FILLED           (0x40000000)    /* Filesystem understood
+                                                          this request and
+                                                          filled in the answer */
+
+#define OCFS2_INFO_FL_ERROR            (0x80000000)    /* Error happened during
+                                                          request handling. */
+
+#define OCFS2_IOC_INFO         _IOR('o', 5, struct ocfs2_info)
+
 #endif /* OCFS2_IOCTL_H */
index efdd7560740655beba6f53dccef235b5ce89cdbf..b5f9160e93e9119b949451bb3e5db66b3c1df62c 100644 (file)
@@ -49,6 +49,7 @@
 
 struct ocfs2_cow_context {
        struct inode *inode;
+       struct file *file;
        u32 cow_start;
        u32 cow_len;
        struct ocfs2_extent_tree data_et;
@@ -2932,13 +2933,16 @@ static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
        u64 new_block = ocfs2_clusters_to_blocks(sb, new_cluster);
        struct page *page;
        pgoff_t page_index;
-       unsigned int from, to;
+       unsigned int from, to, readahead_pages;
        loff_t offset, end, map_end;
        struct address_space *mapping = context->inode->i_mapping;
 
        mlog(0, "old_cluster %u, new %u, len %u at offset %u\n", old_cluster,
             new_cluster, new_len, cpos);
 
+       readahead_pages =
+               (ocfs2_cow_contig_clusters(sb) <<
+                OCFS2_SB(sb)->s_clustersize_bits) >> PAGE_CACHE_SHIFT;
        offset = ((loff_t)cpos) << OCFS2_SB(sb)->s_clustersize_bits;
        end = offset + (new_len << OCFS2_SB(sb)->s_clustersize_bits);
        /*
@@ -2969,6 +2973,14 @@ static int ocfs2_duplicate_clusters_by_page(handle_t *handle,
                if (PAGE_CACHE_SIZE <= OCFS2_SB(sb)->s_clustersize)
                        BUG_ON(PageDirty(page));
 
+               if (PageReadahead(page) && context->file) {
+                       page_cache_async_readahead(mapping,
+                                                  &context->file->f_ra,
+                                                  context->file,
+                                                  page, page_index,
+                                                  readahead_pages);
+               }
+
                if (!PageUptodate(page)) {
                        ret = block_read_full_page(page, ocfs2_get_block);
                        if (ret) {
@@ -3409,12 +3421,35 @@ static int ocfs2_replace_cow(struct ocfs2_cow_context *context)
        return ret;
 }
 
+static void ocfs2_readahead_for_cow(struct inode *inode,
+                                   struct file *file,
+                                   u32 start, u32 len)
+{
+       struct address_space *mapping;
+       pgoff_t index;
+       unsigned long num_pages;
+       int cs_bits = OCFS2_SB(inode->i_sb)->s_clustersize_bits;
+
+       if (!file)
+               return;
+
+       mapping = file->f_mapping;
+       num_pages = (len << cs_bits) >> PAGE_CACHE_SHIFT;
+       if (!num_pages)
+               num_pages = 1;
+
+       index = ((loff_t)start << cs_bits) >> PAGE_CACHE_SHIFT;
+       page_cache_sync_readahead(mapping, &file->f_ra, file,
+                                 index, num_pages);
+}
+
 /*
  * Starting at cpos, try to CoW write_len clusters.  Don't CoW
  * past max_cpos.  This will stop when it runs into a hole or an
  * unrefcounted extent.
  */
 static int ocfs2_refcount_cow_hunk(struct inode *inode,
+                                  struct file *file,
                                   struct buffer_head *di_bh,
                                   u32 cpos, u32 write_len, u32 max_cpos)
 {
@@ -3443,6 +3478,8 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
 
        BUG_ON(cow_len == 0);
 
+       ocfs2_readahead_for_cow(inode, file, cow_start, cow_len);
+
        context = kzalloc(sizeof(struct ocfs2_cow_context), GFP_NOFS);
        if (!context) {
                ret = -ENOMEM;
@@ -3464,6 +3501,7 @@ static int ocfs2_refcount_cow_hunk(struct inode *inode,
        context->ref_root_bh = ref_root_bh;
        context->cow_duplicate_clusters = ocfs2_duplicate_clusters_by_page;
        context->get_clusters = ocfs2_di_get_clusters;
+       context->file = file;
 
        ocfs2_init_dinode_extent_tree(&context->data_et,
                                      INODE_CACHE(inode), di_bh);
@@ -3492,6 +3530,7 @@ out:
  * clusters between cpos and cpos+write_len are safe to modify.
  */
 int ocfs2_refcount_cow(struct inode *inode,
+                      struct file *file,
                       struct buffer_head *di_bh,
                       u32 cpos, u32 write_len, u32 max_cpos)
 {
@@ -3511,7 +3550,7 @@ int ocfs2_refcount_cow(struct inode *inode,
                        num_clusters = write_len;
 
                if (ext_flags & OCFS2_EXT_REFCOUNTED) {
-                       ret = ocfs2_refcount_cow_hunk(inode, di_bh, cpos,
+                       ret = ocfs2_refcount_cow_hunk(inode, file, di_bh, cpos,
                                                      num_clusters, max_cpos);
                        if (ret) {
                                mlog_errno(ret);
index 9983ba1570e20073bb45e3d8e47f78e320afe1a5..c8ce46f7d8e30ee842cc8966a8c034aefae3b98b 100644 (file)
@@ -21,14 +21,14 @@ struct ocfs2_refcount_tree {
        struct rb_node rf_node;
        u64 rf_blkno;
        u32 rf_generation;
+       struct kref rf_getcnt;
        struct rw_semaphore rf_sem;
        struct ocfs2_lock_res rf_lockres;
-       struct kref rf_getcnt;
        int rf_removed;
 
        /* the following 4 fields are used by caching_info. */
-       struct ocfs2_caching_info rf_ci;
        spinlock_t rf_lock;
+       struct ocfs2_caching_info rf_ci;
        struct mutex rf_io_mutex;
        struct super_block *rf_sb;
 };
@@ -52,7 +52,8 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode,
                                          u32 clusters,
                                          int *credits,
                                          int *ref_blocks);
-int ocfs2_refcount_cow(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_refcount_cow(struct inode *inode,
+                      struct file *filep, struct buffer_head *di_bh,
                       u32 cpos, u32 write_len, u32 max_cpos);
 
 typedef int (ocfs2_post_refcount_func)(struct inode *inode,
index bfbd7e9e949f0a26bbf0afecba362a449c6e45cf..ab4e0172cc1d11abc3c5d70c62a9298d652fb096 100644 (file)
@@ -357,7 +357,7 @@ static int ocfs2_map_slot_buffers(struct ocfs2_super *osb,
 {
        int status = 0;
        u64 blkno;
-       unsigned long long blocks, bytes;
+       unsigned long long blocks, bytes = 0;
        unsigned int i;
        struct buffer_head *bh;
 
index 0d3049f696c5418448173ed3538020bd5d51b9d0..19965b00c43caee7df4e09428775a55150ba9f8c 100644 (file)
@@ -283,6 +283,8 @@ static int o2cb_cluster_connect(struct ocfs2_cluster_connection *conn)
        /* for now we only have one cluster/node, make sure we see it
         * in the heartbeat universe */
        if (!o2hb_check_local_node_heartbeating()) {
+               if (o2hb_global_heartbeat_active())
+                       mlog(ML_ERROR, "Global heartbeat not started\n");
                rc = -EINVAL;
                goto out;
        }
index 849c2f0e0a0e664e983adf61f620abedf87fcb72..5fed60de7630f4ed94c4ab429eb8f7187f679468 100644 (file)
@@ -1380,6 +1380,14 @@ static inline int ocfs2_block_group_set_bits(handle_t *handle,
        }
 
        le16_add_cpu(&bg->bg_free_bits_count, -num_bits);
+       if (le16_to_cpu(bg->bg_free_bits_count) > le16_to_cpu(bg->bg_bits)) {
+               ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit"
+                           " count %u but claims %u are freed. num_bits %d",
+                           (unsigned long long)le64_to_cpu(bg->bg_blkno),
+                           le16_to_cpu(bg->bg_bits),
+                           le16_to_cpu(bg->bg_free_bits_count), num_bits);
+               return -EROFS;
+       }
        while(num_bits--)
                ocfs2_set_bit(bit_off++, bitmap);
 
@@ -2419,6 +2427,14 @@ static int ocfs2_block_group_clear_bits(handle_t *handle,
                                (unsigned long *) undo_bg->bg_bitmap);
        }
        le16_add_cpu(&bg->bg_free_bits_count, num_bits);
+       if (le16_to_cpu(bg->bg_free_bits_count) > le16_to_cpu(bg->bg_bits)) {
+               ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit"
+                           " count %u but claims %u are freed. num_bits %d",
+                           (unsigned long long)le64_to_cpu(bg->bg_blkno),
+                           le16_to_cpu(bg->bg_bits),
+                           le16_to_cpu(bg->bg_free_bits_count), num_bits);
+               return -EROFS;
+       }
 
        if (undo_fn)
                jbd_unlock_bh_state(group_bh);
index fa1be1b304d10b7bf30c4ecb2c7a3fd9b3ecd8ca..a8a0ca44f88f30d9d783301dc2a10d67df165510 100644 (file)
@@ -162,6 +162,7 @@ enum {
        Opt_nointr,
        Opt_hb_none,
        Opt_hb_local,
+       Opt_hb_global,
        Opt_data_ordered,
        Opt_data_writeback,
        Opt_atime_quantum,
@@ -177,6 +178,8 @@ enum {
        Opt_noacl,
        Opt_usrquota,
        Opt_grpquota,
+       Opt_coherency_buffered,
+       Opt_coherency_full,
        Opt_resv_level,
        Opt_dir_resv_level,
        Opt_err,
@@ -190,6 +193,7 @@ static const match_table_t tokens = {
        {Opt_nointr, "nointr"},
        {Opt_hb_none, OCFS2_HB_NONE},
        {Opt_hb_local, OCFS2_HB_LOCAL},
+       {Opt_hb_global, OCFS2_HB_GLOBAL},
        {Opt_data_ordered, "data=ordered"},
        {Opt_data_writeback, "data=writeback"},
        {Opt_atime_quantum, "atime_quantum=%u"},
@@ -205,6 +209,8 @@ static const match_table_t tokens = {
        {Opt_noacl, "noacl"},
        {Opt_usrquota, "usrquota"},
        {Opt_grpquota, "grpquota"},
+       {Opt_coherency_buffered, "coherency=buffered"},
+       {Opt_coherency_full, "coherency=full"},
        {Opt_resv_level, "resv_level=%u"},
        {Opt_dir_resv_level, "dir_resv_level=%u"},
        {Opt_err, NULL}
@@ -514,11 +520,11 @@ static void ocfs2_release_system_inodes(struct ocfs2_super *osb)
 
        mlog_entry_void();
 
-       for (i = 0; i < NUM_SYSTEM_INODES; i++) {
-               inode = osb->system_inodes[i];
+       for (i = 0; i < NUM_GLOBAL_SYSTEM_INODES; i++) {
+               inode = osb->global_system_inodes[i];
                if (inode) {
                        iput(inode);
-                       osb->system_inodes[i] = NULL;
+                       osb->global_system_inodes[i] = NULL;
                }
        }
 
@@ -534,6 +540,20 @@ static void ocfs2_release_system_inodes(struct ocfs2_super *osb)
                osb->root_inode = NULL;
        }
 
+       if (!osb->local_system_inodes)
+               goto out;
+
+       for (i = 0; i < NUM_LOCAL_SYSTEM_INODES * osb->max_slots; i++) {
+               if (osb->local_system_inodes[i]) {
+                       iput(osb->local_system_inodes[i]);
+                       osb->local_system_inodes[i] = NULL;
+               }
+       }
+
+       kfree(osb->local_system_inodes);
+       osb->local_system_inodes = NULL;
+
+out:
        mlog_exit(0);
 }
 
@@ -608,6 +628,7 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
        int ret = 0;
        struct mount_options parsed_options;
        struct ocfs2_super *osb = OCFS2_SB(sb);
+       u32 tmp;
 
        lock_kernel();
 
@@ -617,8 +638,9 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
                goto out;
        }
 
-       if ((osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) !=
-           (parsed_options.mount_opt & OCFS2_MOUNT_HB_LOCAL)) {
+       tmp = OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL |
+               OCFS2_MOUNT_HB_NONE;
+       if ((osb->s_mount_opt & tmp) != (parsed_options.mount_opt & tmp)) {
                ret = -EINVAL;
                mlog(ML_ERROR, "Cannot change heartbeat mode on remount\n");
                goto out;
@@ -809,23 +831,29 @@ bail:
 
 static int ocfs2_verify_heartbeat(struct ocfs2_super *osb)
 {
-       if (ocfs2_mount_local(osb)) {
-               if (osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) {
+       u32 hb_enabled = OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL;
+
+       if (osb->s_mount_opt & hb_enabled) {
+               if (ocfs2_mount_local(osb)) {
                        mlog(ML_ERROR, "Cannot heartbeat on a locally "
                             "mounted device.\n");
                        return -EINVAL;
                }
-       }
-
-       if (ocfs2_userspace_stack(osb)) {
-               if (osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) {
+               if (ocfs2_userspace_stack(osb)) {
                        mlog(ML_ERROR, "Userspace stack expected, but "
                             "o2cb heartbeat arguments passed to mount\n");
                        return -EINVAL;
                }
+               if (((osb->s_mount_opt & OCFS2_MOUNT_HB_GLOBAL) &&
+                    !ocfs2_cluster_o2cb_global_heartbeat(osb)) ||
+                   ((osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) &&
+                    ocfs2_cluster_o2cb_global_heartbeat(osb))) {
+                       mlog(ML_ERROR, "Mismatching o2cb heartbeat modes\n");
+                       return -EINVAL;
+               }
        }
 
-       if (!(osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL)) {
+       if (!(osb->s_mount_opt & hb_enabled)) {
                if (!ocfs2_mount_local(osb) && !ocfs2_is_hard_readonly(osb) &&
                    !ocfs2_userspace_stack(osb)) {
                        mlog(ML_ERROR, "Heartbeat has to be started to mount "
@@ -1291,6 +1319,7 @@ static int ocfs2_parse_options(struct super_block *sb,
 {
        int status;
        char *p;
+       u32 tmp;
 
        mlog_entry("remount: %d, options: \"%s\"\n", is_remount,
                   options ? options : "(none)");
@@ -1322,7 +1351,10 @@ static int ocfs2_parse_options(struct super_block *sb,
                        mopt->mount_opt |= OCFS2_MOUNT_HB_LOCAL;
                        break;
                case Opt_hb_none:
-                       mopt->mount_opt &= ~OCFS2_MOUNT_HB_LOCAL;
+                       mopt->mount_opt |= OCFS2_MOUNT_HB_NONE;
+                       break;
+               case Opt_hb_global:
+                       mopt->mount_opt |= OCFS2_MOUNT_HB_GLOBAL;
                        break;
                case Opt_barrier:
                        if (match_int(&args[0], &option)) {
@@ -1438,6 +1470,12 @@ static int ocfs2_parse_options(struct super_block *sb,
                case Opt_grpquota:
                        mopt->mount_opt |= OCFS2_MOUNT_GRPQUOTA;
                        break;
+               case Opt_coherency_buffered:
+                       mopt->mount_opt |= OCFS2_MOUNT_COHERENCY_BUFFERED;
+                       break;
+               case Opt_coherency_full:
+                       mopt->mount_opt &= ~OCFS2_MOUNT_COHERENCY_BUFFERED;
+                       break;
                case Opt_acl:
                        mopt->mount_opt |= OCFS2_MOUNT_POSIX_ACL;
                        mopt->mount_opt &= ~OCFS2_MOUNT_NO_POSIX_ACL;
@@ -1477,6 +1515,15 @@ static int ocfs2_parse_options(struct super_block *sb,
                }
        }
 
+       /* Ensure only one heartbeat mode */
+       tmp = mopt->mount_opt & (OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL |
+                                OCFS2_MOUNT_HB_NONE);
+       if (hweight32(tmp) != 1) {
+               mlog(ML_ERROR, "Invalid heartbeat mount options\n");
+               status = 0;
+               goto bail;
+       }
+
        status = 1;
 
 bail:
@@ -1490,10 +1537,14 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
        unsigned long opts = osb->s_mount_opt;
        unsigned int local_alloc_megs;
 
-       if (opts & OCFS2_MOUNT_HB_LOCAL)
-               seq_printf(s, ",_netdev,heartbeat=local");
-       else
-               seq_printf(s, ",heartbeat=none");
+       if (opts & (OCFS2_MOUNT_HB_LOCAL | OCFS2_MOUNT_HB_GLOBAL)) {
+               seq_printf(s, ",_netdev");
+               if (opts & OCFS2_MOUNT_HB_LOCAL)
+                       seq_printf(s, ",%s", OCFS2_HB_LOCAL);
+               else
+                       seq_printf(s, ",%s", OCFS2_HB_GLOBAL);
+       } else
+               seq_printf(s, ",%s", OCFS2_HB_NONE);
 
        if (opts & OCFS2_MOUNT_NOINTR)
                seq_printf(s, ",nointr");
@@ -1536,6 +1587,11 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
        if (opts & OCFS2_MOUNT_GRPQUOTA)
                seq_printf(s, ",grpquota");
 
+       if (opts & OCFS2_MOUNT_COHERENCY_BUFFERED)
+               seq_printf(s, ",coherency=buffered");
+       else
+               seq_printf(s, ",coherency=full");
+
        if (opts & OCFS2_MOUNT_NOUSERXATTR)
                seq_printf(s, ",nouser_xattr");
        else
@@ -1990,6 +2046,36 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu
        return 0;
 }
 
+/* Make sure entire volume is addressable by our journal.  Requires
+   osb_clusters_at_boot to be valid and for the journal to have been
+   initialized by ocfs2_journal_init(). */
+static int ocfs2_journal_addressable(struct ocfs2_super *osb)
+{
+       int status = 0;
+       u64 max_block =
+               ocfs2_clusters_to_blocks(osb->sb,
+                                        osb->osb_clusters_at_boot) - 1;
+
+       /* 32-bit block number is always OK. */
+       if (max_block <= (u32)~0ULL)
+               goto out;
+
+       /* Volume is "huge", so see if our journal is new enough to
+          support it. */
+       if (!(OCFS2_HAS_COMPAT_FEATURE(osb->sb,
+                                      OCFS2_FEATURE_COMPAT_JBD2_SB) &&
+             jbd2_journal_check_used_features(osb->journal->j_journal, 0, 0,
+                                              JBD2_FEATURE_INCOMPAT_64BIT))) {
+               mlog(ML_ERROR, "The journal cannot address the entire volume. "
+                    "Enable the 'block64' journal option with tunefs.ocfs2");
+               status = -EFBIG;
+               goto out;
+       }
+
+ out:
+       return status;
+}
+
 static int ocfs2_initialize_super(struct super_block *sb,
                                  struct buffer_head *bh,
                                  int sector_size,
@@ -2002,6 +2088,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
        struct ocfs2_journal *journal;
        __le32 uuid_net_key;
        struct ocfs2_super *osb;
+       u64 total_blocks;
 
        mlog_entry_void();
 
@@ -2060,6 +2147,15 @@ static int ocfs2_initialize_super(struct super_block *sb,
        snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u",
                 MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev));
 
+       osb->max_slots = le16_to_cpu(di->id2.i_super.s_max_slots);
+       if (osb->max_slots > OCFS2_MAX_SLOTS || osb->max_slots == 0) {
+               mlog(ML_ERROR, "Invalid number of node slots (%u)\n",
+                    osb->max_slots);
+               status = -EINVAL;
+               goto bail;
+       }
+       mlog(0, "max_slots for this device: %u\n", osb->max_slots);
+
        ocfs2_orphan_scan_init(osb);
 
        status = ocfs2_recovery_init(osb);
@@ -2098,15 +2194,6 @@ static int ocfs2_initialize_super(struct super_block *sb,
                goto bail;
        }
 
-       osb->max_slots = le16_to_cpu(di->id2.i_super.s_max_slots);
-       if (osb->max_slots > OCFS2_MAX_SLOTS || osb->max_slots == 0) {
-               mlog(ML_ERROR, "Invalid number of node slots (%u)\n",
-                    osb->max_slots);
-               status = -EINVAL;
-               goto bail;
-       }
-       mlog(0, "max_slots for this device: %u\n", osb->max_slots);
-
        osb->slot_recovery_generations =
                kcalloc(osb->max_slots, sizeof(*osb->slot_recovery_generations),
                        GFP_KERNEL);
@@ -2149,7 +2236,9 @@ static int ocfs2_initialize_super(struct super_block *sb,
                goto bail;
        }
 
-       if (ocfs2_userspace_stack(osb)) {
+       if (ocfs2_clusterinfo_valid(osb)) {
+               osb->osb_stackflags =
+                       OCFS2_RAW_SB(di)->s_cluster_info.ci_stackflags;
                memcpy(osb->osb_cluster_stack,
                       OCFS2_RAW_SB(di)->s_cluster_info.ci_stack,
                       OCFS2_STACK_LABEL_LEN);
@@ -2214,11 +2303,15 @@ static int ocfs2_initialize_super(struct super_block *sb,
                goto bail;
        }
 
-       if (ocfs2_clusters_to_blocks(osb->sb, le32_to_cpu(di->i_clusters) - 1)
-           > (u32)~0UL) {
-               mlog(ML_ERROR, "Volume might try to write to blocks beyond "
-                    "what jbd can address in 32 bits.\n");
-               status = -EINVAL;
+       total_blocks = ocfs2_clusters_to_blocks(osb->sb,
+                                               le32_to_cpu(di->i_clusters));
+
+       status = generic_check_addressable(osb->sb->s_blocksize_bits,
+                                          total_blocks);
+       if (status) {
+               mlog(ML_ERROR, "Volume too large "
+                    "to mount safely on this system");
+               status = -EFBIG;
                goto bail;
        }
 
@@ -2380,6 +2473,12 @@ static int ocfs2_check_volume(struct ocfs2_super *osb)
                goto finally;
        }
 
+       /* Now that journal has been initialized, check to make sure
+          entire volume is addressable. */
+       status = ocfs2_journal_addressable(osb);
+       if (status)
+               goto finally;
+
        /* If the journal was unmounted cleanly then we don't want to
         * recover anything. Otherwise, journal_load will do that
         * dirty work for us :) */
index bfe7190cdbf1b0969cc5e2ade3096a9cea16e9ad..902efb23b6a66cbe086e3d6f0b95fb883d6f95b2 100644 (file)
@@ -44,11 +44,6 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb,
                                                   int type,
                                                   u32 slot);
 
-static inline int is_global_system_inode(int type);
-static inline int is_in_system_inode_array(struct ocfs2_super *osb,
-                                          int type,
-                                          u32 slot);
-
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key ocfs2_sysfile_cluster_lock_key[NUM_SYSTEM_INODES];
 #endif
@@ -59,11 +54,52 @@ static inline int is_global_system_inode(int type)
                type <= OCFS2_LAST_GLOBAL_SYSTEM_INODE;
 }
 
-static inline int is_in_system_inode_array(struct ocfs2_super *osb,
-                                          int type,
-                                          u32 slot)
+static struct inode **get_local_system_inode(struct ocfs2_super *osb,
+                                            int type,
+                                            u32 slot)
 {
-       return slot == osb->slot_num || is_global_system_inode(type);
+       int index;
+       struct inode **local_system_inodes, **free = NULL;
+
+       BUG_ON(slot == OCFS2_INVALID_SLOT);
+       BUG_ON(type < OCFS2_FIRST_LOCAL_SYSTEM_INODE ||
+              type > OCFS2_LAST_LOCAL_SYSTEM_INODE);
+
+       spin_lock(&osb->osb_lock);
+       local_system_inodes = osb->local_system_inodes;
+       spin_unlock(&osb->osb_lock);
+
+       if (unlikely(!local_system_inodes)) {
+               local_system_inodes = kzalloc(sizeof(struct inode *) *
+                                             NUM_LOCAL_SYSTEM_INODES *
+                                             osb->max_slots,
+                                             GFP_NOFS);
+               if (!local_system_inodes) {
+                       mlog_errno(-ENOMEM);
+                       /*
+                        * return NULL here so that ocfs2_get_sytem_file_inodes
+                        * will try to create an inode and use it. We will try
+                        * to initialize local_system_inodes next time.
+                        */
+                       return NULL;
+               }
+
+               spin_lock(&osb->osb_lock);
+               if (osb->local_system_inodes) {
+                       /* Someone has initialized it for us. */
+                       free = local_system_inodes;
+                       local_system_inodes = osb->local_system_inodes;
+               } else
+                       osb->local_system_inodes = local_system_inodes;
+               spin_unlock(&osb->osb_lock);
+               if (unlikely(free))
+                       kfree(free);
+       }
+
+       index = (slot * NUM_LOCAL_SYSTEM_INODES) +
+               (type - OCFS2_FIRST_LOCAL_SYSTEM_INODE);
+
+       return &local_system_inodes[index];
 }
 
 struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
@@ -74,8 +110,10 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
        struct inode **arr = NULL;
 
        /* avoid the lookup if cached in local system file array */
-       if (is_in_system_inode_array(osb, type, slot))
-               arr = &(osb->system_inodes[type]);
+       if (is_global_system_inode(type)) {
+               arr = &(osb->global_system_inodes[type]);
+       } else
+               arr = get_local_system_inode(osb, type, slot);
 
        if (arr && ((inode = *arr) != NULL)) {
                /* get a ref in addition to the array ref */
index 06fa5e77c40ef7aa0a3c0483ddbf3b9dd59f9dcf..67cd43914641f5d3d522c098763437e21b7c7f46 100644 (file)
@@ -7081,7 +7081,7 @@ static int ocfs2_reflink_xattr_in_block(struct ocfs2_xattr_reflink *args,
                goto out;
        }
 
-       if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED))
+       if (!indexed)
                ret = ocfs2_reflink_xattr_block(args, blk_bh, new_blk_bh);
        else
                ret = ocfs2_reflink_xattr_tree(args, blk_bh, new_blk_bh);
index 23c1e598792a088cfdd757030f9d733251943fb7..442f34ff1af80178ee63e9a7d8ae2abe3df6154e 100644 (file)
@@ -148,6 +148,65 @@ void sysfs_remove_group(struct kobject * kobj,
        sysfs_put(sd);
 }
 
+/**
+ * sysfs_merge_group - merge files into a pre-existing attribute group.
+ * @kobj:      The kobject containing the group.
+ * @grp:       The files to create and the attribute group they belong to.
+ *
+ * This function returns an error if the group doesn't exist or any of the
+ * files already exist in that group, in which case none of the new files
+ * are created.
+ */
+int sysfs_merge_group(struct kobject *kobj,
+                      const struct attribute_group *grp)
+{
+       struct sysfs_dirent *dir_sd;
+       int error = 0;
+       struct attribute *const *attr;
+       int i;
+
+       if (grp)
+               dir_sd = sysfs_get_dirent(kobj->sd, NULL, grp->name);
+       else
+               dir_sd = sysfs_get(kobj->sd);
+       if (!dir_sd)
+               return -ENOENT;
+
+       for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr))
+               error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR);
+       if (error) {
+               while (--i >= 0)
+                       sysfs_hash_and_remove(dir_sd, NULL, (*--attr)->name);
+       }
+       sysfs_put(dir_sd);
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(sysfs_merge_group);
+
+/**
+ * sysfs_unmerge_group - remove files from a pre-existing attribute group.
+ * @kobj:      The kobject containing the group.
+ * @grp:       The files to remove and the attribute group they belong to.
+ */
+void sysfs_unmerge_group(struct kobject *kobj,
+                      const struct attribute_group *grp)
+{
+       struct sysfs_dirent *dir_sd;
+       struct attribute *const *attr;
+
+       if (grp)
+               dir_sd = sysfs_get_dirent(kobj->sd, NULL, grp->name);
+       else
+               dir_sd = sysfs_get(kobj->sd);
+       if (dir_sd) {
+               for (attr = grp->attrs; *attr; ++attr)
+                       sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
+               sysfs_put(dir_sd);
+       }
+}
+EXPORT_SYMBOL_GPL(sysfs_unmerge_group);
+
 
 EXPORT_SYMBOL_GPL(sysfs_create_group);
 EXPORT_SYMBOL_GPL(sysfs_update_group);
index e53347fbf1da6bdc85aa45ef66ed1c47bdb65a08..fd57b8477fab56990d4b9d8155501bd0b8f6f0b9 100644 (file)
@@ -43,6 +43,7 @@
  */
 #define atomic_set(v, i) (((v)->counter) = (i))
 
+#include <linux/irqflags.h>
 #include <asm/system.h>
 
 /**
@@ -57,7 +58,7 @@ static inline int atomic_add_return(int i, atomic_t *v)
        unsigned long flags;
        int temp;
 
-       raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */
+       raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */
        temp = v->counter;
        temp += i;
        v->counter = temp;
@@ -78,7 +79,7 @@ static inline int atomic_sub_return(int i, atomic_t *v)
        unsigned long flags;
        int temp;
 
-       raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */
+       raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */
        temp = v->counter;
        temp -= i;
        v->counter = temp;
index b2ba2fc8829a6a759d521e14bf1a3e1e80d64c78..2533fddd34a69d7b1f272895b980c750f39cfdd1 100644 (file)
@@ -2,6 +2,7 @@
 #define __ASM_GENERIC_CMPXCHG_LOCAL_H
 
 #include <linux/types.h>
+#include <linux/irqflags.h>
 
 extern unsigned long wrong_size_cmpxchg(volatile void *ptr);
 
index 62f59080e5cc215edb843f928763d9898055071f..04d0a977cd431fc5eb2c2f34cbd5390bfeb0db05 100644 (file)
@@ -3,13 +3,13 @@
 
 #include <linux/cache.h>
 #include <linux/threads.h>
-#include <linux/irq.h>
 
 typedef struct {
        unsigned int __softirq_pending;
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+#include <linux/irq.h>
 
 #ifndef ack_bad_irq
 static inline void ack_bad_irq(unsigned int irq)
index 9aebf618275af2e5bf519bb241661039f8e632d4..1f40d0024cf381d5c380f2a1c19b5c5ce3ae24e1 100644 (file)
@@ -5,68 +5,62 @@
  * 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
+#ifndef ARCH_IRQ_DISABLED
+#define ARCH_IRQ_DISABLED 0
+#define ARCH_IRQ_ENABLED 1
 #endif
 
 /* read interrupt enabled status */
-#ifndef __raw_local_save_flags
-unsigned long __raw_local_save_flags(void);
+#ifndef arch_local_save_flags
+unsigned long arch_local_save_flags(void);
 #endif
 
 /* set interrupt enabled status */
-#ifndef raw_local_irq_restore
-void raw_local_irq_restore(unsigned long flags);
+#ifndef arch_local_irq_restore
+void arch_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)
+#ifndef arch_local_irq_save
+static inline unsigned long arch_local_irq_save(void)
 {
        unsigned long flags;
-       flags = __raw_local_save_flags();
-       raw_local_irq_restore(RAW_IRQ_DISABLED);
+       flags = arch_local_save_flags();
+       arch_local_irq_restore(ARCH_IRQ_DISABLED);
        return flags;
 }
 #endif
 
 /* test flags */
-#ifndef raw_irqs_disabled_flags
-static inline int raw_irqs_disabled_flags(unsigned long flags)
+#ifndef arch_irqs_disabled_flags
+static inline int arch_irqs_disabled_flags(unsigned long flags)
 {
-       return flags == RAW_IRQ_DISABLED;
+       return flags == ARCH_IRQ_DISABLED;
 }
 #endif
 
 /* unconditionally enable interrupts */
-#ifndef raw_local_irq_enable
-static inline void raw_local_irq_enable(void)
+#ifndef arch_local_irq_enable
+static inline void arch_local_irq_enable(void)
 {
-       raw_local_irq_restore(RAW_IRQ_ENABLED);
+       arch_local_irq_restore(ARCH_IRQ_ENABLED);
 }
 #endif
 
 /* unconditionally disable interrupts */
-#ifndef raw_local_irq_disable
-static inline void raw_local_irq_disable(void)
+#ifndef arch_local_irq_disable
+static inline void arch_local_irq_disable(void)
 {
-       raw_local_irq_restore(RAW_IRQ_DISABLED);
+       arch_local_irq_restore(ARCH_IRQ_DISABLED);
 }
 #endif
 
 /* test hardware interrupt enable bit */
-#ifndef raw_irqs_disabled
-static inline int raw_irqs_disabled(void)
+#ifndef arch_irqs_disabled
+static inline int arch_irqs_disabled(void)
 {
-       return raw_irqs_disabled_flags(__raw_local_save_flags());
+       return arch_irqs_disabled_flags(arch_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 */
index e2bd73e8f9c0b4db75755d1e4f0aadaaa0e20c2a..f4d4120e5128a8fe76580286151017ddb68c497b 100644 (file)
@@ -129,6 +129,10 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres
 #define move_pte(pte, prot, old_addr, new_addr)        (pte)
 #endif
 
+#ifndef flush_tlb_fix_spurious_fault
+#define flush_tlb_fix_spurious_fault(vma, address) flush_tlb_page(vma, address)
+#endif
+
 #ifndef pgprot_noncached
 #define pgprot_noncached(prot) (prot)
 #endif
index 8a92a170fb7dfd87710bb26b3c7f384dd6801363..f4229fb315e1d7d81caddb7557cbcb6c65072fed 100644 (file)
                                                                        \
        BUG_TABLE                                                       \
                                                                        \
+       JUMP_TABLE                                                      \
+                                                                       \
        /* PCI quirks */                                                \
        .pci_fixup        : AT(ADDR(.pci_fixup) - LOAD_OFFSET) {        \
                VMLINUX_SYMBOL(__start_pci_fixups_early) = .;           \
 #define BUG_TABLE
 #endif
 
+#define JUMP_TABLE                                                     \
+       . = ALIGN(8);                                                   \
+       __jump_table : AT(ADDR(__jump_table) - LOAD_OFFSET) {           \
+               VMLINUX_SYMBOL(__start___jump_table) = .;               \
+               *(__jump_table)                                         \
+               VMLINUX_SYMBOL(__stop___jump_table) = .;                \
+       }
+
 #ifdef CONFIG_PM_TRACE
 #define TRACEDATA                                                      \
        . = ALIGN(4);                                                   \
                                - LOAD_OFFSET) {                        \
                VMLINUX_SYMBOL(__per_cpu_start) = .;                    \
                *(.data..percpu..first)                                 \
+               . = ALIGN(PAGE_SIZE);                                   \
                *(.data..percpu..page_aligned)                          \
+               *(.data..percpu..readmostly)                            \
                *(.data..percpu)                                        \
                *(.data..percpu..shared_aligned)                        \
                VMLINUX_SYMBOL(__per_cpu_end) = .;                      \
                VMLINUX_SYMBOL(__per_cpu_load) = .;                     \
                VMLINUX_SYMBOL(__per_cpu_start) = .;                    \
                *(.data..percpu..first)                                 \
+               . = ALIGN(PAGE_SIZE);                                   \
                *(.data..percpu..page_aligned)                          \
+               *(.data..percpu..readmostly)                            \
                *(.data..percpu)                                        \
                *(.data..percpu..shared_aligned)                        \
                VMLINUX_SYMBOL(__per_cpu_end) = .;                      \
index 7e3d2859be50230b9b2755288a53d8fb693145b0..1d0ef1ae80362d50f1b620b54c01313d6c46b936 100644 (file)
@@ -25,8 +25,6 @@ static inline u32 acpi_pm_read_early(void)
        return acpi_pm_read_verified() & ACPI_PM_MASK;
 }
 
-extern void pmtimer_wait(unsigned);
-
 #else
 
 static inline u32 acpi_pm_read_early(void)
index b0c1740124365979f9e6e50a0671bf217206bdda..c6454cca044787f65965369d92837f4649297a93 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/resource.h>
 
 #define AMBA_NR_IRQS   2
+#define AMBA_CID       0xb105f00d
 
 struct clk;
 
@@ -70,9 +71,15 @@ void amba_release_regions(struct amba_device *);
 #define amba_pclk_disable(d)   \
        do { if (!IS_ERR((d)->pclk)) clk_disable((d)->pclk); } while (0)
 
-#define amba_config(d) (((d)->periphid >> 24) & 0xff)
-#define amba_rev(d)    (((d)->periphid >> 20) & 0x0f)
-#define amba_manf(d)   (((d)->periphid >> 12) & 0xff)
-#define amba_part(d)   ((d)->periphid & 0xfff)
+/* Some drivers don't use the struct amba_device */
+#define AMBA_CONFIG_BITS(a) (((a) >> 24) & 0xff)
+#define AMBA_REV_BITS(a) (((a) >> 20) & 0x0f)
+#define AMBA_MANF_BITS(a) (((a) >> 12) & 0xff)
+#define AMBA_PART_BITS(a) ((a) & 0xfff)
+
+#define amba_config(d) AMBA_CONFIG_BITS((d)->periphid)
+#define amba_rev(d)    AMBA_REV_BITS((d)->periphid)
+#define amba_manf(d)   AMBA_MANF_BITS((d)->periphid)
+#define amba_part(d)   AMBA_PART_BITS((d)->periphid)
 
 #endif
index ca84ce70d5d5fca84b7de66533ba06cab54e5298..f4ee9acc97213b72f36f984ce31b57fd4ba1a784 100644 (file)
@@ -24,6 +24,7 @@
  * whether a card is present in the MMC slot or not
  * @gpio_wp: read this GPIO pin to see if the card is write protected
  * @gpio_cd: read this GPIO pin to detect card insertion
+ * @cd_invert: true if the gpio_cd pin value is active low
  * @capabilities: the capabilities of the block as implemented in
  * this platform, signify anything MMC_CAP_* from mmc/host.h
  */
@@ -35,6 +36,7 @@ struct mmci_platform_data {
        unsigned int (*status)(struct device *);
        int     gpio_wp;
        int     gpio_cd;
+       bool    cd_invert;
        unsigned long capabilities;
 };
 
index abf26cc47a2bc19ff0238a71128d2505c9acc156..4ce98f54186b4fe0a215fa47ddd49fe1ef83152a 100644 (file)
@@ -228,6 +228,7 @@ enum ssp_chip_select {
 };
 
 
+struct dma_chan;
 /**
  * struct pl022_ssp_master - device.platform_data for SPI controller devices.
  * @num_chipselect: chipselects are used to distinguish individual
@@ -235,11 +236,16 @@ enum ssp_chip_select {
  *     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.
+ * @dma_rx_param: parameter to locate an RX DMA channel.
+ * @dma_tx_param: parameter to locate a TX DMA channel.
  */
 struct pl022_ssp_controller {
        u16 bus_id;
        u8 num_chipselect;
        u8 enable_dma:1;
+       bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
+       void *dma_rx_param;
+       void *dma_tx_param;
 };
 
 /**
@@ -270,20 +276,13 @@ struct pl022_ssp_controller {
  * @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;
index e1b634b635f2a3df5e8a0787c76ea371ae9d8f1a..6021588ba0a87ea14ab1cb4620bef7aeea3d3ab9 100644 (file)
@@ -32,7 +32,9 @@
 #define UART01x_RSR            0x04    /* Receive status register (Read). */
 #define UART01x_ECR            0x04    /* Error clear register (Write). */
 #define UART010_LCRH           0x08    /* Line control register, high byte. */
+#define ST_UART011_DMAWM       0x08    /* DMA watermark configure register. */
 #define UART010_LCRM           0x0C    /* Line control register, middle byte. */
+#define ST_UART011_TIMEOUT     0x0C    /* Timeout period register. */
 #define UART010_LCRL           0x10    /* Line control register, low byte. */
 #define UART010_CR             0x14    /* Control register. */
 #define UART01x_FR             0x18    /* Flag register (Read only). */
 #define UART011_MIS            0x40    /* Masked interrupt status. */
 #define UART011_ICR            0x44    /* Interrupt clear register. */
 #define UART011_DMACR          0x48    /* DMA control register. */
+#define ST_UART011_XFCR                0x50    /* XON/XOFF control register. */
+#define ST_UART011_XON1                0x54    /* XON1 register. */
+#define ST_UART011_XON2                0x58    /* XON2 register. */
+#define ST_UART011_XOFF1       0x5C    /* XON1 register. */
+#define ST_UART011_XOFF2       0x60    /* XON2 register. */
+#define ST_UART011_ITCR                0x80    /* Integration test control register. */
+#define ST_UART011_ITIP                0x84    /* Integration test input register. */
+#define ST_UART011_ABCR                0x100   /* Autobaud control register. */
+#define ST_UART011_ABIMSC      0x15C   /* Autobaud interrupt mask/clear register. */
 
 #define UART011_DR_OE          (1 << 11)
 #define UART011_DR_BE          (1 << 10)
index fe6e681a9d742788be67c16003662b9a7a218e89..0c4929fa34d31da64a79bd22dbfdccd8aaba33dc 100644 (file)
@@ -89,6 +89,7 @@ enum {
        ATA_ID_SPG              = 98,
        ATA_ID_LBA_CAPACITY_2   = 100,
        ATA_ID_SECTOR_SIZE      = 106,
+       ATA_ID_LOGICAL_SECTOR_SIZE      = 117,  /* and 118 */
        ATA_ID_LAST_LUN         = 126,
        ATA_ID_DLF              = 128,
        ATA_ID_CSFO             = 129,
@@ -640,16 +641,49 @@ static inline int ata_id_flush_ext_enabled(const u16 *id)
        return (id[ATA_ID_CFS_ENABLE_2] & 0x2400) == 0x2400;
 }
 
-static inline int ata_id_has_large_logical_sectors(const u16 *id)
+static inline u32 ata_id_logical_sector_size(const u16 *id)
 {
-       if ((id[ATA_ID_SECTOR_SIZE] & 0xc000) != 0x4000)
-               return 0;
-       return id[ATA_ID_SECTOR_SIZE] & (1 << 13);
+       /* T13/1699-D Revision 6a, Sep 6, 2008. Page 128.
+        * IDENTIFY DEVICE data, word 117-118.
+        * 0xd000 ignores bit 13 (logical:physical > 1)
+        */
+       if ((id[ATA_ID_SECTOR_SIZE] & 0xd000) == 0x5000)
+               return (((id[ATA_ID_LOGICAL_SECTOR_SIZE+1] << 16)
+                        + id[ATA_ID_LOGICAL_SECTOR_SIZE]) * sizeof(u16)) ;
+       return ATA_SECT_SIZE;
+}
+
+static inline u8 ata_id_log2_per_physical_sector(const u16 *id)
+{
+       /* T13/1699-D Revision 6a, Sep 6, 2008. Page 128.
+        * IDENTIFY DEVICE data, word 106.
+        * 0xe000 ignores bit 12 (logical sector > 512 bytes)
+        */
+       if ((id[ATA_ID_SECTOR_SIZE] & 0xe000) == 0x6000)
+               return (id[ATA_ID_SECTOR_SIZE] & 0xf);
+       return 0;
 }
 
-static inline u16 ata_id_logical_per_physical_sectors(const u16 *id)
+/* Offset of logical sectors relative to physical sectors.
+ *
+ * If device has more than one logical sector per physical sector
+ * (aka 512 byte emulation), vendors might offset the "sector 0" address
+ * so sector 63 is "naturally aligned" - e.g. FAT partition table.
+ * This avoids Read/Mod/Write penalties when using FAT partition table
+ * and updating "well aligned" (FS perspective) physical sectors on every
+ * transaction.
+ */
+static inline u16 ata_id_logical_sector_offset(const u16 *id,
+        u8 log2_per_phys)
 {
-       return 1 << (id[ATA_ID_SECTOR_SIZE] & 0xf);
+       u16 word_209 = id[209];
+
+       if ((log2_per_phys > 1) && (word_209 & 0xc000) == 0x4000) {
+               u16 first = word_209 & 0x3fff;
+               if (first > 0)
+                       return (1 << log2_per_phys) - first;
+       }
+       return 0;
 }
 
 static inline int ata_id_has_lba48(const u16 *id)
similarity index 97%
rename from fs/ceph/auth.h
rename to include/linux/ceph/auth.h
index d38a2fb4a13762fc6e37578f840b166ee85efd16..7fff521d7eb5e00741fcf2fc97f7ce8c40fdbfc8 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef _FS_CEPH_AUTH_H
 #define _FS_CEPH_AUTH_H
 
-#include "types.h"
-#include "buffer.h"
+#include <linux/ceph/types.h>
+#include <linux/ceph/buffer.h>
 
 /*
  * Abstract interface for communicating with the authenticate module.
similarity index 100%
rename from fs/ceph/buffer.h
rename to include/linux/ceph/buffer.h
similarity index 86%
rename from fs/ceph/ceph_debug.h
rename to include/linux/ceph/ceph_debug.h
index 1818c2305610e28f6dbb7d3e126e7137d28c1365..aa2e19182d990eedda70de69bf638db5856811d1 100644 (file)
@@ -3,7 +3,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#ifdef CONFIG_CEPH_FS_PRETTYDEBUG
+#ifdef CONFIG_CEPH_LIB_PRETTYDEBUG
 
 /*
  * wrap pr_debug to include a filename:lineno prefix on each line.
@@ -14,7 +14,8 @@
 # if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
 extern const char *ceph_file_part(const char *s, int len);
 #  define dout(fmt, ...)                                               \
-       pr_debug(" %12.12s:%-4d : " fmt,                                \
+       pr_debug("%.*s %12.12s:%-4d : " fmt,                            \
+                8 - (int)sizeof(KBUILD_MODNAME), "    ",               \
                 ceph_file_part(__FILE__, sizeof(__FILE__)),            \
                 __LINE__, ##__VA_ARGS__)
 # else
similarity index 99%
rename from fs/ceph/ceph_fs.h
rename to include/linux/ceph/ceph_fs.h
index d5619ac86711a6b41c56a00da7660099352d5327..c3c74aef289d0d34afb2758392ef144d82b59cc6 100644 (file)
@@ -299,6 +299,7 @@ enum {
        CEPH_MDS_OP_SETATTR    = 0x01108,
        CEPH_MDS_OP_SETFILELOCK= 0x01109,
        CEPH_MDS_OP_GETFILELOCK= 0x00110,
+       CEPH_MDS_OP_SETDIRLAYOUT=0x0110a,
 
        CEPH_MDS_OP_MKNOD      = 0x01201,
        CEPH_MDS_OP_LINK       = 0x01202,
diff --git a/include/linux/ceph/debugfs.h b/include/linux/ceph/debugfs.h
new file mode 100644 (file)
index 0000000..2a79702
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _FS_CEPH_DEBUGFS_H
+#define _FS_CEPH_DEBUGFS_H
+
+#include "ceph_debug.h"
+#include "types.h"
+
+#define CEPH_DEFINE_SHOW_FUNC(name)                                    \
+static int name##_open(struct inode *inode, struct file *file)         \
+{                                                                      \
+       struct seq_file *sf;                                            \
+       int ret;                                                        \
+                                                                       \
+       ret = single_open(file, name, NULL);                            \
+       sf = file->private_data;                                        \
+       sf->private = inode->i_private;                                 \
+       return ret;                                                     \
+}                                                                      \
+                                                                       \
+static const struct file_operations name##_fops = {                    \
+       .open           = name##_open,                                  \
+       .read           = seq_read,                                     \
+       .llseek         = seq_lseek,                                    \
+       .release        = single_release,                               \
+};
+
+/* debugfs.c */
+extern int ceph_debugfs_init(void);
+extern void ceph_debugfs_cleanup(void);
+extern int ceph_debugfs_client_init(struct ceph_client *client);
+extern void ceph_debugfs_client_cleanup(struct ceph_client *client);
+
+#endif
+
similarity index 96%
rename from fs/ceph/decode.h
rename to include/linux/ceph/decode.h
index 3d25415afe6368debff12c405463e52c7683edc6..c5b6939fb32af578501a280f73f2aa7b4276ac37 100644 (file)
@@ -191,6 +191,11 @@ static inline void ceph_encode_string(void **p, void *end,
                ceph_encode_need(p, end, n, bad);               \
                ceph_encode_copy(p, pv, n);                     \
        } while (0)
+#define ceph_encode_string_safe(p, end, s, n, bad)             \
+       do {                                                    \
+               ceph_encode_need(p, end, n, bad);               \
+               ceph_encode_string(p, end, s, n);               \
+       } while (0)
 
 
 #endif
diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
new file mode 100644 (file)
index 0000000..f22b2e9
--- /dev/null
@@ -0,0 +1,249 @@
+#ifndef _FS_CEPH_LIBCEPH_H
+#define _FS_CEPH_LIBCEPH_H
+
+#include "ceph_debug.h"
+
+#include <asm/unaligned.h>
+#include <linux/backing-dev.h>
+#include <linux/completion.h>
+#include <linux/exportfs.h>
+#include <linux/fs.h>
+#include <linux/mempool.h>
+#include <linux/pagemap.h>
+#include <linux/wait.h>
+#include <linux/writeback.h>
+#include <linux/slab.h>
+
+#include "types.h"
+#include "messenger.h"
+#include "msgpool.h"
+#include "mon_client.h"
+#include "osd_client.h"
+#include "ceph_fs.h"
+
+/*
+ * Supported features
+ */
+#define CEPH_FEATURE_SUPPORTED_DEFAULT CEPH_FEATURE_NOSRCADDR
+#define CEPH_FEATURE_REQUIRED_DEFAULT  CEPH_FEATURE_NOSRCADDR
+
+/*
+ * mount options
+ */
+#define CEPH_OPT_FSID             (1<<0)
+#define CEPH_OPT_NOSHARE          (1<<1) /* don't share client with other sbs */
+#define CEPH_OPT_MYIP             (1<<2) /* specified my ip */
+#define CEPH_OPT_NOCRC            (1<<3) /* no data crc on writes */
+
+#define CEPH_OPT_DEFAULT   (0);
+
+#define ceph_set_opt(client, opt) \
+       (client)->options->flags |= CEPH_OPT_##opt;
+#define ceph_test_opt(client, opt) \
+       (!!((client)->options->flags & CEPH_OPT_##opt))
+
+struct ceph_options {
+       int flags;
+       struct ceph_fsid fsid;
+       struct ceph_entity_addr my_addr;
+       int mount_timeout;
+       int osd_idle_ttl;
+       int osd_timeout;
+       int osd_keepalive_timeout;
+
+       /*
+        * any type that can't be simply compared or doesn't need need
+        * to be compared should go beyond this point,
+        * ceph_compare_options() should be updated accordingly
+        */
+
+       struct ceph_entity_addr *mon_addr; /* should be the first
+                                             pointer type of args */
+       int num_mon;
+       char *name;
+       char *secret;
+};
+
+/*
+ * defaults
+ */
+#define CEPH_MOUNT_TIMEOUT_DEFAULT  60
+#define CEPH_OSD_TIMEOUT_DEFAULT    60  /* seconds */
+#define CEPH_OSD_KEEPALIVE_DEFAULT  5
+#define CEPH_OSD_IDLE_TTL_DEFAULT    60
+#define CEPH_MOUNT_RSIZE_DEFAULT    (512*1024) /* readahead */
+
+#define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024)
+#define CEPH_MSG_MAX_DATA_LEN  (16*1024*1024)
+
+#define CEPH_AUTH_NAME_DEFAULT   "guest"
+
+/*
+ * Delay telling the MDS we no longer want caps, in case we reopen
+ * the file.  Delay a minimum amount of time, even if we send a cap
+ * message for some other reason.  Otherwise, take the oppotunity to
+ * update the mds to avoid sending another message later.
+ */
+#define CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT      5  /* cap release delay */
+#define CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT     60  /* cap release delay */
+
+#define CEPH_CAP_RELEASE_SAFETY_DEFAULT        (CEPH_CAPS_PER_RELEASE * 4)
+
+/* mount state */
+enum {
+       CEPH_MOUNT_MOUNTING,
+       CEPH_MOUNT_MOUNTED,
+       CEPH_MOUNT_UNMOUNTING,
+       CEPH_MOUNT_UNMOUNTED,
+       CEPH_MOUNT_SHUTDOWN,
+};
+
+/*
+ * subtract jiffies
+ */
+static inline unsigned long time_sub(unsigned long a, unsigned long b)
+{
+       BUG_ON(time_after(b, a));
+       return (long)a - (long)b;
+}
+
+struct ceph_mds_client;
+
+/*
+ * per client state
+ *
+ * possibly shared by multiple mount points, if they are
+ * mounting the same ceph filesystem/cluster.
+ */
+struct ceph_client {
+       struct ceph_fsid fsid;
+       bool have_fsid;
+
+       void *private;
+
+       struct ceph_options *options;
+
+       struct mutex mount_mutex;      /* serialize mount attempts */
+       wait_queue_head_t auth_wq;
+       int auth_err;
+
+       int (*extra_mon_dispatch)(struct ceph_client *, struct ceph_msg *);
+
+       u32 supported_features;
+       u32 required_features;
+
+       struct ceph_messenger *msgr;   /* messenger instance */
+       struct ceph_mon_client monc;
+       struct ceph_osd_client osdc;
+
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debugfs_dir;
+       struct dentry *debugfs_monmap;
+       struct dentry *debugfs_osdmap;
+#endif
+};
+
+
+
+/*
+ * snapshots
+ */
+
+/*
+ * A "snap context" is the set of existing snapshots when we
+ * write data.  It is used by the OSD to guide its COW behavior.
+ *
+ * The ceph_snap_context is refcounted, and attached to each dirty
+ * page, indicating which context the dirty data belonged when it was
+ * dirtied.
+ */
+struct ceph_snap_context {
+       atomic_t nref;
+       u64 seq;
+       int num_snaps;
+       u64 snaps[];
+};
+
+static inline struct ceph_snap_context *
+ceph_get_snap_context(struct ceph_snap_context *sc)
+{
+       /*
+       printk("get_snap_context %p %d -> %d\n", sc, atomic_read(&sc->nref),
+              atomic_read(&sc->nref)+1);
+       */
+       if (sc)
+               atomic_inc(&sc->nref);
+       return sc;
+}
+
+static inline void ceph_put_snap_context(struct ceph_snap_context *sc)
+{
+       if (!sc)
+               return;
+       /*
+       printk("put_snap_context %p %d -> %d\n", sc, atomic_read(&sc->nref),
+              atomic_read(&sc->nref)-1);
+       */
+       if (atomic_dec_and_test(&sc->nref)) {
+               /*printk(" deleting snap_context %p\n", sc);*/
+               kfree(sc);
+       }
+}
+
+/*
+ * calculate the number of pages a given length and offset map onto,
+ * if we align the data.
+ */
+static inline int calc_pages_for(u64 off, u64 len)
+{
+       return ((off+len+PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT) -
+               (off >> PAGE_CACHE_SHIFT);
+}
+
+/* ceph_common.c */
+extern const char *ceph_msg_type_name(int type);
+extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid);
+extern struct kmem_cache *ceph_inode_cachep;
+extern struct kmem_cache *ceph_cap_cachep;
+extern struct kmem_cache *ceph_dentry_cachep;
+extern struct kmem_cache *ceph_file_cachep;
+
+extern int ceph_parse_options(struct ceph_options **popt, char *options,
+                             const char *dev_name, const char *dev_name_end,
+                             int (*parse_extra_token)(char *c, void *private),
+                             void *private);
+extern void ceph_destroy_options(struct ceph_options *opt);
+extern int ceph_compare_options(struct ceph_options *new_opt,
+                               struct ceph_client *client);
+extern struct ceph_client *ceph_create_client(struct ceph_options *opt,
+                                             void *private);
+extern u64 ceph_client_id(struct ceph_client *client);
+extern void ceph_destroy_client(struct ceph_client *client);
+extern int __ceph_open_session(struct ceph_client *client,
+                              unsigned long started);
+extern int ceph_open_session(struct ceph_client *client);
+
+/* pagevec.c */
+extern void ceph_release_page_vector(struct page **pages, int num_pages);
+
+extern struct page **ceph_get_direct_page_vector(const char __user *data,
+                                           int num_pages,
+                                           loff_t off, size_t len);
+extern void ceph_put_page_vector(struct page **pages, int num_pages);
+extern void ceph_release_page_vector(struct page **pages, int num_pages);
+extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
+extern int ceph_copy_user_to_page_vector(struct page **pages,
+                                        const char __user *data,
+                                        loff_t off, size_t len);
+extern int ceph_copy_to_page_vector(struct page **pages,
+                                   const char *data,
+                                   loff_t off, size_t len);
+extern int ceph_copy_from_page_vector(struct page **pages,
+                                   char *data,
+                                   loff_t off, size_t len);
+extern int ceph_copy_page_vector_to_user(struct page **pages, char __user *data,
+                                   loff_t off, size_t len);
+extern void ceph_zero_page_vector_range(int off, int len, struct page **pages);
+
+
+#endif /* _FS_CEPH_SUPER_H */
similarity index 100%
rename from fs/ceph/mdsmap.h
rename to include/linux/ceph/mdsmap.h
similarity index 95%
rename from fs/ceph/messenger.h
rename to include/linux/ceph/messenger.h
index 76fbc957bc137dab063cdd69abcc1b432800aa51..5956d62c3057139ac6634df8e13556659d07725e 100644 (file)
@@ -65,6 +65,9 @@ struct ceph_messenger {
         */
        u32 global_seq;
        spinlock_t global_seq_lock;
+
+       u32 supported_features;
+       u32 required_features;
 };
 
 /*
@@ -82,6 +85,10 @@ struct ceph_msg {
        struct ceph_pagelist *pagelist; /* instead of pages */
        struct list_head list_head;
        struct kref kref;
+       struct bio  *bio;               /* instead of pages/pagelist */
+       struct bio  *bio_iter;          /* bio iterator */
+       int bio_seg;                    /* current bio segment */
+       struct ceph_pagelist *trail;    /* the trailing part of the data */
        bool front_is_vmalloc;
        bool more_to_follow;
        bool needs_out_seq;
@@ -205,7 +212,7 @@ struct ceph_connection {
 };
 
 
-extern const char *pr_addr(const struct sockaddr_storage *ss);
+extern const char *ceph_pr_addr(const struct sockaddr_storage *ss);
 extern int ceph_parse_ips(const char *c, const char *end,
                          struct ceph_entity_addr *addr,
                          int max_count, int *count);
@@ -216,7 +223,8 @@ extern void ceph_msgr_exit(void);
 extern void ceph_msgr_flush(void);
 
 extern struct ceph_messenger *ceph_messenger_create(
-       struct ceph_entity_addr *myaddr);
+       struct ceph_entity_addr *myaddr,
+       u32 features, u32 required);
 extern void ceph_messenger_destroy(struct ceph_messenger *);
 
 extern void ceph_con_init(struct ceph_messenger *msgr,
similarity index 99%
rename from fs/ceph/mon_client.h
rename to include/linux/ceph/mon_client.h
index 8e396f2c09637f29d0a82311244d036441a51c1c..545f85917780ab3cd65a314553f7011b655dbb50 100644 (file)
@@ -79,6 +79,7 @@ struct ceph_mon_client {
        u64 last_tid;
 
        /* mds/osd map */
+       int want_mdsmap;
        int want_next_osdmap; /* 1 = want, 2 = want+asked */
        u32 have_osdmap, have_mdsmap;
 
similarity index 100%
rename from fs/ceph/msgr.h
rename to include/linux/ceph/msgr.h
similarity index 76%
rename from fs/ceph/osd_client.h
rename to include/linux/ceph/osd_client.h
index ce776989ef6a76d73d1475ce2335ce558b653e2d..6c91fb032c39cd907a3ac509db75a3a860e564c1 100644 (file)
@@ -15,6 +15,7 @@ struct ceph_snap_context;
 struct ceph_osd_request;
 struct ceph_osd_client;
 struct ceph_authorizer;
+struct ceph_pagelist;
 
 /*
  * completion callback for async writepages
@@ -68,6 +69,7 @@ struct ceph_osd_request {
        struct list_head  r_unsafe_item;
 
        struct inode *r_inode;                /* for use by callbacks */
+       void *r_priv;                         /* ditto */
 
        char              r_oid[40];          /* object name */
        int               r_oid_len;
@@ -80,6 +82,11 @@ struct ceph_osd_request {
        struct page     **r_pages;            /* pages for data payload */
        int               r_pages_from_pool;
        int               r_own_pages;        /* if true, i own page list */
+#ifdef CONFIG_BLOCK
+       struct bio       *r_bio;              /* instead of pages */
+#endif
+
+       struct ceph_pagelist *r_trail;        /* trailing part of the data */
 };
 
 struct ceph_osd_client {
@@ -110,6 +117,42 @@ struct ceph_osd_client {
        struct ceph_msgpool     msgpool_op_reply;
 };
 
+struct ceph_osd_req_op {
+       u16 op;           /* CEPH_OSD_OP_* */
+       u32 flags;        /* CEPH_OSD_FLAG_* */
+       union {
+               struct {
+                       u64 offset, length;
+                       u64 truncate_size;
+                       u32 truncate_seq;
+               } extent;
+               struct {
+                       const char *name;
+                       u32 name_len;
+                       const char  *val;
+                       u32 value_len;
+                       __u8 cmp_op;       /* CEPH_OSD_CMPXATTR_OP_* */
+                       __u8 cmp_mode;     /* CEPH_OSD_CMPXATTR_MODE_* */
+               } xattr;
+               struct {
+                       const char *class_name;
+                       __u8 class_len;
+                       const char *method_name;
+                       __u8 method_len;
+                       __u8 argc;
+                       const char *indata;
+                       u32 indata_len;
+               } cls;
+               struct {
+                       u64 cookie, count;
+               } pgls;
+               struct {
+                       u64 snapid;
+               } snap;
+       };
+       u32 payload_len;
+};
+
 extern int ceph_osdc_init(struct ceph_osd_client *osdc,
                          struct ceph_client *client);
 extern void ceph_osdc_stop(struct ceph_osd_client *osdc);
@@ -119,6 +162,30 @@ extern void ceph_osdc_handle_reply(struct ceph_osd_client *osdc,
 extern void ceph_osdc_handle_map(struct ceph_osd_client *osdc,
                                 struct ceph_msg *msg);
 
+extern void ceph_calc_raw_layout(struct ceph_osd_client *osdc,
+                       struct ceph_file_layout *layout,
+                       u64 snapid,
+                       u64 off, u64 *plen, u64 *bno,
+                       struct ceph_osd_request *req,
+                       struct ceph_osd_req_op *op);
+
+extern struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
+                                              int flags,
+                                              struct ceph_snap_context *snapc,
+                                              struct ceph_osd_req_op *ops,
+                                              bool use_mempool,
+                                              gfp_t gfp_flags,
+                                              struct page **pages,
+                                              struct bio *bio);
+
+extern void ceph_osdc_build_request(struct ceph_osd_request *req,
+                                   u64 off, u64 *plen,
+                                   struct ceph_osd_req_op *src_ops,
+                                   struct ceph_snap_context *snapc,
+                                   struct timespec *mtime,
+                                   const char *oid,
+                                   int oid_len);
+
 extern struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *,
                                      struct ceph_file_layout *layout,
                                      struct ceph_vino vino,
similarity index 97%
rename from fs/ceph/osdmap.h
rename to include/linux/ceph/osdmap.h
index 970b547e510dbd0edb8ba8c2ec95c45932be6106..ba4c205cbb016a141495e2e872ee6a3cfd57253a 100644 (file)
@@ -4,7 +4,7 @@
 #include <linux/rbtree.h>
 #include "types.h"
 #include "ceph_fs.h"
-#include "crush/crush.h"
+#include <linux/crush/crush.h>
 
 /*
  * The osd map describes the current membership of the osd cluster and
@@ -125,4 +125,6 @@ extern int ceph_calc_pg_acting(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
 extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap,
                                struct ceph_pg pgid);
 
+extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name);
+
 #endif
similarity index 62%
rename from fs/ceph/pagelist.h
rename to include/linux/ceph/pagelist.h
index e8a4187e1087aa7fbc86a2620764f87f234dfe0a..9660d6b0a35d780dbe0806edf6193d1f7d5ef8f5 100644 (file)
@@ -8,6 +8,14 @@ struct ceph_pagelist {
        void *mapped_tail;
        size_t length;
        size_t room;
+       struct list_head free_list;
+       size_t num_pages_free;
+};
+
+struct ceph_pagelist_cursor {
+       struct ceph_pagelist *pl;   /* pagelist, for error checking */
+       struct list_head *page_lru; /* page in list */
+       size_t room;                /* room remaining to reset to */
 };
 
 static inline void ceph_pagelist_init(struct ceph_pagelist *pl)
@@ -16,10 +24,23 @@ static inline void ceph_pagelist_init(struct ceph_pagelist *pl)
        pl->mapped_tail = NULL;
        pl->length = 0;
        pl->room = 0;
+       INIT_LIST_HEAD(&pl->free_list);
+       pl->num_pages_free = 0;
 }
+
 extern int ceph_pagelist_release(struct ceph_pagelist *pl);
 
-extern int ceph_pagelist_append(struct ceph_pagelist *pl, void *d, size_t l);
+extern int ceph_pagelist_append(struct ceph_pagelist *pl, const void *d, size_t l);
+
+extern int ceph_pagelist_reserve(struct ceph_pagelist *pl, size_t space);
+
+extern int ceph_pagelist_free_reserve(struct ceph_pagelist *pl);
+
+extern void ceph_pagelist_set_cursor(struct ceph_pagelist *pl,
+                                    struct ceph_pagelist_cursor *c);
+
+extern int ceph_pagelist_truncate(struct ceph_pagelist *pl,
+                                 struct ceph_pagelist_cursor *c);
 
 static inline int ceph_pagelist_encode_64(struct ceph_pagelist *pl, u64 v)
 {
similarity index 100%
rename from fs/ceph/rados.h
rename to include/linux/ceph/rados.h
similarity index 100%
rename from fs/ceph/types.h
rename to include/linux/ceph/types.h
index 0c991023ee475fad85136a04b00cb8d2699a382b..709dfb901d1124c75656fb0f7591826683bd2c5d 100644 (file)
@@ -75,7 +75,7 @@ struct cgroup_subsys_state {
 
        unsigned long flags;
        /* ID for this css, if possible */
-       struct css_id *id;
+       struct css_id __rcu *id;
 };
 
 /* bits in struct cgroup_subsys_state flags field */
@@ -205,7 +205,7 @@ struct cgroup {
        struct list_head children;      /* my children */
 
        struct cgroup *parent;          /* my parent */
-       struct dentry *dentry;          /* cgroup fs entry, RCU protected */
+       struct dentry __rcu *dentry;    /* cgroup fs entry, RCU protected */
 
        /* Private pointers for each registered subsystem */
        struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
index c1a62c56a660226b1592bc6bc269087adac58649..320d6c94ff848d5db94fb1fd76576501a88e9a3a 100644 (file)
 # define __release(x)  __context__(x,-1)
 # define __cond_lock(x,c)      ((c) ? ({ __acquire(x); 1; }) : 0)
 # define __percpu      __attribute__((noderef, address_space(3)))
+#ifdef CONFIG_SPARSE_RCU_POINTER
+# define __rcu         __attribute__((noderef, address_space(4)))
+#else
 # define __rcu
+#endif
 extern void __chk_user_ptr(const volatile void __user *);
 extern void __chk_io_ptr(const volatile void __iomem *);
 #else
index 4d2c39573f3694cdeef07d83c6f141b4804a5f36..4aaeab3764469961f1106d988e57e58a91e1a16e 100644 (file)
@@ -84,7 +84,7 @@ struct thread_group_cred {
        atomic_t        usage;
        pid_t           tgid;                   /* thread group process ID */
        spinlock_t      lock;
-       struct key      *session_keyring;       /* keyring inherited over fork */
+       struct key __rcu *session_keyring;      /* keyring inherited over fork */
        struct key      *process_keyring;       /* keyring private to this process */
        struct rcu_head rcu;                    /* RCU deletion hook */
 };
index 29b3ce3f2a1d0cd948523d8890c0bb8420834e09..2833452ea01c8ecec5207a7a8631da3f2b439fa3 100644 (file)
@@ -49,7 +49,6 @@ struct task_struct;
 
 #ifdef CONFIG_LOCKDEP
 extern void debug_show_all_locks(void);
-extern void __debug_show_held_locks(struct task_struct *task);
 extern void debug_show_held_locks(struct task_struct *task);
 extern void debug_check_no_locks_freed(const void *from, unsigned long len);
 extern void debug_check_no_locks_held(struct task_struct *task);
@@ -58,10 +57,6 @@ static inline void debug_show_all_locks(void)
 {
 }
 
-static inline void __debug_show_held_locks(struct task_struct *task)
-{
-}
-
 static inline void debug_show_held_locks(struct task_struct *task)
 {
 }
index d7cecc90ed34069f99c92692b17ed7d91aac2a20..a7d9dc21391d276e94c7a008107d31a0c56d8dc6 100644 (file)
@@ -57,15 +57,15 @@ extern int dmar_table_init(void);
 extern int dmar_dev_scope_init(void);
 
 /* Intel IOMMU detection */
-extern void detect_intel_iommu(void);
+extern int detect_intel_iommu(void);
 extern int enable_drhd_fault_handling(void);
 
 extern int parse_ioapics_under_ir(void);
 extern int alloc_iommu(struct dmar_drhd_unit *);
 #else
-static inline void detect_intel_iommu(void)
+static inline int detect_intel_iommu(void)
 {
-       return;
+       return -ENODEV;
 }
 
 static inline int dmar_table_init(void)
@@ -106,6 +106,7 @@ struct irte {
                __u64 high;
        };
 };
+
 #ifdef CONFIG_INTR_REMAP
 extern int intr_remapping_enabled;
 extern int intr_remapping_supported(void);
@@ -119,11 +120,8 @@ extern int alloc_irte(struct intel_iommu *iommu, int irq, u16 count);
 extern int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index,
                        u16 sub_handle);
 extern int map_irq_to_irte_handle(int irq, u16 *sub_handle);
-extern int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index);
-extern int flush_irte(int irq);
 extern int free_irte(int irq);
 
-extern int irq_remapped(int irq);
 extern struct intel_iommu *map_dev_to_ir(struct pci_dev *dev);
 extern struct intel_iommu *map_ioapic_to_ir(int apic);
 extern struct intel_iommu *map_hpet_to_ir(u8 id);
@@ -177,7 +175,6 @@ static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev)
        return 0;
 }
 
-#define irq_remapped(irq)              (0)
 #define enable_intr_remapping(mode)    (-1)
 #define disable_intr_remapping()       (0)
 #define reenable_intr_remapping(mode)  (0)
@@ -187,8 +184,9 @@ static inline int set_msi_sid(struct irte *irte, struct pci_dev *dev)
 /* Can't use the common MSI interrupt functions
  * since DMAR is not a pci device
  */
-extern void dmar_msi_unmask(unsigned int irq);
-extern void dmar_msi_mask(unsigned int irq);
+struct irq_data;
+extern void dmar_msi_unmask(struct irq_data *data);
+extern void dmar_msi_mask(struct irq_data *data);
 extern void dmar_msi_read(int irq, struct msi_msg *msg);
 extern void dmar_msi_write(int irq, struct msi_msg *msg);
 extern int dmar_set_interrupt(struct intel_iommu *iommu);
index 52c0da4bdd18fe5969fbf9c583652c0f7f00ba07..bef3cda44c4c4bb54570600a99fb0003db7038e7 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _DYNAMIC_DEBUG_H
 #define _DYNAMIC_DEBUG_H
 
+#include <linux/jump_label.h>
+
 /* dynamic_printk_enabled, and dynamic_printk_enabled2 are bitmasks in which
  * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
  * use independent hash functions, to reduce the chance of false positives.
@@ -22,8 +24,6 @@ struct _ddebug {
        const char *function;
        const char *filename;
        const char *format;
-       char primary_hash;
-       char secondary_hash;
        unsigned int lineno:24;
        /*
         * The flags field controls the behaviour at the callsite.
@@ -33,6 +33,7 @@ struct _ddebug {
 #define _DPRINTK_FLAGS_PRINT   (1<<0)  /* printk() a message using the format */
 #define _DPRINTK_FLAGS_DEFAULT 0
        unsigned int flags:8;
+       char enabled;
 } __attribute__((aligned(8)));
 
 
@@ -42,33 +43,35 @@ int ddebug_add_module(struct _ddebug *tab, unsigned int n,
 #if defined(CONFIG_DYNAMIC_DEBUG)
 extern int ddebug_remove_module(const char *mod_name);
 
-#define __dynamic_dbg_enabled(dd)  ({       \
-       int __ret = 0;                                                       \
-       if (unlikely((dynamic_debug_enabled & (1LL << DEBUG_HASH)) &&        \
-                       (dynamic_debug_enabled2 & (1LL << DEBUG_HASH2))))   \
-                               if (unlikely(dd.flags))                      \
-                                       __ret = 1;                           \
-       __ret; })
-
 #define dynamic_pr_debug(fmt, ...) do {                                        \
+       __label__ do_printk;                                            \
+       __label__ out;                                                  \
        static struct _ddebug descriptor                                \
        __used                                                          \
        __attribute__((section("__verbose"), aligned(8))) =             \
-       { KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH,  \
-               DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT };        \
-       if (__dynamic_dbg_enabled(descriptor))                          \
-               printk(KERN_DEBUG pr_fmt(fmt),  ##__VA_ARGS__);         \
+       { KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__,            \
+               _DPRINTK_FLAGS_DEFAULT };                               \
+       JUMP_LABEL(&descriptor.enabled, do_printk);                     \
+       goto out;                                                       \
+do_printk:                                                             \
+       printk(KERN_DEBUG pr_fmt(fmt),  ##__VA_ARGS__);                 \
+out:   ;                                                               \
        } while (0)
 
 
 #define dynamic_dev_dbg(dev, fmt, ...) do {                            \
+       __label__ do_printk;                                            \
+       __label__ out;                                                  \
        static struct _ddebug descriptor                                \
        __used                                                          \
        __attribute__((section("__verbose"), aligned(8))) =             \
-       { KBUILD_MODNAME, __func__, __FILE__, fmt, DEBUG_HASH,  \
-               DEBUG_HASH2, __LINE__, _DPRINTK_FLAGS_DEFAULT };        \
-       if (__dynamic_dbg_enabled(descriptor))                          \
-               dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__);        \
+       { KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__,            \
+               _DPRINTK_FLAGS_DEFAULT };                               \
+       JUMP_LABEL(&descriptor.enabled, do_printk);                     \
+       goto out;                                                       \
+do_printk:                                                             \
+       dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__);                \
+out:   ;                                                               \
        } while (0)
 
 #else
diff --git a/include/linux/early_res.h b/include/linux/early_res.h
deleted file mode 100644 (file)
index 29c09f5..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _LINUX_EARLY_RES_H
-#define _LINUX_EARLY_RES_H
-#ifdef __KERNEL__
-
-extern void reserve_early(u64 start, u64 end, char *name);
-extern void reserve_early_overlap_ok(u64 start, u64 end, char *name);
-extern void free_early(u64 start, u64 end);
-void free_early_partial(u64 start, u64 end);
-extern void early_res_to_bootmem(u64 start, u64 end);
-
-void reserve_early_without_check(u64 start, u64 end, char *name);
-u64 find_early_area(u64 ei_start, u64 ei_last, u64 start, u64 end,
-                        u64 size, u64 align);
-u64 find_early_area_size(u64 ei_start, u64 ei_last, u64 start,
-                        u64 *sizep, u64 align);
-u64 find_fw_memmap_area(u64 start, u64 end, u64 size, u64 align);
-u64 get_max_mapped(void);
-#include <linux/range.h>
-int get_free_all_memory_range(struct range **rangep, int nodeid);
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_EARLY_RES_H */
index 7cf92e8a4196c0f6a38257cec095b1aa6d04939f..36c66443bdfd260def7dd6e9724f751dd17c7cc6 100644 (file)
@@ -13,6 +13,7 @@
 #define _LINUX_EDAC_H_
 
 #include <asm/atomic.h>
+#include <linux/sysdev.h>
 
 #define EDAC_OPSTATE_INVAL     -1
 #define EDAC_OPSTATE_POLL      0
 extern int edac_op_state;
 extern int edac_err_assert;
 extern atomic_t edac_handlers;
+extern struct sysdev_class edac_class;
 
 extern int edac_handler_set(void);
 extern void edac_atomic_assert_error(void);
+extern struct sysdev_class *edac_get_sysfs_class(void);
+extern void edac_put_sysfs_class(void);
 
 static inline void opstate_init(void)
 {
index f59ed297b661fceb086a6ca188b54c3ff0006f85..133c0ba25e306a68199d399cf26fc15c242d347a 100644 (file)
@@ -31,7 +31,7 @@ struct embedded_fd_set {
 
 struct fdtable {
        unsigned int max_fds;
-       struct file ** fd;      /* current fd array */
+       struct file __rcu **fd;      /* current fd array */
        fd_set *close_on_exec;
        fd_set *open_fds;
        struct rcu_head rcu;
@@ -46,7 +46,7 @@ struct files_struct {
    * read mostly part
    */
        atomic_t count;
-       struct fdtable *fdt;
+       struct fdtable __rcu *fdt;
        struct fdtable fdtab;
   /*
    * written part on a separate cache line in SMP
@@ -55,7 +55,7 @@ struct files_struct {
        int next_fd;
        struct embedded_fd_set close_on_exec_init;
        struct embedded_fd_set open_fds_init;
-       struct file * fd_array[NR_OPEN_DEFAULT];
+       struct file __rcu * fd_array[NR_OPEN_DEFAULT];
 };
 
 #define rcu_dereference_check_fdtable(files, fdtfd) \
index 63d069bd80b702c392d4052bf2be937f90763692..7d6f18fddfdb9241b6734eb918828dbec253a8ba 100644 (file)
@@ -1384,7 +1384,7 @@ struct super_block {
         * Saved mount options for lazy filesystems using
         * generic_show_options()
         */
-       char *s_options;
+       char __rcu *s_options;
 };
 
 extern struct timespec current_fs_time(struct super_block *sb);
@@ -2378,6 +2378,8 @@ extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos,
 
 extern int generic_file_fsync(struct file *, int);
 
+extern int generic_check_addressable(unsigned, u64);
+
 #ifdef CONFIG_MIGRATION
 extern int buffer_migrate_page(struct address_space *,
                                struct page *, struct page *);
index 02b8b24f8f51f0e37156731ba94da19ba2d19131..8beabb958f61d5147c8893f1e780415a91fcb2e6 100644 (file)
@@ -191,8 +191,8 @@ struct ftrace_event_call {
        unsigned int            flags;
 
 #ifdef CONFIG_PERF_EVENTS
-       int                     perf_refcount;
-       struct hlist_head       *perf_events;
+       int                             perf_refcount;
+       struct hlist_head __percpu      *perf_events;
 #endif
 };
 
@@ -252,8 +252,8 @@ DECLARE_PER_CPU(struct pt_regs, perf_trace_regs);
 
 extern int  perf_trace_init(struct perf_event *event);
 extern void perf_trace_destroy(struct perf_event *event);
-extern int  perf_trace_enable(struct perf_event *event);
-extern void perf_trace_disable(struct perf_event *event);
+extern int  perf_trace_add(struct perf_event *event, int flags);
+extern void perf_trace_del(struct perf_event *event, int flags);
 extern int  ftrace_profile_set_filter(struct perf_event *event, int event_id,
                                     char *filter_str);
 extern void ftrace_profile_free_filter(struct perf_event *event);
index 5f2f4c4d8fb0594720bfc1643cec75fbf12aaa36..af3f06b41dc1e520a7729eb10e73f22b26ed8dff 100644 (file)
@@ -129,8 +129,8 @@ struct blk_scsi_cmd_filter {
 struct disk_part_tbl {
        struct rcu_head rcu_head;
        int len;
-       struct hd_struct *last_lookup;
-       struct hd_struct *part[];
+       struct hd_struct __rcu *last_lookup;
+       struct hd_struct __rcu *part[];
 };
 
 struct gendisk {
@@ -149,7 +149,7 @@ struct gendisk {
         * non-critical accesses use RCU.  Always access through
         * helpers.
         */
-       struct disk_part_tbl *part_tbl;
+       struct disk_part_tbl __rcu *part_tbl;
        struct hd_struct part0;
 
        const struct block_device_operations *fops;
index d5b387669dab1f044406826847fdfa7646ab829d..8a389b608ce3b568e85d14dcbfb71f8f98cf0c13 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/lockdep.h>
 #include <linux/ftrace_irq.h>
 #include <asm/hardirq.h>
-#include <asm/system.h>
 
 /*
  * We put the hardirq and softirq counter into the preemption
@@ -64,6 +63,8 @@
 #define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT)
 #define NMI_OFFSET     (1UL << NMI_SHIFT)
 
+#define SOFTIRQ_DISABLE_OFFSET (2 * SOFTIRQ_OFFSET)
+
 #ifndef PREEMPT_ACTIVE
 #define PREEMPT_ACTIVE_BITS    1
 #define PREEMPT_ACTIVE_SHIFT   (NMI_SHIFT + NMI_BITS)
 /*
  * Are we doing bottom half or hardware interrupt processing?
  * Are we in a softirq context? Interrupt context?
+ * in_softirq - Are we currently processing softirq or have bh disabled?
+ * in_serving_softirq - Are we currently processing softirq?
  */
 #define in_irq()               (hardirq_count())
 #define in_softirq()           (softirq_count())
 #define in_interrupt()         (irq_count())
+#define in_serving_softirq()   (softirq_count() & SOFTIRQ_OFFSET)
 
 /*
  * Are we in NMI context?
@@ -132,14 +136,16 @@ extern void synchronize_irq(unsigned int irq);
 
 struct task_struct;
 
-#ifndef CONFIG_VIRT_CPU_ACCOUNTING
+#if !defined(CONFIG_VIRT_CPU_ACCOUNTING) && !defined(CONFIG_IRQ_TIME_ACCOUNTING)
 static inline void account_system_vtime(struct task_struct *tsk)
 {
 }
+#else
+extern void account_system_vtime(struct task_struct *tsk);
 #endif
 
 #if defined(CONFIG_NO_HZ)
-#if defined(CONFIG_TINY_RCU)
+#if defined(CONFIG_TINY_RCU) || defined(CONFIG_TINY_PREEMPT_RCU)
 extern void rcu_enter_nohz(void);
 extern void rcu_exit_nohz(void);
 
index c96ea46737d03067afeeeeb4191c29c3ec438d6f..70a1dbbf209350836f97743363fadfe4f6f95b36 100644 (file)
@@ -9,8 +9,9 @@ struct ht_irq_msg {
 /* Helper functions.. */
 void fetch_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg);
 void write_ht_irq_msg(unsigned int irq, struct ht_irq_msg *msg);
-void mask_ht_irq(unsigned int irq);
-void unmask_ht_irq(unsigned int irq);
+struct irq_data;
+void mask_ht_irq(struct irq_data *data);
+void unmask_ht_irq(struct irq_data *data);
 
 /* The arch hook for getting things started */
 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev);
index e968db71e33a94548160cb38c216289ab1577c30..cdb715e58e3e6de8b2e60485e31ce79ea99da8f4 100644 (file)
 
 struct idr_layer {
        unsigned long            bitmap; /* A zero bit means "space here" */
-       struct idr_layer        *ary[1<<IDR_BITS];
+       struct idr_layer __rcu  *ary[1<<IDR_BITS];
        int                      count;  /* When zero, we can release it */
        int                      layer;  /* distance from leaf */
        struct rcu_head          rcu_head;
 };
 
 struct idr {
-       struct idr_layer *top;
+       struct idr_layer __rcu *top;
        struct idr_layer *id_free;
        int               layers; /* only valid without concurrent changes */
        int               id_free_cnt;
index 1f43fa56f6001f821736e4b66e9fac5e6e0375ed..2fea6c8ef6babea0564ccf3b061698cacba1d14e 100644 (file)
@@ -82,11 +82,17 @@ extern struct group_info init_groups;
 # define CAP_INIT_BSET  CAP_FULL_SET
 
 #ifdef CONFIG_TREE_PREEMPT_RCU
+#define INIT_TASK_RCU_TREE_PREEMPT()                                   \
+       .rcu_blocked_node = NULL,
+#else
+#define INIT_TASK_RCU_TREE_PREEMPT(tsk)
+#endif
+#ifdef CONFIG_PREEMPT_RCU
 #define INIT_TASK_RCU_PREEMPT(tsk)                                     \
        .rcu_read_lock_nesting = 0,                                     \
        .rcu_read_unlock_special = 0,                                   \
-       .rcu_blocked_node = NULL,                                       \
-       .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry),
+       .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry),           \
+       INIT_TASK_RCU_TREE_PREEMPT()
 #else
 #define INIT_TASK_RCU_PREEMPT(tsk)
 #endif
@@ -137,8 +143,8 @@ extern struct cred init_cred;
        .children       = LIST_HEAD_INIT(tsk.children),                 \
        .sibling        = LIST_HEAD_INIT(tsk.sibling),                  \
        .group_leader   = &tsk,                                         \
-       .real_cred      = &init_cred,                                   \
-       .cred           = &init_cred,                                   \
+       RCU_INIT_POINTER(.real_cred, &init_cred),                       \
+       RCU_INIT_POINTER(.cred, &init_cred),                            \
        .cred_guard_mutex =                                             \
                 __MUTEX_INITIALIZER(tsk.cred_guard_mutex),             \
        .comm           = "swapper",                                    \
index 896a92227bc429a9abdd27da5e3b0d77be122d95..d6ae1761be97fae4cbbc66602d19d9bdd60f3bdd 100644 (file)
@@ -1196,7 +1196,7 @@ struct input_dev {
        int (*flush)(struct input_dev *dev, struct file *file);
        int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 
-       struct input_handle *grab;
+       struct input_handle __rcu *grab;
 
        spinlock_t event_lock;
        struct mutex mutex;
index a0384a4d1e6f4da4d39a02c0f8ba6634842dd236..07f741a075a78fe242bed11b7bdc9bd712ed557f 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/atomic.h>
 #include <asm/ptrace.h>
 #include <asm/system.h>
+#include <trace/events/irq.h>
 
 /*
  * These correspond to the IORESOURCE_IRQ_* defines in
@@ -407,7 +408,12 @@ asmlinkage void do_softirq(void);
 asmlinkage void __do_softirq(void);
 extern void open_softirq(int nr, void (*action)(struct softirq_action *));
 extern void softirq_init(void);
-#define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0)
+static inline void __raise_softirq_irqoff(unsigned int nr)
+{
+       trace_softirq_raise(nr);
+       or_softirq_pending(1UL << nr);
+}
+
 extern void raise_softirq_irqoff(unsigned int nr);
 extern void raise_softirq(unsigned int nr);
 extern void wakeup_softirqd(void);
@@ -641,11 +647,8 @@ static inline void init_irq_proc(void)
 struct seq_file;
 int show_interrupts(struct seq_file *p, void *v);
 
-struct irq_desc;
-
 extern int early_irq_init(void);
 extern int arch_probe_nr_irqs(void);
 extern int arch_early_irq_init(void);
-extern int arch_init_chip_data(struct irq_desc *desc, int node);
 
 #endif
index 64d5291330312ac718ba7f649e3d428063127f39..3e70b21884a948880f90e28684e5d5778e7a3d35 100644 (file)
@@ -53,7 +53,7 @@ struct io_context {
 
        struct radix_tree_root radix_root;
        struct hlist_head cic_list;
-       void *ioc_data;
+       void __rcu *ioc_data;
 };
 
 static inline struct io_context *ioc_task_link(struct io_context *ioc)
index c03243ad84b46b220324d499b18e0805e9fb827b..e9639115dff1b920095b79b92202767cd0ed0537 100644 (file)
@@ -72,6 +72,10 @@ typedef      void (*irq_flow_handler_t)(unsigned int irq,
 #define IRQ_ONESHOT            0x08000000      /* IRQ is not unmasked after hardirq */
 #define IRQ_NESTED_THREAD      0x10000000      /* IRQ is nested into another, no own handler thread */
 
+#define IRQF_MODIFY_MASK       \
+       (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \
+        IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL)
+
 #ifdef CONFIG_IRQ_PER_CPU
 # define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
 # define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING)
@@ -80,36 +84,77 @@ typedef     void (*irq_flow_handler_t)(unsigned int irq,
 # define IRQ_NO_BALANCING_MASK IRQ_NO_BALANCING
 #endif
 
-struct proc_dir_entry;
 struct msi_desc;
 
+/**
+ * struct irq_data - per irq and irq chip data passed down to chip functions
+ * @irq:               interrupt number
+ * @node:              node index useful for balancing
+ * @chip:              low level interrupt hardware access
+ * @handler_data:      per-IRQ data for the irq_chip methods
+ * @chip_data:         platform-specific per-chip private data for the chip
+ *                     methods, to allow shared chip implementations
+ * @msi_desc:          MSI descriptor
+ * @affinity:          IRQ affinity on SMP
+ *
+ * The fields here need to overlay the ones in irq_desc until we
+ * cleaned up the direct references and switched everything over to
+ * irq_data.
+ */
+struct irq_data {
+       unsigned int            irq;
+       unsigned int            node;
+       struct irq_chip         *chip;
+       void                    *handler_data;
+       void                    *chip_data;
+       struct msi_desc         *msi_desc;
+#ifdef CONFIG_SMP
+       cpumask_var_t           affinity;
+#endif
+};
+
 /**
  * struct irq_chip - hardware interrupt chip descriptor
  *
  * @name:              name for /proc/interrupts
- * @startup:           start up the interrupt (defaults to ->enable if NULL)
- * @shutdown:          shut down the interrupt (defaults to ->disable if NULL)
- * @enable:            enable the interrupt (defaults to chip->unmask if NULL)
- * @disable:           disable the interrupt
- * @ack:               start of a new interrupt
- * @mask:              mask an interrupt source
- * @mask_ack:          ack and mask an interrupt source
- * @unmask:            unmask an interrupt source
- * @eoi:               end of interrupt - chip level
- * @end:               end of interrupt - flow level
- * @set_affinity:      set the CPU affinity on SMP machines
- * @retrigger:         resend an IRQ to the CPU
- * @set_type:          set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
- * @set_wake:          enable/disable power-management wake-on of an IRQ
+ * @startup:           deprecated, replaced by irq_startup
+ * @shutdown:          deprecated, replaced by irq_shutdown
+ * @enable:            deprecated, replaced by irq_enable
+ * @disable:           deprecated, replaced by irq_disable
+ * @ack:               deprecated, replaced by irq_ack
+ * @mask:              deprecated, replaced by irq_mask
+ * @mask_ack:          deprecated, replaced by irq_mask_ack
+ * @unmask:            deprecated, replaced by irq_unmask
+ * @eoi:               deprecated, replaced by irq_eoi
+ * @end:               deprecated, will go away with __do_IRQ()
+ * @set_affinity:      deprecated, replaced by irq_set_affinity
+ * @retrigger:         deprecated, replaced by irq_retrigger
+ * @set_type:          deprecated, replaced by irq_set_type
+ * @set_wake:          deprecated, replaced by irq_wake
+ * @bus_lock:          deprecated, replaced by irq_bus_lock
+ * @bus_sync_unlock:   deprecated, replaced by irq_bus_sync_unlock
  *
- * @bus_lock:          function to lock access to slow bus (i2c) chips
- * @bus_sync_unlock:   function to sync and unlock slow bus (i2c) chips
+ * @irq_startup:       start up the interrupt (defaults to ->enable if NULL)
+ * @irq_shutdown:      shut down the interrupt (defaults to ->disable if NULL)
+ * @irq_enable:                enable the interrupt (defaults to chip->unmask if NULL)
+ * @irq_disable:       disable the interrupt
+ * @irq_ack:           start of a new interrupt
+ * @irq_mask:          mask an interrupt source
+ * @irq_mask_ack:      ack and mask an interrupt source
+ * @irq_unmask:                unmask an interrupt source
+ * @irq_eoi:           end of interrupt
+ * @irq_set_affinity:  set the CPU affinity on SMP machines
+ * @irq_retrigger:     resend an IRQ to the CPU
+ * @irq_set_type:      set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ
+ * @irq_set_wake:      enable/disable power-management wake-on of an IRQ
+ * @irq_bus_lock:      function to lock access to slow bus (i2c) chips
+ * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips
  *
  * @release:           release function solely used by UML
- * @typename:          obsoleted by name, kept as migration helper
  */
 struct irq_chip {
        const char      *name;
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
        unsigned int    (*startup)(unsigned int irq);
        void            (*shutdown)(unsigned int irq);
        void            (*enable)(unsigned int irq);
@@ -130,154 +175,66 @@ struct irq_chip {
 
        void            (*bus_lock)(unsigned int irq);
        void            (*bus_sync_unlock)(unsigned int irq);
+#endif
+       unsigned int    (*irq_startup)(struct irq_data *data);
+       void            (*irq_shutdown)(struct irq_data *data);
+       void            (*irq_enable)(struct irq_data *data);
+       void            (*irq_disable)(struct irq_data *data);
+
+       void            (*irq_ack)(struct irq_data *data);
+       void            (*irq_mask)(struct irq_data *data);
+       void            (*irq_mask_ack)(struct irq_data *data);
+       void            (*irq_unmask)(struct irq_data *data);
+       void            (*irq_eoi)(struct irq_data *data);
+
+       int             (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
+       int             (*irq_retrigger)(struct irq_data *data);
+       int             (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
+       int             (*irq_set_wake)(struct irq_data *data, unsigned int on);
+
+       void            (*irq_bus_lock)(struct irq_data *data);
+       void            (*irq_bus_sync_unlock)(struct irq_data *data);
 
        /* Currently used only by UML, might disappear one day.*/
 #ifdef CONFIG_IRQ_RELEASE_METHOD
        void            (*release)(unsigned int irq, void *dev_id);
 #endif
-       /*
-        * For compatibility, ->typename is copied into ->name.
-        * Will disappear.
-        */
-       const char      *typename;
 };
 
-struct timer_rand_state;
-struct irq_2_iommu;
-/**
- * struct irq_desc - interrupt descriptor
- * @irq:               interrupt number for this descriptor
- * @timer_rand_state:  pointer to timer rand state struct
- * @kstat_irqs:                irq stats per cpu
- * @irq_2_iommu:       iommu with this irq
- * @handle_irq:                highlevel irq-events handler [if NULL, __do_IRQ()]
- * @chip:              low level interrupt hardware access
- * @msi_desc:          MSI descriptor
- * @handler_data:      per-IRQ data for the irq_chip methods
- * @chip_data:         platform-specific per-chip private data for the chip
- *                     methods, to allow shared chip implementations
- * @action:            the irq action chain
- * @status:            status information
- * @depth:             disable-depth, for nested irq_disable() calls
- * @wake_depth:                enable depth, for multiple set_irq_wake() callers
- * @irq_count:         stats field to detect stalled irqs
- * @last_unhandled:    aging timer for unhandled count
- * @irqs_unhandled:    stats field for spurious unhandled interrupts
- * @lock:              locking for SMP
- * @affinity:          IRQ affinity on SMP
- * @node:              node index useful for balancing
- * @pending_mask:      pending rebalanced interrupts
- * @threads_active:    number of irqaction threads currently running
- * @wait_for_threads:  wait queue for sync_irq to wait for threaded handlers
- * @dir:               /proc/irq/ procfs entry
- * @name:              flow handler name for /proc/interrupts output
- */
-struct irq_desc {
-       unsigned int            irq;
-       struct timer_rand_state *timer_rand_state;
-       unsigned int            *kstat_irqs;
-#ifdef CONFIG_INTR_REMAP
-       struct irq_2_iommu      *irq_2_iommu;
-#endif
-       irq_flow_handler_t      handle_irq;
-       struct irq_chip         *chip;
-       struct msi_desc         *msi_desc;
-       void                    *handler_data;
-       void                    *chip_data;
-       struct irqaction        *action;        /* IRQ action list */
-       unsigned int            status;         /* IRQ status */
-
-       unsigned int            depth;          /* nested irq disables */
-       unsigned int            wake_depth;     /* nested wake enables */
-       unsigned int            irq_count;      /* For detecting broken IRQs */
-       unsigned long           last_unhandled; /* Aging timer for unhandled count */
-       unsigned int            irqs_unhandled;
-       raw_spinlock_t          lock;
-#ifdef CONFIG_SMP
-       cpumask_var_t           affinity;
-       const struct cpumask    *affinity_hint;
-       unsigned int            node;
-#ifdef CONFIG_GENERIC_PENDING_IRQ
-       cpumask_var_t           pending_mask;
-#endif
-#endif
-       atomic_t                threads_active;
-       wait_queue_head_t       wait_for_threads;
-#ifdef CONFIG_PROC_FS
-       struct proc_dir_entry   *dir;
-#endif
-       const char              *name;
-} ____cacheline_internodealigned_in_smp;
+/* This include will go away once we isolated irq_desc usage to core code */
+#include <linux/irqdesc.h>
 
-extern void arch_init_copy_chip_data(struct irq_desc *old_desc,
-                                       struct irq_desc *desc, int node);
-extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc);
+/*
+ * Pick up the arch-dependent methods:
+ */
+#include <asm/hw_irq.h>
 
-#ifndef CONFIG_SPARSE_IRQ
-extern struct irq_desc irq_desc[NR_IRQS];
+#ifndef NR_IRQS_LEGACY
+# define NR_IRQS_LEGACY 0
 #endif
 
-#ifdef CONFIG_NUMA_IRQ_DESC
-extern struct irq_desc *move_irq_desc(struct irq_desc *old_desc, int node);
-#else
-static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
-{
-       return desc;
-}
+#ifndef ARCH_IRQ_INIT_FLAGS
+# define ARCH_IRQ_INIT_FLAGS   0
 #endif
 
-extern struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node);
-
-/*
- * Pick up the arch-dependent methods:
- */
-#include <asm/hw_irq.h>
+#define IRQ_DEFAULT_INIT_FLAGS (IRQ_DISABLED | ARCH_IRQ_INIT_FLAGS)
 
+struct irqaction;
 extern int setup_irq(unsigned int irq, struct irqaction *new);
 extern void remove_irq(unsigned int irq, struct irqaction *act);
 
 #ifdef CONFIG_GENERIC_HARDIRQS
 
-#ifdef CONFIG_SMP
-
-#ifdef CONFIG_GENERIC_PENDING_IRQ
-
+#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ)
 void move_native_irq(int irq);
 void move_masked_irq(int irq);
-
-#else /* CONFIG_GENERIC_PENDING_IRQ */
-
-static inline void move_irq(int irq)
-{
-}
-
-static inline void move_native_irq(int irq)
-{
-}
-
-static inline void move_masked_irq(int irq)
-{
-}
-
-#endif /* CONFIG_GENERIC_PENDING_IRQ */
-
-#else /* CONFIG_SMP */
-
-#define move_native_irq(x)
-#define move_masked_irq(x)
-
-#endif /* CONFIG_SMP */
+#else
+static inline void move_native_irq(int irq) { }
+static inline void move_masked_irq(int irq) { }
+#endif
 
 extern int no_irq_affinity;
 
-static inline int irq_balancing_disabled(unsigned int irq)
-{
-       struct irq_desc *desc;
-
-       desc = irq_to_desc(irq);
-       return desc->status & IRQ_NO_BALANCING_MASK;
-}
-
 /* Handle irq action chains: */
 extern irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action);
 
@@ -293,42 +250,10 @@ extern void handle_percpu_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
 extern void handle_nested_irq(unsigned int irq);
 
-/*
- * Monolithic do_IRQ implementation.
- */
-#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
-extern unsigned int __do_IRQ(unsigned int irq);
-#endif
-
-/*
- * Architectures call this to let the generic IRQ layer
- * handle an interrupt. If the descriptor is attached to an
- * irqchip-style controller then we call the ->handle_irq() handler,
- * and it calls __do_IRQ() if it's attached to an irqtype-style controller.
- */
-static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
-{
-#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
-       desc->handle_irq(irq, desc);
-#else
-       if (likely(desc->handle_irq))
-               desc->handle_irq(irq, desc);
-       else
-               __do_IRQ(irq);
-#endif
-}
-
-static inline void generic_handle_irq(unsigned int irq)
-{
-       generic_handle_irq_desc(irq, irq_to_desc(irq));
-}
-
 /* Handling of unhandled and spurious interrupts: */
 extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
                           irqreturn_t action_ret);
 
-/* Resending of interrupts :*/
-void check_irq_resend(struct irq_desc *desc, unsigned int irq);
 
 /* Enable/disable irq debugging output: */
 extern int noirqdebug_setup(char *str);
@@ -351,16 +276,6 @@ extern void
 __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
                  const char *name);
 
-/* caller has locked the irq_desc and both params are valid */
-static inline void __set_irq_handler_unlocked(int irq,
-                                             irq_flow_handler_t handler)
-{
-       struct irq_desc *desc;
-
-       desc = irq_to_desc(irq);
-       desc->handle_irq = handler;
-}
-
 /*
  * Set a highlevel flow handler for a given IRQ:
  */
@@ -384,141 +299,121 @@ set_irq_chained_handler(unsigned int irq,
 
 extern void set_irq_nested_thread(unsigned int irq, int nest);
 
-extern void set_irq_noprobe(unsigned int irq);
-extern void set_irq_probe(unsigned int irq);
+void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set);
+
+static inline void irq_set_status_flags(unsigned int irq, unsigned long set)
+{
+       irq_modify_status(irq, 0, set);
+}
+
+static inline void irq_clear_status_flags(unsigned int irq, unsigned long clr)
+{
+       irq_modify_status(irq, clr, 0);
+}
+
+static inline void set_irq_noprobe(unsigned int irq)
+{
+       irq_modify_status(irq, 0, IRQ_NOPROBE);
+}
+
+static inline void set_irq_probe(unsigned int irq)
+{
+       irq_modify_status(irq, IRQ_NOPROBE, 0);
+}
 
 /* Handle dynamic irq creation and destruction */
 extern unsigned int create_irq_nr(unsigned int irq_want, int node);
 extern int create_irq(void);
 extern void destroy_irq(unsigned int irq);
 
-/* Test to see if a driver has successfully requested an irq */
-static inline int irq_has_action(unsigned int irq)
+/*
+ * Dynamic irq helper functions. Obsolete. Use irq_alloc_desc* and
+ * irq_free_desc instead.
+ */
+extern void dynamic_irq_cleanup(unsigned int irq);
+static inline void dynamic_irq_init(unsigned int irq)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
-       return desc->action != NULL;
+       dynamic_irq_cleanup(irq);
 }
 
-/* Dynamic irq helper functions */
-extern void dynamic_irq_init(unsigned int irq);
-void dynamic_irq_init_keep_chip_data(unsigned int irq);
-extern void dynamic_irq_cleanup(unsigned int irq);
-void dynamic_irq_cleanup_keep_chip_data(unsigned int irq);
-
 /* Set/get chip/data for an IRQ: */
 extern int set_irq_chip(unsigned int irq, struct irq_chip *chip);
 extern int set_irq_data(unsigned int irq, void *data);
 extern int set_irq_chip_data(unsigned int irq, void *data);
 extern int set_irq_type(unsigned int irq, unsigned int type);
 extern int set_irq_msi(unsigned int irq, struct msi_desc *entry);
+extern struct irq_data *irq_get_irq_data(unsigned int irq);
 
-#define get_irq_chip(irq)      (irq_to_desc(irq)->chip)
-#define get_irq_chip_data(irq) (irq_to_desc(irq)->chip_data)
-#define get_irq_data(irq)      (irq_to_desc(irq)->handler_data)
-#define get_irq_msi(irq)       (irq_to_desc(irq)->msi_desc)
-
-#define get_irq_desc_chip(desc)                ((desc)->chip)
-#define get_irq_desc_chip_data(desc)   ((desc)->chip_data)
-#define get_irq_desc_data(desc)                ((desc)->handler_data)
-#define get_irq_desc_msi(desc)         ((desc)->msi_desc)
-
-#endif /* CONFIG_GENERIC_HARDIRQS */
-
-#endif /* !CONFIG_S390 */
-
-#ifdef CONFIG_SMP
-/**
- * alloc_desc_masks - allocate cpumasks for irq_desc
- * @desc:      pointer to irq_desc struct
- * @node:      node which will be handling the cpumasks
- * @boot:      true if need bootmem
- *
- * Allocates affinity and pending_mask cpumask if required.
- * Returns true if successful (or not required).
- */
-static inline bool alloc_desc_masks(struct irq_desc *desc, int node,
-                                                       bool boot)
+static inline struct irq_chip *get_irq_chip(unsigned int irq)
 {
-       gfp_t gfp = GFP_ATOMIC;
-
-       if (boot)
-               gfp = GFP_NOWAIT;
-
-#ifdef CONFIG_CPUMASK_OFFSTACK
-       if (!alloc_cpumask_var_node(&desc->affinity, gfp, node))
-               return false;
+       struct irq_data *d = irq_get_irq_data(irq);
+       return d ? d->chip : NULL;
+}
 
-#ifdef CONFIG_GENERIC_PENDING_IRQ
-       if (!alloc_cpumask_var_node(&desc->pending_mask, gfp, node)) {
-               free_cpumask_var(desc->affinity);
-               return false;
-       }
-#endif
-#endif
-       return true;
+static inline struct irq_chip *irq_data_get_irq_chip(struct irq_data *d)
+{
+       return d->chip;
 }
 
-static inline void init_desc_masks(struct irq_desc *desc)
+static inline void *get_irq_chip_data(unsigned int irq)
 {
-       cpumask_setall(desc->affinity);
-#ifdef CONFIG_GENERIC_PENDING_IRQ
-       cpumask_clear(desc->pending_mask);
-#endif
+       struct irq_data *d = irq_get_irq_data(irq);
+       return d ? d->chip_data : NULL;
 }
 
-/**
- * init_copy_desc_masks - copy cpumasks for irq_desc
- * @old_desc:  pointer to old irq_desc struct
- * @new_desc:  pointer to new irq_desc struct
- *
- * Insures affinity and pending_masks are copied to new irq_desc.
- * If !CONFIG_CPUMASKS_OFFSTACK the cpumasks are embedded in the
- * irq_desc struct so the copy is redundant.
- */
+static inline void *irq_data_get_irq_chip_data(struct irq_data *d)
+{
+       return d->chip_data;
+}
 
-static inline void init_copy_desc_masks(struct irq_desc *old_desc,
-                                       struct irq_desc *new_desc)
+static inline void *get_irq_data(unsigned int irq)
 {
-#ifdef CONFIG_CPUMASK_OFFSTACK
-       cpumask_copy(new_desc->affinity, old_desc->affinity);
+       struct irq_data *d = irq_get_irq_data(irq);
+       return d ? d->handler_data : NULL;
+}
 
-#ifdef CONFIG_GENERIC_PENDING_IRQ
-       cpumask_copy(new_desc->pending_mask, old_desc->pending_mask);
-#endif
-#endif
+static inline void *irq_data_get_irq_data(struct irq_data *d)
+{
+       return d->handler_data;
 }
 
-static inline void free_desc_masks(struct irq_desc *old_desc,
-                                  struct irq_desc *new_desc)
+static inline struct msi_desc *get_irq_msi(unsigned int irq)
 {
-       free_cpumask_var(old_desc->affinity);
+       struct irq_data *d = irq_get_irq_data(irq);
+       return d ? d->msi_desc : NULL;
+}
 
-#ifdef CONFIG_GENERIC_PENDING_IRQ
-       free_cpumask_var(old_desc->pending_mask);
-#endif
+static inline struct msi_desc *irq_data_get_msi(struct irq_data *d)
+{
+       return d->msi_desc;
 }
 
-#else /* !CONFIG_SMP */
+int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node);
+void irq_free_descs(unsigned int irq, unsigned int cnt);
+int irq_reserve_irqs(unsigned int from, unsigned int cnt);
 
-static inline bool alloc_desc_masks(struct irq_desc *desc, int node,
-                                                               bool boot)
+static inline int irq_alloc_desc(int node)
 {
-       return true;
+       return irq_alloc_descs(-1, 0, 1, node);
 }
 
-static inline void init_desc_masks(struct irq_desc *desc)
+static inline int irq_alloc_desc_at(unsigned int at, int node)
 {
+       return irq_alloc_descs(at, at, 1, node);
 }
 
-static inline void init_copy_desc_masks(struct irq_desc *old_desc,
-                                       struct irq_desc *new_desc)
+static inline int irq_alloc_desc_from(unsigned int from, int node)
 {
+       return irq_alloc_descs(-1, from, 1, node);
 }
 
-static inline void free_desc_masks(struct irq_desc *old_desc,
-                                  struct irq_desc *new_desc)
+static inline void irq_free_desc(unsigned int irq)
 {
+       irq_free_descs(irq, 1);
 }
-#endif /* CONFIG_SMP */
+
+#endif /* CONFIG_GENERIC_HARDIRQS */
+
+#endif /* !CONFIG_S390 */
 
 #endif /* _LINUX_IRQ_H */
diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h
new file mode 100644 (file)
index 0000000..4fa09d4
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _LINUX_IRQ_WORK_H
+#define _LINUX_IRQ_WORK_H
+
+struct irq_work {
+       struct irq_work *next;
+       void (*func)(struct irq_work *);
+};
+
+static inline
+void init_irq_work(struct irq_work *entry, void (*func)(struct irq_work *))
+{
+       entry->next = NULL;
+       entry->func = func;
+}
+
+bool irq_work_queue(struct irq_work *entry);
+void irq_work_run(void);
+void irq_work_sync(struct irq_work *entry);
+
+#endif /* _LINUX_IRQ_WORK_H */
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
new file mode 100644 (file)
index 0000000..979c68c
--- /dev/null
@@ -0,0 +1,159 @@
+#ifndef _LINUX_IRQDESC_H
+#define _LINUX_IRQDESC_H
+
+/*
+ * Core internal functions to deal with irq descriptors
+ *
+ * This include will move to kernel/irq once we cleaned up the tree.
+ * For now it's included from <linux/irq.h>
+ */
+
+struct proc_dir_entry;
+struct timer_rand_state;
+/**
+ * struct irq_desc - interrupt descriptor
+ * @irq_data:          per irq and chip data passed down to chip functions
+ * @timer_rand_state:  pointer to timer rand state struct
+ * @kstat_irqs:                irq stats per cpu
+ * @handle_irq:                highlevel irq-events handler [if NULL, __do_IRQ()]
+ * @action:            the irq action chain
+ * @status:            status information
+ * @depth:             disable-depth, for nested irq_disable() calls
+ * @wake_depth:                enable depth, for multiple set_irq_wake() callers
+ * @irq_count:         stats field to detect stalled irqs
+ * @last_unhandled:    aging timer for unhandled count
+ * @irqs_unhandled:    stats field for spurious unhandled interrupts
+ * @lock:              locking for SMP
+ * @pending_mask:      pending rebalanced interrupts
+ * @threads_active:    number of irqaction threads currently running
+ * @wait_for_threads:  wait queue for sync_irq to wait for threaded handlers
+ * @dir:               /proc/irq/ procfs entry
+ * @name:              flow handler name for /proc/interrupts output
+ */
+struct irq_desc {
+
+#ifdef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
+       struct irq_data         irq_data;
+#else
+       /*
+        * This union will go away, once we fixed the direct access to
+        * irq_desc all over the place. The direct fields are a 1:1
+        * overlay of irq_data.
+        */
+       union {
+               struct irq_data         irq_data;
+               struct {
+                       unsigned int            irq;
+                       unsigned int            node;
+                       struct irq_chip         *chip;
+                       void                    *handler_data;
+                       void                    *chip_data;
+                       struct msi_desc         *msi_desc;
+#ifdef CONFIG_SMP
+                       cpumask_var_t           affinity;
+#endif
+               };
+       };
+#endif
+
+       struct timer_rand_state *timer_rand_state;
+       unsigned int            *kstat_irqs;
+       irq_flow_handler_t      handle_irq;
+       struct irqaction        *action;        /* IRQ action list */
+       unsigned int            status;         /* IRQ status */
+
+       unsigned int            depth;          /* nested irq disables */
+       unsigned int            wake_depth;     /* nested wake enables */
+       unsigned int            irq_count;      /* For detecting broken IRQs */
+       unsigned long           last_unhandled; /* Aging timer for unhandled count */
+       unsigned int            irqs_unhandled;
+       raw_spinlock_t          lock;
+#ifdef CONFIG_SMP
+       const struct cpumask    *affinity_hint;
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+       cpumask_var_t           pending_mask;
+#endif
+#endif
+       atomic_t                threads_active;
+       wait_queue_head_t       wait_for_threads;
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry   *dir;
+#endif
+       const char              *name;
+} ____cacheline_internodealigned_in_smp;
+
+#ifndef CONFIG_SPARSE_IRQ
+extern struct irq_desc irq_desc[NR_IRQS];
+#endif
+
+/* Will be removed once the last users in power and sh are gone */
+extern struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node);
+static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
+{
+       return desc;
+}
+
+#ifdef CONFIG_GENERIC_HARDIRQS
+
+#define get_irq_desc_chip(desc)                ((desc)->irq_data.chip)
+#define get_irq_desc_chip_data(desc)   ((desc)->irq_data.chip_data)
+#define get_irq_desc_data(desc)                ((desc)->irq_data.handler_data)
+#define get_irq_desc_msi(desc)         ((desc)->irq_data.msi_desc)
+
+/*
+ * Monolithic do_IRQ implementation.
+ */
+#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
+extern unsigned int __do_IRQ(unsigned int irq);
+#endif
+
+/*
+ * Architectures call this to let the generic IRQ layer
+ * handle an interrupt. If the descriptor is attached to an
+ * irqchip-style controller then we call the ->handle_irq() handler,
+ * and it calls __do_IRQ() if it's attached to an irqtype-style controller.
+ */
+static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
+{
+#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
+       desc->handle_irq(irq, desc);
+#else
+       if (likely(desc->handle_irq))
+               desc->handle_irq(irq, desc);
+       else
+               __do_IRQ(irq);
+#endif
+}
+
+static inline void generic_handle_irq(unsigned int irq)
+{
+       generic_handle_irq_desc(irq, irq_to_desc(irq));
+}
+
+/* Test to see if a driver has successfully requested an irq */
+static inline int irq_has_action(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       return desc->action != NULL;
+}
+
+static inline int irq_balancing_disabled(unsigned int irq)
+{
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+       return desc->status & IRQ_NO_BALANCING_MASK;
+}
+
+/* caller has locked the irq_desc and both params are valid */
+static inline void __set_irq_handler_unlocked(int irq,
+                                             irq_flow_handler_t handler)
+{
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+       desc->handle_irq = handler;
+}
+#endif
+
+#endif
index 006bf45eae30e5777ece188a997736cd5ff509cf..d176d658fe25dd6b09b3d03936a4b60ce324367c 100644 (file)
@@ -12,6 +12,7 @@
 #define _LINUX_TRACE_IRQFLAGS_H
 
 #include <linux/typecheck.h>
+#include <asm/irqflags.h>
 
 #ifdef CONFIG_TRACE_IRQFLAGS
   extern void trace_softirqs_on(unsigned long ip);
 # define start_critical_timings() do { } while (0)
 #endif
 
-#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
-
-#include <asm/irqflags.h>
+/*
+ * Wrap the arch provided IRQ routines to provide appropriate checks.
+ */
+#define raw_local_irq_disable()                arch_local_irq_disable()
+#define raw_local_irq_enable()         arch_local_irq_enable()
+#define raw_local_irq_save(flags)                      \
+       do {                                            \
+               typecheck(unsigned long, flags);        \
+               flags = arch_local_irq_save();          \
+       } while (0)
+#define raw_local_irq_restore(flags)                   \
+       do {                                            \
+               typecheck(unsigned long, flags);        \
+               arch_local_irq_restore(flags);          \
+       } while (0)
+#define raw_local_save_flags(flags)                    \
+       do {                                            \
+               typecheck(unsigned long, flags);        \
+               flags = arch_local_save_flags();        \
+       } while (0)
+#define raw_irqs_disabled_flags(flags)                 \
+       ({                                              \
+               typecheck(unsigned long, flags);        \
+               arch_irqs_disabled_flags(flags);        \
+       })
+#define raw_irqs_disabled()            (arch_irqs_disabled())
+#define raw_safe_halt()                        arch_safe_halt()
 
+/*
+ * The local_irq_*() APIs are equal to the raw_local_irq*()
+ * if !TRACE_IRQFLAGS.
+ */
+#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
 #define local_irq_enable() \
        do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0)
 #define local_irq_disable() \
        do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0)
 #define local_irq_save(flags)                          \
        do {                                            \
-               typecheck(unsigned long, flags);        \
                raw_local_irq_save(flags);              \
                trace_hardirqs_off();                   \
        } while (0)
@@ -70,7 +99,6 @@
 
 #define local_irq_restore(flags)                       \
        do {                                            \
-               typecheck(unsigned long, flags);        \
                if (raw_irqs_disabled_flags(flags)) {   \
                        raw_local_irq_restore(flags);   \
                        trace_hardirqs_off();           \
                        raw_local_irq_restore(flags);   \
                }                                       \
        } while (0)
-#else /* !CONFIG_TRACE_IRQFLAGS_SUPPORT */
-/*
- * The local_irq_*() APIs are equal to the raw_local_irq*()
- * if !TRACE_IRQFLAGS.
- */
-# define raw_local_irq_disable()       local_irq_disable()
-# define raw_local_irq_enable()                local_irq_enable()
-# define raw_local_irq_save(flags)                     \
-       do {                                            \
-               typecheck(unsigned long, flags);        \
-               local_irq_save(flags);                  \
-       } while (0)
-# define raw_local_irq_restore(flags)                  \
+#define local_save_flags(flags)                                \
        do {                                            \
-               typecheck(unsigned long, flags);        \
-               local_irq_restore(flags);               \
+               raw_local_save_flags(flags);            \
        } while (0)
-#endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */
 
-#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
-#define safe_halt()                                            \
-       do {                                                    \
-               trace_hardirqs_on();                            \
-               raw_safe_halt();                                \
-       } while (0)
+#define irqs_disabled_flags(flags)                     \
+       ({                                              \
+               raw_irqs_disabled_flags(flags);         \
+       })
 
-#define local_save_flags(flags)                                \
-       do {                                            \
-               typecheck(unsigned long, flags);        \
-               raw_local_save_flags(flags);            \
+#define irqs_disabled()                                        \
+       ({                                              \
+               unsigned long _flags;                   \
+               raw_local_save_flags(_flags);           \
+               raw_irqs_disabled_flags(_flags);        \
+       })
+
+#define safe_halt()                            \
+       do {                                    \
+               trace_hardirqs_on();            \
+               raw_safe_halt();                \
        } while (0)
 
-#define irqs_disabled()                                                \
-({                                                             \
-       unsigned long _flags;                                   \
-                                                               \
-       raw_local_save_flags(_flags);                           \
-       raw_irqs_disabled_flags(_flags);                        \
-})
 
-#define irqs_disabled_flags(flags)             \
-({                                             \
-       typecheck(unsigned long, flags);        \
-       raw_irqs_disabled_flags(flags);         \
-})
+#else /* !CONFIG_TRACE_IRQFLAGS_SUPPORT */
+
+#define local_irq_enable()     do { raw_local_irq_enable(); } while (0)
+#define local_irq_disable()    do { raw_local_irq_disable(); } while (0)
+#define local_irq_save(flags)                                  \
+       do {                                                    \
+               raw_local_irq_save(flags);                      \
+       } while (0)
+#define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0)
+#define local_save_flags(flags)        do { raw_local_save_flags(flags); } while (0)
+#define irqs_disabled()                (raw_irqs_disabled())
+#define irqs_disabled_flags(flags) (raw_irqs_disabled_flags(flags))
+#define safe_halt()            do { raw_safe_halt(); } while (0)
+
 #endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */
 
 #endif
index 7bf89bc8cbca32762d082664c1839d8d642f8782..05aa8c23483ff502bdf94e76365236fa44ff9721 100644 (file)
@@ -25,6 +25,7 @@
 
 extern int nr_irqs;
 extern struct irq_desc *irq_to_desc(unsigned int irq);
+unsigned int irq_get_next_irq(unsigned int offset);
 
 # define for_each_irq_desc(irq, desc)                                  \
        for (irq = 0, desc = irq_to_desc(irq); irq < nr_irqs;           \
@@ -47,6 +48,10 @@ extern struct irq_desc *irq_to_desc(unsigned int irq);
 #define irq_node(irq)  0
 #endif
 
+# define for_each_active_irq(irq)                      \
+       for (irq = irq_get_next_irq(0); irq < nr_irqs;  \
+            irq = irq_get_next_irq(irq + 1))
+
 #endif /* CONFIG_GENERIC_HARDIRQS */
 
 #define for_each_irq_nr(irq)                   \
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h
new file mode 100644 (file)
index 0000000..b67cb18
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef _LINUX_JUMP_LABEL_H
+#define _LINUX_JUMP_LABEL_H
+
+#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_HAVE_ARCH_JUMP_LABEL)
+# include <asm/jump_label.h>
+# define HAVE_JUMP_LABEL
+#endif
+
+enum jump_label_type {
+       JUMP_LABEL_ENABLE,
+       JUMP_LABEL_DISABLE
+};
+
+struct module;
+
+#ifdef HAVE_JUMP_LABEL
+
+extern struct jump_entry __start___jump_table[];
+extern struct jump_entry __stop___jump_table[];
+
+extern void arch_jump_label_transform(struct jump_entry *entry,
+                                enum jump_label_type type);
+extern void arch_jump_label_text_poke_early(jump_label_t addr);
+extern void jump_label_update(unsigned long key, enum jump_label_type type);
+extern void jump_label_apply_nops(struct module *mod);
+extern int jump_label_text_reserved(void *start, void *end);
+
+#define jump_label_enable(key) \
+       jump_label_update((unsigned long)key, JUMP_LABEL_ENABLE);
+
+#define jump_label_disable(key) \
+       jump_label_update((unsigned long)key, JUMP_LABEL_DISABLE);
+
+#else
+
+#define JUMP_LABEL(key, label)                 \
+do {                                           \
+       if (unlikely(*key))                     \
+               goto label;                     \
+} while (0)
+
+#define jump_label_enable(cond_var)    \
+do {                                   \
+       *(cond_var) = 1;                        \
+} while (0)
+
+#define jump_label_disable(cond_var)   \
+do {                                   \
+       *(cond_var) = 0;                        \
+} while (0)
+
+static inline int jump_label_apply_nops(struct module *mod)
+{
+       return 0;
+}
+
+static inline int jump_label_text_reserved(void *start, void *end)
+{
+       return 0;
+}
+
+#endif
+
+#define COND_STMT(key, stmt)                                   \
+do {                                                           \
+       __label__ jl_enabled;                                   \
+       JUMP_LABEL(key, jl_enabled);                            \
+       if (0) {                                                \
+jl_enabled:                                                    \
+               stmt;                                           \
+       }                                                       \
+} while (0)
+
+#endif
diff --git a/include/linux/jump_label_ref.h b/include/linux/jump_label_ref.h
new file mode 100644 (file)
index 0000000..e5d012a
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef _LINUX_JUMP_LABEL_REF_H
+#define _LINUX_JUMP_LABEL_REF_H
+
+#include <linux/jump_label.h>
+#include <asm/atomic.h>
+
+#ifdef HAVE_JUMP_LABEL
+
+static inline void jump_label_inc(atomic_t *key)
+{
+       if (atomic_add_return(1, key) == 1)
+               jump_label_enable(key);
+}
+
+static inline void jump_label_dec(atomic_t *key)
+{
+       if (atomic_dec_and_test(key))
+               jump_label_disable(key);
+}
+
+#else /* !HAVE_JUMP_LABEL */
+
+static inline void jump_label_inc(atomic_t *key)
+{
+       atomic_inc(key);
+}
+
+static inline void jump_label_dec(atomic_t *key)
+{
+       atomic_dec(key);
+}
+
+#undef JUMP_LABEL
+#define JUMP_LABEL(key, label)                                         \
+do {                                                                   \
+       if (unlikely(__builtin_choose_expr(                             \
+             __builtin_types_compatible_p(typeof(key), atomic_t *),    \
+             atomic_read((atomic_t *)(key)), *(key))))                 \
+               goto label;                                             \
+} while (0)
+
+#endif /* HAVE_JUMP_LABEL */
+
+#endif /* _LINUX_JUMP_LABEL_REF_H */
index 2b0a35e6bc691896609944c114328b414be37a12..1759ba5adce845fa08d4b1fd899920ac65436938 100644 (file)
@@ -58,7 +58,18 @@ extern const char linux_proc_banner[];
 
 #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
-#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+#define roundup(x, y) (                                        \
+{                                                      \
+       typeof(y) __y = y;                              \
+       (((x) + (__y - 1)) / __y) * __y;                \
+}                                                      \
+)
+#define rounddown(x, y) (                              \
+{                                                      \
+       typeof(x) __x = (x);                            \
+       __x - (__x % (y));                              \
+}                                                      \
+)
 #define DIV_ROUND_CLOSEST(x, divisor)(                 \
 {                                                      \
        typeof(divisor) __divisor = divisor;            \
index cd50dfa1d4c224de2a26e2d8ef3926d7fc74435e..3db0adce1fdabd00d034ad2e111b9d3411146dfd 100644 (file)
@@ -178,8 +178,9 @@ struct key {
         */
        union {
                unsigned long           value;
+               void __rcu              *rcudata;
                void                    *data;
-               struct keyring_list     *subscriptions;
+               struct keyring_list __rcu *subscriptions;
        } payload;
 };
 
index c13cc48697aa73d2f8daa55dcbaf94204ff3db38..ac740b26eb1071950a26ce64ddca68f8212e8742 100644 (file)
@@ -205,7 +205,7 @@ struct kvm {
 
        struct mutex irq_lock;
 #ifdef CONFIG_HAVE_KVM_IRQCHIP
-       struct kvm_irq_routing_table *irq_routing;
+       struct kvm_irq_routing_table __rcu *irq_routing;
        struct hlist_head mask_notifier_list;
        struct hlist_head irq_ack_notifier_list;
 #endif
index 45fb2967b66d6949094289a467ae120d12014c0d..15b77b8dc7e11f529b93cc9ba629f464627d3a74 100644 (file)
@@ -37,6 +37,7 @@
 #include <scsi/scsi_host.h>
 #include <linux/acpi.h>
 #include <linux/cdrom.h>
+#include <linux/sched.h>
 
 /*
  * Define if arch has non-standard setup.  This is a _PCI_ standard
@@ -172,6 +173,7 @@ enum {
        ATA_LFLAG_NO_RETRY      = (1 << 5), /* don't retry this link */
        ATA_LFLAG_DISABLED      = (1 << 6), /* link is disabled */
        ATA_LFLAG_SW_ACTIVITY   = (1 << 7), /* keep activity stats */
+       ATA_LFLAG_NO_LPM        = (1 << 8), /* disable LPM on this link */
 
        /* struct ata_port flags */
        ATA_FLAG_SLAVE_POSS     = (1 << 0), /* host supports slave dev */
@@ -196,7 +198,7 @@ enum {
        ATA_FLAG_ACPI_SATA      = (1 << 17), /* need native SATA ACPI layout */
        ATA_FLAG_AN             = (1 << 18), /* controller supports AN */
        ATA_FLAG_PMP            = (1 << 19), /* controller supports PMP */
-       ATA_FLAG_IPM            = (1 << 20), /* driver can handle IPM */
+       ATA_FLAG_LPM            = (1 << 20), /* driver can handle LPM */
        ATA_FLAG_EM             = (1 << 21), /* driver supports enclosure
                                              * management */
        ATA_FLAG_SW_ACTIVITY    = (1 << 22), /* driver supports sw activity
@@ -324,12 +326,11 @@ enum {
        ATA_EH_HARDRESET        = (1 << 2), /* meaningful only in ->prereset */
        ATA_EH_RESET            = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
        ATA_EH_ENABLE_LINK      = (1 << 3),
-       ATA_EH_LPM              = (1 << 4),  /* link power management action */
        ATA_EH_PARK             = (1 << 5), /* unload heads and stop I/O */
 
        ATA_EH_PERDEV_MASK      = ATA_EH_REVALIDATE | ATA_EH_PARK,
        ATA_EH_ALL_ACTIONS      = ATA_EH_REVALIDATE | ATA_EH_RESET |
-                                 ATA_EH_ENABLE_LINK | ATA_EH_LPM,
+                                 ATA_EH_ENABLE_LINK,
 
        /* ata_eh_info->flags */
        ATA_EHI_HOTPLUGGED      = (1 << 0),  /* could have been hotplugged */
@@ -341,7 +342,7 @@ enum {
        ATA_EHI_DID_HARDRESET   = (1 << 17), /* already soft-reset this port */
        ATA_EHI_PRINTINFO       = (1 << 18), /* print configuration info */
        ATA_EHI_SETMODE         = (1 << 19), /* configure transfer mode */
-       ATA_EHI_POST_SETMODE    = (1 << 20), /* revaildating after setmode */
+       ATA_EHI_POST_SETMODE    = (1 << 20), /* revalidating after setmode */
 
        ATA_EHI_DID_RESET       = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET,
 
@@ -377,7 +378,6 @@ enum {
        ATA_HORKAGE_BROKEN_HPA  = (1 << 4),     /* Broken HPA */
        ATA_HORKAGE_DISABLE     = (1 << 5),     /* Disable it */
        ATA_HORKAGE_HPA_SIZE    = (1 << 6),     /* native size off by one */
-       ATA_HORKAGE_IPM         = (1 << 7),     /* Link PM problems */
        ATA_HORKAGE_IVB         = (1 << 8),     /* cbl det validity bit bugs */
        ATA_HORKAGE_STUCK_ERR   = (1 << 9),     /* stuck ERR on next PACKET */
        ATA_HORKAGE_BRIDGE_OK   = (1 << 10),    /* no bridge limits */
@@ -464,6 +464,22 @@ enum ata_completion_errors {
        AC_ERR_NCQ              = (1 << 10), /* marker for offending NCQ qc */
 };
 
+/*
+ * Link power management policy: If you alter this, you also need to
+ * alter libata-scsi.c (for the ascii descriptions)
+ */
+enum ata_lpm_policy {
+       ATA_LPM_UNKNOWN,
+       ATA_LPM_MAX_POWER,
+       ATA_LPM_MED_POWER,
+       ATA_LPM_MIN_POWER,
+};
+
+enum ata_lpm_hints {
+       ATA_LPM_EMPTY           = (1 << 0), /* port empty/probing */
+       ATA_LPM_HIPM            = (1 << 1), /* may use HIPM */
+};
+
 /* forward declarations */
 struct scsi_device;
 struct ata_port_operations;
@@ -478,16 +494,6 @@ typedef int (*ata_reset_fn_t)(struct ata_link *link, unsigned int *classes,
                              unsigned long deadline);
 typedef void (*ata_postreset_fn_t)(struct ata_link *link, unsigned int *classes);
 
-/*
- * host pm policy: If you alter this, you also need to alter libata-scsi.c
- * (for the ascii descriptions)
- */
-enum link_pm {
-       NOT_AVAILABLE,
-       MIN_POWER,
-       MAX_PERFORMANCE,
-       MEDIUM_POWER,
-};
 extern struct device_attribute dev_attr_link_power_management_policy;
 extern struct device_attribute dev_attr_unload_heads;
 extern struct device_attribute dev_attr_em_message_type;
@@ -530,6 +536,10 @@ struct ata_host {
        void                    *private_data;
        struct ata_port_operations *ops;
        unsigned long           flags;
+
+       struct mutex            eh_mutex;
+       struct task_struct      *eh_owner;
+
 #ifdef CONFIG_ATA_ACPI
        acpi_handle             acpi_handle;
 #endif
@@ -560,13 +570,13 @@ struct ata_queued_cmd {
        unsigned int            extrabytes;
        unsigned int            curbytes;
 
-       struct scatterlist      *cursg;
-       unsigned int            cursg_ofs;
-
        struct scatterlist      sgent;
 
        struct scatterlist      *sg;
 
+       struct scatterlist      *cursg;
+       unsigned int            cursg_ofs;
+
        unsigned int            err_mask;
        struct ata_taskfile     result_tf;
        ata_qc_cb_t             complete_fn;
@@ -604,6 +614,7 @@ struct ata_device {
        union acpi_object       *gtf_cache;
        unsigned int            gtf_filter;
 #endif
+       struct device           tdev;
        /* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */
        u64                     n_sectors;      /* size of device, if ATA */
        u64                     n_native_sectors; /* native size, if ATA */
@@ -690,6 +701,7 @@ struct ata_link {
        struct ata_port         *ap;
        int                     pmp;            /* port multiplier port # */
 
+       struct device           tdev;
        unsigned int            active_tag;     /* active tag on this link */
        u32                     sactive;        /* active NCQ commands */
 
@@ -699,6 +711,7 @@ struct ata_link {
        unsigned int            hw_sata_spd_limit;
        unsigned int            sata_spd_limit;
        unsigned int            sata_spd;       /* current SATA PHY speed */
+       enum ata_lpm_policy     lpm_policy;
 
        /* record runtime error info, protected by host_set lock */
        struct ata_eh_info      eh_info;
@@ -707,6 +720,8 @@ struct ata_link {
 
        struct ata_device       device[ATA_MAX_DEVICES];
 };
+#define ATA_LINK_CLEAR_BEGIN           offsetof(struct ata_link, active_tag)
+#define ATA_LINK_CLEAR_END             offsetof(struct ata_link, device[0])
 
 struct ata_port {
        struct Scsi_Host        *scsi_host; /* our co-allocated scsi host */
@@ -752,6 +767,7 @@ struct ata_port {
        struct ata_port_stats   stats;
        struct ata_host         *host;
        struct device           *dev;
+       struct device           tdev;
 
        struct mutex            scsi_scan_mutex;
        struct delayed_work     hotplug_task;
@@ -767,7 +783,7 @@ struct ata_port {
 
        pm_message_t            pm_mesg;
        int                     *pm_result;
-       enum link_pm            pm_policy;
+       enum ata_lpm_policy     target_lpm_policy;
 
        struct timer_list       fastdrain_timer;
        unsigned long           fastdrain_cnt;
@@ -833,8 +849,8 @@ struct ata_port_operations {
        int  (*scr_write)(struct ata_link *link, unsigned int sc_reg, u32 val);
        void (*pmp_attach)(struct ata_port *ap);
        void (*pmp_detach)(struct ata_port *ap);
-       int  (*enable_pm)(struct ata_port *ap, enum link_pm policy);
-       void (*disable_pm)(struct ata_port *ap);
+       int  (*set_lpm)(struct ata_link *link, enum ata_lpm_policy policy,
+                       unsigned hints);
 
        /*
         * Start, stop, suspend and resume
@@ -946,6 +962,8 @@ extern int sata_link_debounce(struct ata_link *link,
                        const unsigned long *params, unsigned long deadline);
 extern int sata_link_resume(struct ata_link *link, const unsigned long *params,
                            unsigned long deadline);
+extern int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
+                            bool spm_wakeup);
 extern int sata_link_hardreset(struct ata_link *link,
                        const unsigned long *timing, unsigned long deadline,
                        bool *online, int (*check_ready)(struct ata_link *));
@@ -991,8 +1009,9 @@ extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
 extern void ata_host_resume(struct ata_host *host);
 #endif
 extern int ata_ratelimit(void);
-extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
-                            unsigned long interval, unsigned long timeout);
+extern void ata_msleep(struct ata_port *ap, unsigned int msecs);
+extern u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask,
+                       u32 val, unsigned long interval, unsigned long timeout);
 extern int atapi_cmd_type(u8 opcode);
 extern void ata_tf_to_fis(const struct ata_taskfile *tf,
                          u8 pmp, int is_cmd, u8 *fis);
index d167b5d7c0ac0844d9b42fab6a16d486793878c5..88a000617d775fb74333a5f54aceac8460cb5008 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/stddef.h>
 #include <linux/poison.h>
 #include <linux/prefetch.h>
-#include <asm/system.h>
 
 /*
  * Simple doubly linked list implementation.
index 06aed8305bf3bc38061dc42c168c3b9d83f29492..71c09b26c7592ff4a1f6351fd226c9442ef66e5d 100644 (file)
@@ -31,6 +31,17 @@ extern int lock_stat;
 
 #define MAX_LOCKDEP_SUBCLASSES         8UL
 
+/*
+ * NR_LOCKDEP_CACHING_CLASSES ... Number of classes
+ * cached in the instance of lockdep_map
+ *
+ * Currently main class (subclass == 0) and signle depth subclass
+ * are cached in lockdep_map. This optimization is mainly targeting
+ * on rq->lock. double_rq_lock() acquires this highly competitive with
+ * single depth.
+ */
+#define NR_LOCKDEP_CACHING_CLASSES     2
+
 /*
  * Lock-classes are keyed via unique addresses, by embedding the
  * lockclass-key into the kernel (or module) .data section. (For
@@ -138,7 +149,7 @@ void clear_lock_stats(struct lock_class *class);
  */
 struct lockdep_map {
        struct lock_class_key           *key;
-       struct lock_class               *class_cache;
+       struct lock_class               *class_cache[NR_LOCKDEP_CACHING_CLASSES];
        const char                      *name;
 #ifdef CONFIG_LOCK_STAT
        int                             cpu;
@@ -424,14 +435,6 @@ do {                                                               \
 
 #endif /* CONFIG_LOCKDEP */
 
-#ifdef CONFIG_GENERIC_HARDIRQS
-extern void early_init_irq_lock_class(void);
-#else
-static inline void early_init_irq_lock_class(void)
-{
-}
-#endif
-
 #ifdef CONFIG_TRACE_IRQFLAGS
 extern void early_boot_irqs_off(void);
 extern void early_boot_irqs_on(void);
index a59faf2b5edd15faa6b408de6cc75fcfb069d840..62a10c2a11f2dc6a68f5bf4b1e30bbb23149ce6a 100644 (file)
@@ -2,6 +2,7 @@
 #define _LINUX_MEMBLOCK_H
 #ifdef __KERNEL__
 
+#ifdef CONFIG_HAVE_MEMBLOCK
 /*
  * Logical memory blocks.
  *
 #include <linux/init.h>
 #include <linux/mm.h>
 
-#define MAX_MEMBLOCK_REGIONS 128
+#include <asm/memblock.h>
 
-struct memblock_property {
-       u64 base;
-       u64 size;
-};
+#define INIT_MEMBLOCK_REGIONS  128
+#define MEMBLOCK_ERROR         0
 
 struct memblock_region {
-       unsigned long cnt;
-       u64 size;
-       struct memblock_property region[MAX_MEMBLOCK_REGIONS+1];
+       phys_addr_t base;
+       phys_addr_t size;
+};
+
+struct memblock_type {
+       unsigned long cnt;      /* number of regions */
+       unsigned long max;      /* size of the allocated array */
+       struct memblock_region *regions;
 };
 
 struct memblock {
-       unsigned long debug;
-       u64 rmo_size;
-       struct memblock_region memory;
-       struct memblock_region reserved;
+       phys_addr_t current_limit;
+       phys_addr_t memory_size;        /* Updated by memblock_analyze() */
+       struct memblock_type memory;
+       struct memblock_type reserved;
 };
 
 extern struct memblock memblock;
+extern int memblock_debug;
+extern int memblock_can_resize;
 
-extern void __init memblock_init(void);
-extern void __init memblock_analyze(void);
-extern long memblock_add(u64 base, u64 size);
-extern long memblock_remove(u64 base, u64 size);
-extern long __init memblock_free(u64 base, u64 size);
-extern long __init memblock_reserve(u64 base, u64 size);
-extern u64 __init memblock_alloc_nid(u64 size, u64 align, int nid,
-                               u64 (*nid_range)(u64, u64, int *));
-extern u64 __init memblock_alloc(u64 size, u64 align);
-extern u64 __init memblock_alloc_base(u64 size,
-               u64, u64 max_addr);
-extern u64 __init __memblock_alloc_base(u64 size,
-               u64 align, u64 max_addr);
-extern u64 __init memblock_phys_mem_size(void);
-extern u64 memblock_end_of_DRAM(void);
-extern void __init memblock_enforce_memory_limit(u64 memory_limit);
-extern int __init memblock_is_reserved(u64 addr);
-extern int memblock_is_region_reserved(u64 base, u64 size);
-extern int memblock_find(struct memblock_property *res);
+#define memblock_dbg(fmt, ...) \
+       if (memblock_debug) printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
+
+u64 memblock_find_in_range(u64 start, u64 end, u64 size, u64 align);
+int memblock_free_reserved_regions(void);
+int memblock_reserve_reserved_regions(void);
+
+extern void memblock_init(void);
+extern void memblock_analyze(void);
+extern long memblock_add(phys_addr_t base, phys_addr_t size);
+extern long memblock_remove(phys_addr_t base, phys_addr_t size);
+extern long memblock_free(phys_addr_t base, phys_addr_t size);
+extern long memblock_reserve(phys_addr_t base, phys_addr_t size);
+
+/* The numa aware allocator is only available if
+ * CONFIG_ARCH_POPULATES_NODE_MAP is set
+ */
+extern phys_addr_t memblock_alloc_nid(phys_addr_t size, phys_addr_t align,
+                                       int nid);
+extern phys_addr_t memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align,
+                                           int nid);
+
+extern phys_addr_t memblock_alloc(phys_addr_t size, phys_addr_t align);
+
+/* Flags for memblock_alloc_base() amd __memblock_alloc_base() */
+#define MEMBLOCK_ALLOC_ANYWHERE        (~(phys_addr_t)0)
+#define MEMBLOCK_ALLOC_ACCESSIBLE      0
+
+extern phys_addr_t memblock_alloc_base(phys_addr_t size,
+                                        phys_addr_t align,
+                                        phys_addr_t max_addr);
+extern phys_addr_t __memblock_alloc_base(phys_addr_t size,
+                                          phys_addr_t align,
+                                          phys_addr_t max_addr);
+extern phys_addr_t memblock_phys_mem_size(void);
+extern phys_addr_t memblock_end_of_DRAM(void);
+extern void memblock_enforce_memory_limit(phys_addr_t memory_limit);
+extern int memblock_is_memory(phys_addr_t addr);
+extern int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
+extern int memblock_is_reserved(phys_addr_t addr);
+extern int memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
 
 extern void memblock_dump_all(void);
 
-static inline u64
-memblock_size_bytes(struct memblock_region *type, unsigned long region_nr)
+/* Provided by the architecture */
+extern phys_addr_t memblock_nid_range(phys_addr_t start, phys_addr_t end, int *nid);
+extern int memblock_memory_can_coalesce(phys_addr_t addr1, phys_addr_t size1,
+                                  phys_addr_t addr2, phys_addr_t size2);
+
+/**
+ * memblock_set_current_limit - Set the current allocation limit to allow
+ *                         limiting allocations to what is currently
+ *                         accessible during boot
+ * @limit: New limit value (physical address)
+ */
+extern void memblock_set_current_limit(phys_addr_t limit);
+
+
+/*
+ * pfn conversion functions
+ *
+ * While the memory MEMBLOCKs should always be page aligned, the reserved
+ * MEMBLOCKs may not be. This accessor attempt to provide a very clear
+ * idea of what they return for such non aligned MEMBLOCKs.
+ */
+
+/**
+ * memblock_region_memory_base_pfn - Return the lowest pfn intersecting with the memory region
+ * @reg: memblock_region structure
+ */
+static inline unsigned long memblock_region_memory_base_pfn(const struct memblock_region *reg)
 {
-       return type->region[region_nr].size;
+       return PFN_UP(reg->base);
 }
-static inline u64
-memblock_size_pages(struct memblock_region *type, unsigned long region_nr)
+
+/**
+ * memblock_region_memory_end_pfn - Return the end_pfn this region
+ * @reg: memblock_region structure
+ */
+static inline unsigned long memblock_region_memory_end_pfn(const struct memblock_region *reg)
 {
-       return memblock_size_bytes(type, region_nr) >> PAGE_SHIFT;
+       return PFN_DOWN(reg->base + reg->size);
 }
-static inline u64
-memblock_start_pfn(struct memblock_region *type, unsigned long region_nr)
+
+/**
+ * memblock_region_reserved_base_pfn - Return the lowest pfn intersecting with the reserved region
+ * @reg: memblock_region structure
+ */
+static inline unsigned long memblock_region_reserved_base_pfn(const struct memblock_region *reg)
 {
-       return type->region[region_nr].base >> PAGE_SHIFT;
+       return PFN_DOWN(reg->base);
 }
-static inline u64
-memblock_end_pfn(struct memblock_region *type, unsigned long region_nr)
+
+/**
+ * memblock_region_reserved_end_pfn - Return the end_pfn this region
+ * @reg: memblock_region structure
+ */
+static inline unsigned long memblock_region_reserved_end_pfn(const struct memblock_region *reg)
 {
-       return memblock_start_pfn(type, region_nr) +
-              memblock_size_pages(type, region_nr);
+       return PFN_UP(reg->base + reg->size);
 }
 
-#include <asm/memblock.h>
+#define for_each_memblock(memblock_type, region)                                       \
+       for (region = memblock.memblock_type.regions;                           \
+            region < (memblock.memblock_type.regions + memblock.memblock_type.cnt);    \
+            region++)
+
+
+#ifdef ARCH_DISCARD_MEMBLOCK
+#define __init_memblock __init
+#define __initdata_memblock __initdata
+#else
+#define __init_memblock
+#define __initdata_memblock
+#endif
+
+#endif /* CONFIG_HAVE_MEMBLOCK */
 
 #endif /* __KERNEL__ */
 
index e47f770d30684df3f164f2689debe335923b062a..eff3094ca84e0d1c1eaf8b183303c33d6d5cdf76 100644 (file)
@@ -111,9 +111,13 @@ extern int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val);
  * struct tc35892_gpio_platform_data - TC35892 GPIO platform data
  * @gpio_base: first gpio number assigned to TC35892.  A maximum of
  *            %TC35892_NR_GPIOS GPIOs will be allocated.
+ * @setup: callback for board-specific initialization
+ * @remove: callback for board-specific teardown
  */
 struct tc35892_gpio_platform_data {
        int gpio_base;
+       void (*setup)(struct tc35892 *tc35892, unsigned gpio_base);
+       void (*remove)(struct tc35892 *tc35892, unsigned gpio_base);
 };
 
 /**
index 74949fbef8c608b9c5ef6dab3b508041a11243f3..7687228dd3b7d16530cf28087ea71f07155ee3ba 100644 (file)
@@ -1175,6 +1175,8 @@ extern void free_bootmem_with_active_regions(int nid,
                                                unsigned long max_low_pfn);
 int add_from_early_node_map(struct range *range, int az,
                                   int nr_range, int nid);
+u64 __init find_memory_core_early(int nid, u64 size, u64 align,
+                                       u64 goal, u64 limit);
 void *__alloc_memory_core_early(int nodeid, u64 size, u64 align,
                                 u64 goal, u64 limit);
 typedef int (*work_fn_t)(unsigned long, unsigned long, void *);
index ee7e258627f9f5b9999e4c3033f7fa78c5927b48..cb57d657ce4d2643c58e21eb23b2b1434f0f7a2f 100644 (file)
@@ -299,7 +299,7 @@ struct mm_struct {
         * new_owner->mm == mm
         * new_owner->alloc_lock is held
         */
-       struct task_struct *owner;
+       struct task_struct __rcu *owner;
 #endif
 
 #ifdef CONFIG_PROC_FS
index aace066bad8f067758cda4d341b9ce8941d2ae1c..b29e7458b96642b2f36162aa755b10ff76b15abe 100644 (file)
@@ -350,7 +350,10 @@ struct module
        struct tracepoint *tracepoints;
        unsigned int num_tracepoints;
 #endif
-
+#ifdef HAVE_JUMP_LABEL
+       struct jump_entry *jump_entries;
+       unsigned int num_jump_entries;
+#endif
 #ifdef CONFIG_TRACING
        const char **trace_bprintk_fmt_start;
        unsigned int num_trace_bprintk_fmt;
index 91b05c171854f12488e92c8fe2d23812bb1f03e5..05acced439a38ec1faf822200740d032778e9022 100644 (file)
@@ -10,12 +10,13 @@ struct msi_msg {
 };
 
 /* Helper functions */
-struct irq_desc;
-extern void mask_msi_irq(unsigned int irq);
-extern void unmask_msi_irq(unsigned int irq);
-extern void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
-extern void get_cached_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
-extern void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
+struct irq_data;
+struct msi_desc;
+extern void mask_msi_irq(struct irq_data *data);
+extern void unmask_msi_irq(struct irq_data *data);
+extern void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+extern void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+extern void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
 extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
 extern void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
 extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
index 9ed534c991b9312d84876c9162ed63e5ef2b5c66..70cd0603911c97b865bc576a3f4490f523e2fc08 100644 (file)
@@ -39,8 +39,9 @@ enum ctattr_type {
        CTA_TUPLE_MASTER,
        CTA_NAT_SEQ_ADJ_ORIG,
        CTA_NAT_SEQ_ADJ_REPLY,
-       CTA_SECMARK,
+       CTA_SECMARK,            /* obsolete */
        CTA_ZONE,
+       CTA_SECCTX,
        __CTA_MAX
 };
 #define CTA_MAX (__CTA_MAX - 1)
@@ -172,4 +173,11 @@ enum ctattr_help {
 };
 #define CTA_HELP_MAX (__CTA_HELP_MAX - 1)
 
+enum ctattr_secctx {
+       CTA_SECCTX_UNSPEC,
+       CTA_SECCTX_NAME,
+       __CTA_SECCTX_MAX
+};
+#define CTA_SECCTX_MAX (__CTA_SECCTX_MAX - 1)
+
 #endif /* _IPCONNTRACK_NETLINK_H */
index 6fcd3448b18631f04e081cde470f85218dd7f9b8..989092bd6274b44585ccc0faf4f005a0d7b909b7 100644 (file)
  * packets are being marked for.
  */
 #define SECMARK_MODE_SEL       0x01            /* SELinux */
-#define SECMARK_SELCTX_MAX     256
-
-struct xt_secmark_target_selinux_info {
-       __u32 selsid;
-       char selctx[SECMARK_SELCTX_MAX];
-};
+#define SECMARK_SECCTX_MAX     256
 
 struct xt_secmark_target_info {
        __u8 mode;
-       union {
-               struct xt_secmark_target_selinux_info sel;
-       } u;
+       __u32 secid;
+       char secctx[SECMARK_SECCTX_MAX];
 };
 
 #endif /*_XT_SECMARK_H_target */
index 508f8cf6da379bc7179b5c8f22d534a63a539ad0..d0edf7d823ae3ef60ec2ba6c6daa3ff0b34643cd 100644 (file)
@@ -185,7 +185,7 @@ struct nfs_inode {
        struct nfs4_cached_acl  *nfs4_acl;
         /* NFSv4 state */
        struct list_head        open_states;
-       struct nfs_delegation   *delegation;
+       struct nfs_delegation __rcu *delegation;
        fmode_t                  delegation_state;
        struct rw_semaphore     rwsem;
 #endif /* CONFIG_NFS_V4*/
index b2f1a4d835506b7d0d8fdce8831d608fa28759bd..2026f9e1ceb8e5cb5d6a9f3a2a1b4c4ff02d5953 100644 (file)
 
 struct notifier_block {
        int (*notifier_call)(struct notifier_block *, unsigned long, void *);
-       struct notifier_block *next;
+       struct notifier_block __rcu *next;
        int priority;
 };
 
 struct atomic_notifier_head {
        spinlock_t lock;
-       struct notifier_block *head;
+       struct notifier_block __rcu *head;
 };
 
 struct blocking_notifier_head {
        struct rw_semaphore rwsem;
-       struct notifier_block *head;
+       struct notifier_block __rcu *head;
 };
 
 struct raw_notifier_head {
-       struct notifier_block *head;
+       struct notifier_block __rcu *head;
 };
 
 struct srcu_notifier_head {
        struct mutex mutex;
        struct srcu_struct srcu;
-       struct notifier_block *head;
+       struct notifier_block __rcu *head;
 };
 
 #define ATOMIC_INIT_NOTIFIER_HEAD(name) do {   \
diff --git a/include/linux/opp.h b/include/linux/opp.h
new file mode 100644 (file)
index 0000000..5449945
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Generic OPP Interface
+ *
+ * Copyright (C) 2009-2010 Texas Instruments Incorporated.
+ *     Nishanth Menon
+ *     Romit Dasgupta
+ *     Kevin Hilman
+ *
+ * This program is free software; you can 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_OPP_H__
+#define __LINUX_OPP_H__
+
+#include <linux/err.h>
+#include <linux/cpufreq.h>
+
+struct opp;
+
+#if defined(CONFIG_PM_OPP)
+
+unsigned long opp_get_voltage(struct opp *opp);
+
+unsigned long opp_get_freq(struct opp *opp);
+
+int opp_get_opp_count(struct device *dev);
+
+struct opp *opp_find_freq_exact(struct device *dev, unsigned long freq,
+                               bool available);
+
+struct opp *opp_find_freq_floor(struct device *dev, unsigned long *freq);
+
+struct opp *opp_find_freq_ceil(struct device *dev, unsigned long *freq);
+
+int opp_add(struct device *dev, unsigned long freq, unsigned long u_volt);
+
+int opp_enable(struct device *dev, unsigned long freq);
+
+int opp_disable(struct device *dev, unsigned long freq);
+
+#else
+static inline unsigned long opp_get_voltage(struct opp *opp)
+{
+       return 0;
+}
+
+static inline unsigned long opp_get_freq(struct opp *opp)
+{
+       return 0;
+}
+
+static inline int opp_get_opp_count(struct device *dev)
+{
+       return 0;
+}
+
+static inline struct opp *opp_find_freq_exact(struct device *dev,
+                                       unsigned long freq, bool available)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+static inline struct opp *opp_find_freq_floor(struct device *dev,
+                                       unsigned long *freq)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+static inline struct opp *opp_find_freq_ceil(struct device *dev,
+                                       unsigned long *freq)
+{
+       return ERR_PTR(-EINVAL);
+}
+
+static inline int opp_add(struct device *dev, unsigned long freq,
+                                       unsigned long u_volt)
+{
+       return -EINVAL;
+}
+
+static inline int opp_enable(struct device *dev, unsigned long freq)
+{
+       return 0;
+}
+
+static inline int opp_disable(struct device *dev, unsigned long freq)
+{
+       return 0;
+}
+#endif         /* CONFIG_PM */
+
+#if defined(CONFIG_CPU_FREQ) && defined(CONFIG_PM_OPP)
+int opp_init_cpufreq_table(struct device *dev,
+                           struct cpufreq_frequency_table **table);
+#else
+static inline int opp_init_cpufreq_table(struct device *dev,
+                           struct cpufreq_frequency_table **table)
+{
+       return -EINVAL;
+}
+#endif         /* CONFIG_CPU_FREQ */
+
+#endif         /* __LINUX_OPP_H__ */
index 5171639ecf0ff070e74d884deb8c969e3b88132d..32fb81212fd153c0a71ba347ead6429d0a8dcd06 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/types.h>
 #include <linux/spinlock.h>
+#include <linux/init.h>
 #include <asm/atomic.h>
  
 /* Each escaped entry is prefixed by ESCAPE_CODE
@@ -185,4 +186,10 @@ int oprofile_add_data(struct op_entry *entry, unsigned long val);
 int oprofile_add_data64(struct op_entry *entry, u64 val);
 int oprofile_write_commit(struct op_entry *entry);
 
+#ifdef CONFIG_PERF_EVENTS
+int __init oprofile_perf_init(struct oprofile_operations *ops);
+void oprofile_perf_exit(void);
+char *op_name_from_perf_id(void);
+#endif /* CONFIG_PERF_EVENTS */
+
 #endif /* OPROFILE_H */
index 570fddeb0388f62b7b8dd0a32ec5136123856033..dad30734432ac3a0a0ee4523d443c9e29880bc4c 100644 (file)
 #define PCI_DEVICE_ID_AMD_11H_NB_DRAM  0x1302
 #define PCI_DEVICE_ID_AMD_11H_NB_MISC  0x1303
 #define PCI_DEVICE_ID_AMD_11H_NB_LINK  0x1304
+#define PCI_DEVICE_ID_AMD_15H_NB_MISC  0x1603
 #define PCI_DEVICE_ID_AMD_LANCE                0x2000
 #define PCI_DEVICE_ID_AMD_LANCE_HOME   0x2001
 #define PCI_DEVICE_ID_AMD_SCSI         0x2020
 #define PCI_DEVICE_ID_P4080            0x0401
 #define PCI_DEVICE_ID_P4040E           0x0408
 #define PCI_DEVICE_ID_P4040            0x0409
+#define PCI_DEVICE_ID_P2040E           0x0410
+#define PCI_DEVICE_ID_P2040            0x0411
+#define PCI_DEVICE_ID_P3041E           0x041E
+#define PCI_DEVICE_ID_P3041            0x041F
+#define PCI_DEVICE_ID_P5020E           0x0420
+#define PCI_DEVICE_ID_P5020            0x0421
+#define PCI_DEVICE_ID_P5010E           0x0428
+#define PCI_DEVICE_ID_P5010            0x0429
 #define PCI_DEVICE_ID_MPC8641          0x7010
 #define PCI_DEVICE_ID_MPC8641D         0x7011
 #define PCI_DEVICE_ID_MPC8610          0x7018
index ce2dc655cd1d40a6765acc2dd3f49e104bca4f5c..27ef6b190ea6cc5ee84c53dbcd9a38f5c09164d6 100644 (file)
        DEFINE_PER_CPU_SECTION(type, name, "..page_aligned")            \
        __aligned(PAGE_SIZE)
 
+/*
+ * Declaration/definition used for per-CPU variables that must be read mostly.
+ */
+#define DECLARE_PER_CPU_READ_MOSTLY(type, name)                        \
+       DECLARE_PER_CPU_SECTION(type, name, "..readmostly")
+
+#define DEFINE_PER_CPU_READ_MOSTLY(type, name)                         \
+       DEFINE_PER_CPU_SECTION(type, name, "..readmostly")
+
 /*
  * Intermodule exports for per-CPU variables.  sparse forgets about
  * address space across EXPORT_SYMBOL(), change EXPORT_SYMBOL() to
index 49466b13c5c6b310f36b31c052573864df6f02a0..0eb50832aa00fd1bbc31cc23837abfc698412402 100644 (file)
        preempt_enable();                               \
 } while (0)
 
+#define get_cpu_ptr(var) ({                            \
+       preempt_disable();                              \
+       this_cpu_ptr(var); })
+
+#define put_cpu_ptr(var) do {                          \
+       (void)(var);                                    \
+       preempt_enable();                               \
+} while (0)
+
 #ifdef CONFIG_SMP
 
 /* minimum unit size, also is the maximum supported allocation size */
index 716f99b682c1a57fb3b6f1f72e90aec3982ca5fd..057bf22a8323463a6bd9279d6928d3fea7ed8eb8 100644 (file)
@@ -486,6 +486,8 @@ struct perf_guest_info_callbacks {
 #include <linux/workqueue.h>
 #include <linux/ftrace.h>
 #include <linux/cpu.h>
+#include <linux/irq_work.h>
+#include <linux/jump_label_ref.h>
 #include <asm/atomic.h>
 #include <asm/local.h>
 
@@ -529,16 +531,22 @@ struct hw_perf_event {
                        int             last_cpu;
                };
                struct { /* software */
-                       s64             remaining;
                        struct hrtimer  hrtimer;
                };
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
                struct { /* breakpoint */
                        struct arch_hw_breakpoint       info;
                        struct list_head                bp_list;
+                       /*
+                        * Crufty hack to avoid the chicken and egg
+                        * problem hw_breakpoint has with context
+                        * creation and event initalization.
+                        */
+                       struct task_struct              *bp_target;
                };
 #endif
        };
+       int                             state;
        local64_t                       prev_count;
        u64                             sample_period;
        u64                             last_period;
@@ -550,6 +558,13 @@ struct hw_perf_event {
 #endif
 };
 
+/*
+ * hw_perf_event::state flags
+ */
+#define PERF_HES_STOPPED       0x01 /* the counter is stopped */
+#define PERF_HES_UPTODATE      0x02 /* event->count up-to-date */
+#define PERF_HES_ARCH          0x04
+
 struct perf_event;
 
 /*
@@ -561,36 +576,70 @@ struct perf_event;
  * struct pmu - generic performance monitoring unit
  */
 struct pmu {
-       int (*enable)                   (struct perf_event *event);
-       void (*disable)                 (struct perf_event *event);
-       int (*start)                    (struct perf_event *event);
-       void (*stop)                    (struct perf_event *event);
-       void (*read)                    (struct perf_event *event);
-       void (*unthrottle)              (struct perf_event *event);
+       struct list_head                entry;
+
+       int * __percpu                  pmu_disable_count;
+       struct perf_cpu_context * __percpu pmu_cpu_context;
+       int                             task_ctx_nr;
+
+       /*
+        * Fully disable/enable this PMU, can be used to protect from the PMI
+        * as well as for lazy/batch writing of the MSRs.
+        */
+       void (*pmu_enable)              (struct pmu *pmu); /* optional */
+       void (*pmu_disable)             (struct pmu *pmu); /* optional */
 
        /*
-        * Group events scheduling is treated as a transaction, add group
-        * events as a whole and perform one schedulability test. If the test
-        * fails, roll back the whole group
+        * Try and initialize the event for this PMU.
+        * Should return -ENOENT when the @event doesn't match this PMU.
         */
+       int (*event_init)               (struct perf_event *event);
+
+#define PERF_EF_START  0x01            /* start the counter when adding    */
+#define PERF_EF_RELOAD 0x02            /* reload the counter when starting */
+#define PERF_EF_UPDATE 0x04            /* update the counter when stopping */
 
        /*
-        * Start the transaction, after this ->enable() doesn't need
-        * to do schedulability tests.
+        * Adds/Removes a counter to/from the PMU, can be done inside
+        * a transaction, see the ->*_txn() methods.
         */
-       void (*start_txn)       (const struct pmu *pmu);
+       int  (*add)                     (struct perf_event *event, int flags);
+       void (*del)                     (struct perf_event *event, int flags);
+
        /*
-        * If ->start_txn() disabled the ->enable() schedulability test
+        * Starts/Stops a counter present on the PMU. The PMI handler
+        * should stop the counter when perf_event_overflow() returns
+        * !0. ->start() will be used to continue.
+        */
+       void (*start)                   (struct perf_event *event, int flags);
+       void (*stop)                    (struct perf_event *event, int flags);
+
+       /*
+        * Updates the counter value of the event.
+        */
+       void (*read)                    (struct perf_event *event);
+
+       /*
+        * Group events scheduling is treated as a transaction, add
+        * group events as a whole and perform one schedulability test.
+        * If the test fails, roll back the whole group
+        *
+        * Start the transaction, after this ->add() doesn't need to
+        * do schedulability tests.
+        */
+       void (*start_txn)       (struct pmu *pmu); /* optional */
+       /*
+        * If ->start_txn() disabled the ->add() schedulability test
         * then ->commit_txn() is required to perform one. On success
         * the transaction is closed. On error the transaction is kept
         * open until ->cancel_txn() is called.
         */
-       int  (*commit_txn)      (const struct pmu *pmu);
+       int  (*commit_txn)      (struct pmu *pmu); /* optional */
        /*
-        * Will cancel the transaction, assumes ->disable() is called for
-        * each successfull ->enable() during the transaction.
+        * Will cancel the transaction, assumes ->del() is called
+        * for each successfull ->add() during the transaction.
         */
-       void (*cancel_txn)      (const struct pmu *pmu);
+       void (*cancel_txn)      (struct pmu *pmu); /* optional */
 };
 
 /**
@@ -631,11 +680,6 @@ struct perf_buffer {
        void                            *data_pages[0];
 };
 
-struct perf_pending_entry {
-       struct perf_pending_entry *next;
-       void (*func)(struct perf_pending_entry *);
-};
-
 struct perf_sample_data;
 
 typedef void (*perf_overflow_handler_t)(struct perf_event *, int,
@@ -656,6 +700,7 @@ struct swevent_hlist {
 
 #define PERF_ATTACH_CONTEXT    0x01
 #define PERF_ATTACH_GROUP      0x02
+#define PERF_ATTACH_TASK       0x04
 
 /**
  * struct perf_event - performance event kernel representation:
@@ -669,7 +714,7 @@ struct perf_event {
        int                             nr_siblings;
        int                             group_flags;
        struct perf_event               *group_leader;
-       const struct pmu                *pmu;
+       struct pmu                      *pmu;
 
        enum perf_event_active_state    state;
        unsigned int                    attach_state;
@@ -743,7 +788,7 @@ struct perf_event {
        int                             pending_wakeup;
        int                             pending_kill;
        int                             pending_disable;
-       struct perf_pending_entry       pending;
+       struct irq_work                 pending;
 
        atomic_t                        event_limit;
 
@@ -763,12 +808,19 @@ struct perf_event {
 #endif /* CONFIG_PERF_EVENTS */
 };
 
+enum perf_event_context_type {
+       task_context,
+       cpu_context,
+};
+
 /**
  * struct perf_event_context - event context structure
  *
  * Used as a container for task events and CPU events as well:
  */
 struct perf_event_context {
+       enum perf_event_context_type    type;
+       struct pmu                      *pmu;
        /*
         * Protect the states of the events in the list,
         * nr_active, and the list:
@@ -808,6 +860,12 @@ struct perf_event_context {
        struct rcu_head                 rcu_head;
 };
 
+/*
+ * Number of contexts where an event can trigger:
+ *     task, softirq, hardirq, nmi.
+ */
+#define PERF_NR_CONTEXTS       4
+
 /**
  * struct perf_event_cpu_context - per cpu event context structure
  */
@@ -815,18 +873,9 @@ struct perf_cpu_context {
        struct perf_event_context       ctx;
        struct perf_event_context       *task_ctx;
        int                             active_oncpu;
-       int                             max_pertask;
        int                             exclusive;
-       struct swevent_hlist            *swevent_hlist;
-       struct mutex                    hlist_mutex;
-       int                             hlist_refcount;
-
-       /*
-        * Recursion avoidance:
-        *
-        * task, softirq, irq, nmi context
-        */
-       int                             recursion[4];
+       struct list_head                rotation_list;
+       int                             jiffies_interval;
 };
 
 struct perf_output_handle {
@@ -842,26 +891,34 @@ struct perf_output_handle {
 
 #ifdef CONFIG_PERF_EVENTS
 
-/*
- * Set by architecture code:
- */
-extern int perf_max_events;
+extern int perf_pmu_register(struct pmu *pmu);
+extern void perf_pmu_unregister(struct pmu *pmu);
+
+extern int perf_num_counters(void);
+extern const char *perf_pmu_name(void);
+extern void __perf_event_task_sched_in(struct task_struct *task);
+extern void __perf_event_task_sched_out(struct task_struct *task, struct task_struct *next);
 
-extern const struct pmu *hw_perf_event_init(struct perf_event *event);
+extern atomic_t perf_task_events;
+
+static inline void perf_event_task_sched_in(struct task_struct *task)
+{
+       COND_STMT(&perf_task_events, __perf_event_task_sched_in(task));
+}
+
+static inline
+void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next)
+{
+       COND_STMT(&perf_task_events, __perf_event_task_sched_out(task, next));
+}
 
-extern void perf_event_task_sched_in(struct task_struct *task);
-extern void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next);
-extern void perf_event_task_tick(struct task_struct *task);
 extern int perf_event_init_task(struct task_struct *child);
 extern void perf_event_exit_task(struct task_struct *child);
 extern void perf_event_free_task(struct task_struct *task);
-extern void set_perf_event_pending(void);
-extern void perf_event_do_pending(void);
+extern void perf_event_delayed_put(struct task_struct *task);
 extern void perf_event_print_debug(void);
-extern void __perf_disable(void);
-extern bool __perf_enable(void);
-extern void perf_disable(void);
-extern void perf_enable(void);
+extern void perf_pmu_disable(struct pmu *pmu);
+extern void perf_pmu_enable(struct pmu *pmu);
 extern int perf_event_task_disable(void);
 extern int perf_event_task_enable(void);
 extern void perf_event_update_userpage(struct perf_event *event);
@@ -869,7 +926,7 @@ extern int perf_event_release_kernel(struct perf_event *event);
 extern struct perf_event *
 perf_event_create_kernel_counter(struct perf_event_attr *attr,
                                int cpu,
-                               pid_t pid,
+                               struct task_struct *task,
                                perf_overflow_handler_t callback);
 extern u64 perf_event_read_value(struct perf_event *event,
                                 u64 *enabled, u64 *running);
@@ -920,14 +977,7 @@ extern int perf_event_overflow(struct perf_event *event, int nmi,
  */
 static inline int is_software_event(struct perf_event *event)
 {
-       switch (event->attr.type) {
-       case PERF_TYPE_SOFTWARE:
-       case PERF_TYPE_TRACEPOINT:
-       /* for now the breakpoint stuff also works as software event */
-       case PERF_TYPE_BREAKPOINT:
-               return 1;
-       }
-       return 0;
+       return event->pmu->task_ctx_nr == perf_sw_context;
 }
 
 extern atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
@@ -954,18 +1004,20 @@ static inline void perf_fetch_caller_regs(struct pt_regs *regs)
        perf_arch_fetch_caller_regs(regs, CALLER_ADDR0);
 }
 
-static inline void
+static __always_inline void
 perf_sw_event(u32 event_id, u64 nr, int nmi, struct pt_regs *regs, u64 addr)
 {
-       if (atomic_read(&perf_swevent_enabled[event_id])) {
-               struct pt_regs hot_regs;
-
-               if (!regs) {
-                       perf_fetch_caller_regs(&hot_regs);
-                       regs = &hot_regs;
-               }
-               __perf_sw_event(event_id, nr, nmi, regs, addr);
+       struct pt_regs hot_regs;
+
+       JUMP_LABEL(&perf_swevent_enabled[event_id], have_event);
+       return;
+
+have_event:
+       if (!regs) {
+               perf_fetch_caller_regs(&hot_regs);
+               regs = &hot_regs;
        }
+       __perf_sw_event(event_id, nr, nmi, regs, addr);
 }
 
 extern void perf_event_mmap(struct vm_area_struct *vma);
@@ -976,7 +1028,21 @@ extern int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks
 extern void perf_event_comm(struct task_struct *tsk);
 extern void perf_event_fork(struct task_struct *tsk);
 
-extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs);
+/* Callchains */
+DECLARE_PER_CPU(struct perf_callchain_entry, perf_callchain_entry);
+
+extern void perf_callchain_user(struct perf_callchain_entry *entry,
+                               struct pt_regs *regs);
+extern void perf_callchain_kernel(struct perf_callchain_entry *entry,
+                                 struct pt_regs *regs);
+
+
+static inline void
+perf_callchain_store(struct perf_callchain_entry *entry, u64 ip)
+{
+       if (entry->nr < PERF_MAX_STACK_DEPTH)
+               entry->ip[entry->nr++] = ip;
+}
 
 extern int sysctl_perf_event_paranoid;
 extern int sysctl_perf_event_mlock;
@@ -1019,21 +1085,18 @@ extern int perf_swevent_get_recursion_context(void);
 extern void perf_swevent_put_recursion_context(int rctx);
 extern void perf_event_enable(struct perf_event *event);
 extern void perf_event_disable(struct perf_event *event);
+extern void perf_event_task_tick(void);
 #else
 static inline void
 perf_event_task_sched_in(struct task_struct *task)                     { }
 static inline void
 perf_event_task_sched_out(struct task_struct *task,
                            struct task_struct *next)                   { }
-static inline void
-perf_event_task_tick(struct task_struct *task)                         { }
 static inline int perf_event_init_task(struct task_struct *child)      { return 0; }
 static inline void perf_event_exit_task(struct task_struct *child)     { }
 static inline void perf_event_free_task(struct task_struct *task)      { }
-static inline void perf_event_do_pending(void)                         { }
+static inline void perf_event_delayed_put(struct task_struct *task)    { }
 static inline void perf_event_print_debug(void)                                { }
-static inline void perf_disable(void)                                  { }
-static inline void perf_enable(void)                                   { }
 static inline int perf_event_task_disable(void)                                { return -EINVAL; }
 static inline int perf_event_task_enable(void)                         { return -EINVAL; }
 
@@ -1056,6 +1119,7 @@ static inline int  perf_swevent_get_recursion_context(void)               { return -1; }
 static inline void perf_swevent_put_recursion_context(int rctx)                { }
 static inline void perf_event_enable(struct perf_event *event)         { }
 static inline void perf_event_disable(struct perf_event *event)                { }
+static inline void perf_event_task_tick(void)                          { }
 #endif
 
 #define perf_output_put(handle, x) \
index 52e8c55ff314ce9ffa92b14b11ff5603a4e77eb6..40f3f45702bac82a8e454812b67a4419b7d36362 100644 (file)
@@ -41,6 +41,12 @@ extern void (*pm_power_off_prepare)(void);
 
 struct device;
 
+#ifdef CONFIG_PM
+extern const char power_group_name[];          /* = "power" */
+#else
+#define power_group_name       NULL
+#endif
+
 typedef struct pm_message {
        int event;
 } pm_message_t;
@@ -438,6 +444,9 @@ enum rpm_status {
  *
  * RPM_REQ_SUSPEND     Run the device bus type's ->runtime_suspend() callback
  *
+ * RPM_REQ_AUTOSUSPEND Same as RPM_REQ_SUSPEND, but not until the device has
+ *                     been inactive for as long as power.autosuspend_delay
+ *
  * RPM_REQ_RESUME      Run the device bus type's ->runtime_resume() callback
  */
 
@@ -445,26 +454,28 @@ enum rpm_request {
        RPM_REQ_NONE = 0,
        RPM_REQ_IDLE,
        RPM_REQ_SUSPEND,
+       RPM_REQ_AUTOSUSPEND,
        RPM_REQ_RESUME,
 };
 
+struct wakeup_source;
+
 struct dev_pm_info {
        pm_message_t            power_state;
        unsigned int            can_wakeup:1;
-       unsigned int            should_wakeup:1;
        unsigned                async_suspend:1;
        enum dpm_state          status;         /* Owned by the PM core */
+       spinlock_t              lock;
 #ifdef CONFIG_PM_SLEEP
        struct list_head        entry;
        struct completion       completion;
-       unsigned long           wakeup_count;
+       struct wakeup_source    *wakeup;
 #endif
 #ifdef CONFIG_PM_RUNTIME
        struct timer_list       suspend_timer;
        unsigned long           timer_expires;
        struct work_struct      work;
        wait_queue_head_t       wait_queue;
-       spinlock_t              lock;
        atomic_t                usage_count;
        atomic_t                child_count;
        unsigned int            disable_depth:3;
@@ -474,9 +485,14 @@ struct dev_pm_info {
        unsigned int            deferred_resume:1;
        unsigned int            run_wake:1;
        unsigned int            runtime_auto:1;
+       unsigned int            no_callbacks:1;
+       unsigned int            use_autosuspend:1;
+       unsigned int            timer_autosuspends:1;
        enum rpm_request        request;
        enum rpm_status         runtime_status;
        int                     runtime_error;
+       int                     autosuspend_delay;
+       unsigned long           last_busy;
        unsigned long           active_jiffies;
        unsigned long           suspended_jiffies;
        unsigned long           accounting_timestamp;
@@ -558,12 +574,7 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
                __suspend_report_result(__func__, fn, ret);             \
        } while (0)
 
-extern void device_pm_wait_for_dev(struct device *sub, struct device *dev);
-
-/* drivers/base/power/wakeup.c */
-extern void pm_wakeup_event(struct device *dev, unsigned int msec);
-extern void pm_stay_awake(struct device *dev);
-extern void pm_relax(void);
+extern int device_pm_wait_for_dev(struct device *sub, struct device *dev);
 #else /* !CONFIG_PM_SLEEP */
 
 #define device_pm_lock() do {} while (0)
@@ -576,11 +587,10 @@ static inline int dpm_suspend_start(pm_message_t state)
 
 #define suspend_report_result(fn, ret)         do {} while (0)
 
-static inline void device_pm_wait_for_dev(struct device *a, struct device *b) {}
-
-static inline void pm_wakeup_event(struct device *dev, unsigned int msec) {}
-static inline void pm_stay_awake(struct device *dev) {}
-static inline void pm_relax(void) {}
+static inline int device_pm_wait_for_dev(struct device *a, struct device *b)
+{
+       return 0;
+}
 #endif /* !CONFIG_PM_SLEEP */
 
 /* How to reorder dpm_list after device_move() */
index 6e81888c62225f99217ab356dd0f3c46a3a45715..3ec2358f8692d11027e6af927402fcbc0f039da2 100644 (file)
 #include <linux/device.h>
 #include <linux/pm.h>
 
+#include <linux/jiffies.h>
+
+/* Runtime PM flag argument bits */
+#define RPM_ASYNC              0x01    /* Request is asynchronous */
+#define RPM_NOWAIT             0x02    /* Don't wait for concurrent
+                                           state change */
+#define RPM_GET_PUT            0x04    /* Increment/decrement the
+                                           usage_count */
+#define RPM_AUTO               0x08    /* Use autosuspend_delay */
+
 #ifdef CONFIG_PM_RUNTIME
 
 extern struct workqueue_struct *pm_wq;
 
-extern int pm_runtime_idle(struct device *dev);
-extern int pm_runtime_suspend(struct device *dev);
-extern int pm_runtime_resume(struct device *dev);
-extern int pm_request_idle(struct device *dev);
+extern int __pm_runtime_idle(struct device *dev, int rpmflags);
+extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
+extern int __pm_runtime_resume(struct device *dev, int rpmflags);
 extern int pm_schedule_suspend(struct device *dev, unsigned int delay);
-extern int pm_request_resume(struct device *dev);
-extern int __pm_runtime_get(struct device *dev, bool sync);
-extern int __pm_runtime_put(struct device *dev, bool sync);
 extern int __pm_runtime_set_status(struct device *dev, unsigned int status);
 extern int pm_runtime_barrier(struct device *dev);
 extern void pm_runtime_enable(struct device *dev);
@@ -33,6 +39,10 @@ extern void pm_runtime_forbid(struct device *dev);
 extern int pm_generic_runtime_idle(struct device *dev);
 extern int pm_generic_runtime_suspend(struct device *dev);
 extern int pm_generic_runtime_resume(struct device *dev);
+extern void pm_runtime_no_callbacks(struct device *dev);
+extern void __pm_runtime_use_autosuspend(struct device *dev, bool use);
+extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay);
+extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev);
 
 static inline bool pm_children_suspended(struct device *dev)
 {
@@ -70,19 +80,29 @@ static inline bool pm_runtime_suspended(struct device *dev)
        return dev->power.runtime_status == RPM_SUSPENDED;
 }
 
+static inline void pm_runtime_mark_last_busy(struct device *dev)
+{
+       ACCESS_ONCE(dev->power.last_busy) = jiffies;
+}
+
 #else /* !CONFIG_PM_RUNTIME */
 
-static inline int pm_runtime_idle(struct device *dev) { return -ENOSYS; }
-static inline int pm_runtime_suspend(struct device *dev) { return -ENOSYS; }
-static inline int pm_runtime_resume(struct device *dev) { return 0; }
-static inline int pm_request_idle(struct device *dev) { return -ENOSYS; }
+static inline int __pm_runtime_idle(struct device *dev, int rpmflags)
+{
+       return -ENOSYS;
+}
+static inline int __pm_runtime_suspend(struct device *dev, int rpmflags)
+{
+       return -ENOSYS;
+}
+static inline int __pm_runtime_resume(struct device *dev, int rpmflags)
+{
+       return 1;
+}
 static inline int pm_schedule_suspend(struct device *dev, unsigned int delay)
 {
        return -ENOSYS;
 }
-static inline int pm_request_resume(struct device *dev) { return 0; }
-static inline int __pm_runtime_get(struct device *dev, bool sync) { return 1; }
-static inline int __pm_runtime_put(struct device *dev, bool sync) { return 0; }
 static inline int __pm_runtime_set_status(struct device *dev,
                                            unsigned int status) { return 0; }
 static inline int pm_runtime_barrier(struct device *dev) { return 0; }
@@ -102,27 +122,82 @@ static inline bool pm_runtime_suspended(struct device *dev) { return false; }
 static inline int pm_generic_runtime_idle(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
 static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
+static inline void pm_runtime_no_callbacks(struct device *dev) {}
+
+static inline void pm_runtime_mark_last_busy(struct device *dev) {}
+static inline void __pm_runtime_use_autosuspend(struct device *dev,
+                                               bool use) {}
+static inline void pm_runtime_set_autosuspend_delay(struct device *dev,
+                                               int delay) {}
+static inline unsigned long pm_runtime_autosuspend_expiration(
+                               struct device *dev) { return 0; }
 
 #endif /* !CONFIG_PM_RUNTIME */
 
+static inline int pm_runtime_idle(struct device *dev)
+{
+       return __pm_runtime_idle(dev, 0);
+}
+
+static inline int pm_runtime_suspend(struct device *dev)
+{
+       return __pm_runtime_suspend(dev, 0);
+}
+
+static inline int pm_runtime_autosuspend(struct device *dev)
+{
+       return __pm_runtime_suspend(dev, RPM_AUTO);
+}
+
+static inline int pm_runtime_resume(struct device *dev)
+{
+       return __pm_runtime_resume(dev, 0);
+}
+
+static inline int pm_request_idle(struct device *dev)
+{
+       return __pm_runtime_idle(dev, RPM_ASYNC);
+}
+
+static inline int pm_request_resume(struct device *dev)
+{
+       return __pm_runtime_resume(dev, RPM_ASYNC);
+}
+
+static inline int pm_request_autosuspend(struct device *dev)
+{
+       return __pm_runtime_suspend(dev, RPM_ASYNC | RPM_AUTO);
+}
+
 static inline int pm_runtime_get(struct device *dev)
 {
-       return __pm_runtime_get(dev, false);
+       return __pm_runtime_resume(dev, RPM_GET_PUT | RPM_ASYNC);
 }
 
 static inline int pm_runtime_get_sync(struct device *dev)
 {
-       return __pm_runtime_get(dev, true);
+       return __pm_runtime_resume(dev, RPM_GET_PUT);
 }
 
 static inline int pm_runtime_put(struct device *dev)
 {
-       return __pm_runtime_put(dev, false);
+       return __pm_runtime_idle(dev, RPM_GET_PUT | RPM_ASYNC);
+}
+
+static inline int pm_runtime_put_autosuspend(struct device *dev)
+{
+       return __pm_runtime_suspend(dev,
+           RPM_GET_PUT | RPM_ASYNC | RPM_AUTO);
 }
 
 static inline int pm_runtime_put_sync(struct device *dev)
 {
-       return __pm_runtime_put(dev, true);
+       return __pm_runtime_idle(dev, RPM_GET_PUT);
+}
+
+static inline int pm_runtime_put_sync_autosuspend(struct device *dev)
+{
+       return __pm_runtime_suspend(dev, RPM_GET_PUT | RPM_AUTO);
 }
 
 static inline int pm_runtime_set_active(struct device *dev)
@@ -140,4 +215,14 @@ static inline void pm_runtime_disable(struct device *dev)
        __pm_runtime_disable(dev, true);
 }
 
+static inline void pm_runtime_use_autosuspend(struct device *dev)
+{
+       __pm_runtime_use_autosuspend(dev, true);
+}
+
+static inline void pm_runtime_dont_use_autosuspend(struct device *dev)
+{
+       __pm_runtime_use_autosuspend(dev, false);
+}
+
 #endif
index 76aca48722aeb116556b36d478e1e114834c8446..9cff00dd6b63a031d02e59b797fcf2c5fe94f082 100644 (file)
@@ -2,6 +2,7 @@
  *  pm_wakeup.h - Power management wakeup interface
  *
  *  Copyright (C) 2008 Alan Stern
+ *  Copyright (C) 2010 Rafael J. Wysocki, Novell 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
 
 #include <linux/types.h>
 
-#ifdef CONFIG_PM
-
-/* Changes to device_may_wakeup take effect on the next pm state change.
+/**
+ * struct wakeup_source - Representation of wakeup sources
  *
- * By default, most devices should leave wakeup disabled.  The exceptions
- * are devices that everyone expects to be wakeup sources: keyboards,
- * power buttons, possibly network interfaces, etc.
+ * @total_time: Total time this wakeup source has been active.
+ * @max_time: Maximum time this wakeup source has been continuously active.
+ * @last_time: Monotonic clock when the wakeup source's was activated last time.
+ * @event_count: Number of signaled wakeup events.
+ * @active_count: Number of times the wakeup sorce was activated.
+ * @relax_count: Number of times the wakeup sorce was deactivated.
+ * @hit_count: Number of times the wakeup sorce might abort system suspend.
+ * @active: Status of the wakeup source.
  */
-static inline void device_init_wakeup(struct device *dev, bool val)
+struct wakeup_source {
+       char                    *name;
+       struct list_head        entry;
+       spinlock_t              lock;
+       struct timer_list       timer;
+       unsigned long           timer_expires;
+       ktime_t total_time;
+       ktime_t max_time;
+       ktime_t last_time;
+       unsigned long           event_count;
+       unsigned long           active_count;
+       unsigned long           relax_count;
+       unsigned long           hit_count;
+       unsigned int            active:1;
+};
+
+#ifdef CONFIG_PM_SLEEP
+
+/*
+ * Changes to device_may_wakeup take effect on the next pm state change.
+ */
+
+static inline void device_set_wakeup_capable(struct device *dev, bool capable)
+{
+       dev->power.can_wakeup = capable;
+}
+
+static inline bool device_can_wakeup(struct device *dev)
+{
+       return dev->power.can_wakeup;
+}
+
+
+
+static inline bool device_may_wakeup(struct device *dev)
 {
-       dev->power.can_wakeup = dev->power.should_wakeup = val;
+       return dev->power.can_wakeup && !!dev->power.wakeup;
 }
 
+/* drivers/base/power/wakeup.c */
+extern struct wakeup_source *wakeup_source_create(const char *name);
+extern void wakeup_source_destroy(struct wakeup_source *ws);
+extern void wakeup_source_add(struct wakeup_source *ws);
+extern void wakeup_source_remove(struct wakeup_source *ws);
+extern struct wakeup_source *wakeup_source_register(const char *name);
+extern void wakeup_source_unregister(struct wakeup_source *ws);
+extern int device_wakeup_enable(struct device *dev);
+extern int device_wakeup_disable(struct device *dev);
+extern int device_init_wakeup(struct device *dev, bool val);
+extern int device_set_wakeup_enable(struct device *dev, bool enable);
+extern void __pm_stay_awake(struct wakeup_source *ws);
+extern void pm_stay_awake(struct device *dev);
+extern void __pm_relax(struct wakeup_source *ws);
+extern void pm_relax(struct device *dev);
+extern void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec);
+extern void pm_wakeup_event(struct device *dev, unsigned int msec);
+
+#else /* !CONFIG_PM_SLEEP */
+
 static inline void device_set_wakeup_capable(struct device *dev, bool capable)
 {
        dev->power.can_wakeup = capable;
@@ -50,43 +109,63 @@ static inline bool device_can_wakeup(struct device *dev)
        return dev->power.can_wakeup;
 }
 
-static inline void device_set_wakeup_enable(struct device *dev, bool enable)
+static inline bool device_may_wakeup(struct device *dev)
 {
-       dev->power.should_wakeup = enable;
+       return false;
 }
 
-static inline bool device_may_wakeup(struct device *dev)
+static inline struct wakeup_source *wakeup_source_create(const char *name)
 {
-       return dev->power.can_wakeup && dev->power.should_wakeup;
+       return NULL;
 }
 
-#else /* !CONFIG_PM */
+static inline void wakeup_source_destroy(struct wakeup_source *ws) {}
+
+static inline void wakeup_source_add(struct wakeup_source *ws) {}
 
-/* For some reason the following routines work even without CONFIG_PM */
-static inline void device_init_wakeup(struct device *dev, bool val)
+static inline void wakeup_source_remove(struct wakeup_source *ws) {}
+
+static inline struct wakeup_source *wakeup_source_register(const char *name)
 {
-       dev->power.can_wakeup = val;
+       return NULL;
 }
 
-static inline void device_set_wakeup_capable(struct device *dev, bool capable)
+static inline void wakeup_source_unregister(struct wakeup_source *ws) {}
+
+static inline int device_wakeup_enable(struct device *dev)
 {
-       dev->power.can_wakeup = capable;
+       return -EINVAL;
 }
 
-static inline bool device_can_wakeup(struct device *dev)
+static inline int device_wakeup_disable(struct device *dev)
 {
-       return dev->power.can_wakeup;
+       return 0;
 }
 
-static inline void device_set_wakeup_enable(struct device *dev, bool enable)
+static inline int device_init_wakeup(struct device *dev, bool val)
 {
+       dev->power.can_wakeup = val;
+       return val ? -EINVAL : 0;
 }
 
-static inline bool device_may_wakeup(struct device *dev)
+
+static inline int device_set_wakeup_enable(struct device *dev, bool enable)
 {
-       return false;
+       return -EINVAL;
 }
 
-#endif /* !CONFIG_PM */
+static inline void __pm_stay_awake(struct wakeup_source *ws) {}
+
+static inline void pm_stay_awake(struct device *dev) {}
+
+static inline void __pm_relax(struct wakeup_source *ws) {}
+
+static inline void pm_relax(struct device *dev) {}
+
+static inline void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) {}
+
+static inline void pm_wakeup_event(struct device *dev, unsigned int msec) {}
+
+#endif /* !CONFIG_PM_SLEEP */
 
 #endif /* _LINUX_PM_WAKEUP_H */
index 634b8e674ac578e2916b110a28b992bf2e8dfd22..a39cbed9ee17a5d771f7c3e7ca129e3a05171220 100644 (file)
@@ -47,6 +47,8 @@ static inline void *radix_tree_indirect_to_ptr(void *ptr)
 {
        return (void *)((unsigned long)ptr & ~RADIX_TREE_INDIRECT_PTR);
 }
+#define radix_tree_indirect_to_ptr(ptr) \
+       radix_tree_indirect_to_ptr((void __force *)(ptr))
 
 static inline int radix_tree_is_indirect_ptr(void *ptr)
 {
@@ -61,7 +63,7 @@ static inline int radix_tree_is_indirect_ptr(void *ptr)
 struct radix_tree_root {
        unsigned int            height;
        gfp_t                   gfp_mask;
-       struct radix_tree_node  *rnode;
+       struct radix_tree_node  __rcu *rnode;
 };
 
 #define RADIX_TREE_INIT(mask)  {                                       \
index 4ec3b38ce9c584049229b71bbf537770d6fbe263..f31ef61f1c650b585bd6faf969f7cec754dffe2d 100644 (file)
@@ -9,6 +9,21 @@
 #include <linux/list.h>
 #include <linux/rcupdate.h>
 
+/*
+ * Why is there no list_empty_rcu()?  Because list_empty() serves this
+ * purpose.  The list_empty() function fetches the RCU-protected pointer
+ * and compares it to the address of the list head, but neither dereferences
+ * this pointer itself nor provides this pointer to the caller.  Therefore,
+ * it is not necessary to use rcu_dereference(), so that list_empty() can
+ * be used anywhere you would want to use a list_empty_rcu().
+ */
+
+/*
+ * return the ->next pointer of a list_head in an rcu safe
+ * way, we must not access it directly
+ */
+#define list_next_rcu(list)    (*((struct list_head __rcu **)(&(list)->next)))
+
 /*
  * Insert a new entry between two known consecutive entries.
  *
@@ -20,7 +35,7 @@ static inline void __list_add_rcu(struct list_head *new,
 {
        new->next = next;
        new->prev = prev;
-       rcu_assign_pointer(prev->next, new);
+       rcu_assign_pointer(list_next_rcu(prev), new);
        next->prev = new;
 }
 
@@ -138,7 +153,7 @@ static inline void list_replace_rcu(struct list_head *old,
 {
        new->next = old->next;
        new->prev = old->prev;
-       rcu_assign_pointer(new->prev->next, new);
+       rcu_assign_pointer(list_next_rcu(new->prev), new);
        new->next->prev = new;
        old->prev = LIST_POISON2;
 }
@@ -193,7 +208,7 @@ static inline void list_splice_init_rcu(struct list_head *list,
         */
 
        last->next = at;
-       rcu_assign_pointer(head->next, first);
+       rcu_assign_pointer(list_next_rcu(head), first);
        first->prev = head;
        at->prev = last;
 }
@@ -208,7 +223,9 @@ static inline void list_splice_init_rcu(struct list_head *list,
  * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
  */
 #define list_entry_rcu(ptr, type, member) \
-       container_of(rcu_dereference_raw(ptr), type, member)
+       ({typeof (*ptr) __rcu *__ptr = (typeof (*ptr) __rcu __force *)ptr; \
+        container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \
+       })
 
 /**
  * list_first_entry_rcu - get the first element from a list
@@ -225,9 +242,9 @@ static inline void list_splice_init_rcu(struct list_head *list,
        list_entry_rcu((ptr)->next, type, member)
 
 #define __list_for_each_rcu(pos, head) \
-       for (pos = rcu_dereference_raw((head)->next); \
+       for (pos = rcu_dereference_raw(list_next_rcu(head)); \
                pos != (head); \
-               pos = rcu_dereference_raw(pos->next))
+               pos = rcu_dereference_raw(list_next_rcu((pos)))
 
 /**
  * list_for_each_entry_rcu     -       iterate over rcu list of given type
@@ -257,9 +274,9 @@ static inline void list_splice_init_rcu(struct list_head *list,
  * as long as the traversal is guarded by rcu_read_lock().
  */
 #define list_for_each_continue_rcu(pos, head) \
-       for ((pos) = rcu_dereference_raw((pos)->next); \
+       for ((pos) = rcu_dereference_raw(list_next_rcu(pos)); \
                prefetch((pos)->next), (pos) != (head); \
-               (pos) = rcu_dereference_raw((pos)->next))
+               (pos) = rcu_dereference_raw(list_next_rcu(pos)))
 
 /**
  * list_for_each_entry_continue_rcu - continue iteration over list of given type
@@ -314,12 +331,19 @@ static inline void hlist_replace_rcu(struct hlist_node *old,
 
        new->next = next;
        new->pprev = old->pprev;
-       rcu_assign_pointer(*new->pprev, new);
+       rcu_assign_pointer(*(struct hlist_node __rcu **)new->pprev, new);
        if (next)
                new->next->pprev = &new->next;
        old->pprev = LIST_POISON2;
 }
 
+/*
+ * return the first or the next element in an RCU protected hlist
+ */
+#define hlist_first_rcu(head)  (*((struct hlist_node __rcu **)(&(head)->first)))
+#define hlist_next_rcu(node)   (*((struct hlist_node __rcu **)(&(node)->next)))
+#define hlist_pprev_rcu(node)  (*((struct hlist_node __rcu **)((node)->pprev)))
+
 /**
  * hlist_add_head_rcu
  * @n: the element to add to the hash list.
@@ -346,7 +370,7 @@ static inline void hlist_add_head_rcu(struct hlist_node *n,
 
        n->next = first;
        n->pprev = &h->first;
-       rcu_assign_pointer(h->first, n);
+       rcu_assign_pointer(hlist_first_rcu(h), n);
        if (first)
                first->pprev = &n->next;
 }
@@ -374,7 +398,7 @@ static inline void hlist_add_before_rcu(struct hlist_node *n,
 {
        n->pprev = next->pprev;
        n->next = next;
-       rcu_assign_pointer(*(n->pprev), n);
+       rcu_assign_pointer(hlist_pprev_rcu(n), n);
        next->pprev = &n->next;
 }
 
@@ -401,15 +425,15 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
 {
        n->next = prev->next;
        n->pprev = &prev->next;
-       rcu_assign_pointer(prev->next, n);
+       rcu_assign_pointer(hlist_next_rcu(prev), n);
        if (n->next)
                n->next->pprev = &n->next;
 }
 
-#define __hlist_for_each_rcu(pos, head)                        \
-       for (pos = rcu_dereference((head)->first);      \
-            pos && ({ prefetch(pos->next); 1; });      \
-            pos = rcu_dereference(pos->next))
+#define __hlist_for_each_rcu(pos, head)                                \
+       for (pos = rcu_dereference(hlist_first_rcu(head));      \
+            pos && ({ prefetch(pos->next); 1; });              \
+            pos = rcu_dereference(hlist_next_rcu(pos)))
 
 /**
  * hlist_for_each_entry_rcu - iterate over rcu list of given type
@@ -422,11 +446,11 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
  * the _rcu list-mutation primitives such as hlist_add_head_rcu()
  * as long as the traversal is guarded by rcu_read_lock().
  */
-#define hlist_for_each_entry_rcu(tpos, pos, head, member)               \
-       for (pos = rcu_dereference_raw((head)->first);                   \
+#define hlist_for_each_entry_rcu(tpos, pos, head, member)              \
+       for (pos = rcu_dereference_raw(hlist_first_rcu(head));          \
                pos && ({ prefetch(pos->next); 1; }) &&                  \
                ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
-               pos = rcu_dereference_raw(pos->next))
+               pos = rcu_dereference_raw(hlist_next_rcu(pos)))
 
 /**
  * hlist_for_each_entry_rcu_bh - iterate over rcu list of given type
index b70ffe53cb9fe77a668f57c2bc584216f90f95b6..2ae13714828bc42568e77684fedfc2cf929c291d 100644 (file)
@@ -37,6 +37,12 @@ static inline void hlist_nulls_del_init_rcu(struct hlist_nulls_node *n)
        }
 }
 
+#define hlist_nulls_first_rcu(head) \
+       (*((struct hlist_nulls_node __rcu __force **)&(head)->first))
+
+#define hlist_nulls_next_rcu(node) \
+       (*((struct hlist_nulls_node __rcu __force **)&(node)->next))
+
 /**
  * hlist_nulls_del_rcu - deletes entry from hash list without re-initialization
  * @n: the element to delete from the hash list.
@@ -88,7 +94,7 @@ static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n,
 
        n->next = first;
        n->pprev = &h->first;
-       rcu_assign_pointer(h->first, n);
+       rcu_assign_pointer(hlist_nulls_first_rcu(h), n);
        if (!is_a_nulls(first))
                first->pprev = &n->next;
 }
@@ -100,11 +106,11 @@ static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n,
  * @member:    the name of the hlist_nulls_node within the struct.
  *
  */
-#define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \
-       for (pos = rcu_dereference_raw((head)->first);                   \
-               (!is_a_nulls(pos)) &&                   \
+#define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member)                        \
+       for (pos = rcu_dereference_raw(hlist_nulls_first_rcu(head));            \
+               (!is_a_nulls(pos)) &&                                           \
                ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1; }); \
-               pos = rcu_dereference_raw(pos->next))
+               pos = rcu_dereference_raw(hlist_nulls_next_rcu(pos)))
 
 #endif
 #endif
index 83af1f8d8b746cde3b8369d7125f3cdfe07da6d3..03cda7bed98587b128c5a9953316644a8debb4d2 100644 (file)
 #include <linux/lockdep.h>
 #include <linux/completion.h>
 #include <linux/debugobjects.h>
+#include <linux/compiler.h>
 
 #ifdef CONFIG_RCU_TORTURE_TEST
 extern int rcutorture_runnable; /* for sysctl */
 #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
 
+#define ULONG_CMP_GE(a, b)     (ULONG_MAX / 2 >= (a) - (b))
+#define ULONG_CMP_LT(a, b)     (ULONG_MAX / 2 < (a) - (b))
+
 /**
  * struct rcu_head - callback structure for use with RCU
  * @next: next update requests in a list
@@ -57,29 +61,94 @@ struct rcu_head {
 };
 
 /* Exported common interfaces */
-extern void rcu_barrier(void);
+extern void call_rcu_sched(struct rcu_head *head,
+                          void (*func)(struct rcu_head *rcu));
+extern void synchronize_sched(void);
 extern void rcu_barrier_bh(void);
 extern void rcu_barrier_sched(void);
 extern void synchronize_sched_expedited(void);
 extern int sched_expedited_torture_stats(char *page);
 
+static inline void __rcu_read_lock_bh(void)
+{
+       local_bh_disable();
+}
+
+static inline void __rcu_read_unlock_bh(void)
+{
+       local_bh_enable();
+}
+
+#ifdef CONFIG_PREEMPT_RCU
+
+extern void __rcu_read_lock(void);
+extern void __rcu_read_unlock(void);
+void synchronize_rcu(void);
+
+/*
+ * Defined as a macro as it is a very low level header included from
+ * areas that don't even know about current.  This gives the rcu_read_lock()
+ * nesting depth, but makes sense only if CONFIG_PREEMPT_RCU -- in other
+ * types of kernel builds, the rcu_read_lock() nesting depth is unknowable.
+ */
+#define rcu_preempt_depth() (current->rcu_read_lock_nesting)
+
+#else /* #ifdef CONFIG_PREEMPT_RCU */
+
+static inline void __rcu_read_lock(void)
+{
+       preempt_disable();
+}
+
+static inline void __rcu_read_unlock(void)
+{
+       preempt_enable();
+}
+
+static inline void synchronize_rcu(void)
+{
+       synchronize_sched();
+}
+
+static inline int rcu_preempt_depth(void)
+{
+       return 0;
+}
+
+#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
+
 /* Internal to kernel */
 extern void rcu_init(void);
+extern void rcu_sched_qs(int cpu);
+extern void rcu_bh_qs(int cpu);
+extern void rcu_check_callbacks(int cpu, int user);
+struct notifier_block;
+
+#ifdef CONFIG_NO_HZ
+
+extern void rcu_enter_nohz(void);
+extern void rcu_exit_nohz(void);
+
+#else /* #ifdef CONFIG_NO_HZ */
+
+static inline void rcu_enter_nohz(void)
+{
+}
+
+static inline void rcu_exit_nohz(void)
+{
+}
+
+#endif /* #else #ifdef CONFIG_NO_HZ */
 
 #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
 #include <linux/rcutree.h>
-#elif defined(CONFIG_TINY_RCU)
+#elif defined(CONFIG_TINY_RCU) || defined(CONFIG_TINY_PREEMPT_RCU)
 #include <linux/rcutiny.h>
 #else
 #error "Unknown RCU implementation specified to kernel configuration"
 #endif
 
-#define RCU_HEAD_INIT  { .next = NULL, .func = NULL }
-#define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT
-#define INIT_RCU_HEAD(ptr) do { \
-       (ptr)->next = NULL; (ptr)->func = NULL; \
-} while (0)
-
 /*
  * init_rcu_head_on_stack()/destroy_rcu_head_on_stack() are needed for dynamic
  * initialization and destruction of rcu_head on the stack. rcu_head structures
@@ -120,14 +189,15 @@ extern struct lockdep_map rcu_sched_lock_map;
 extern int debug_lockdep_rcu_enabled(void);
 
 /**
- * rcu_read_lock_held - might we be in RCU read-side critical section?
+ * rcu_read_lock_held() - might we be in RCU read-side critical section?
  *
  * If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an RCU
  * read-side critical section.  In absence of CONFIG_DEBUG_LOCK_ALLOC,
  * this assumes we are in an RCU read-side critical section unless it can
- * prove otherwise.
+ * prove otherwise.  This is useful for debug checks in functions that
+ * require that they be called within an RCU read-side critical section.
  *
- * Check debug_lockdep_rcu_enabled() to prevent false positives during boot
+ * Checks debug_lockdep_rcu_enabled() to prevent false positives during boot
  * and while lockdep is disabled.
  */
 static inline int rcu_read_lock_held(void)
@@ -144,14 +214,16 @@ static inline int rcu_read_lock_held(void)
 extern int rcu_read_lock_bh_held(void);
 
 /**
- * rcu_read_lock_sched_held - might we be in RCU-sched read-side critical section?
+ * rcu_read_lock_sched_held() - might we be in RCU-sched read-side critical section?
  *
  * If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an
  * RCU-sched read-side critical section.  In absence of
  * CONFIG_DEBUG_LOCK_ALLOC, this assumes we are in an RCU-sched read-side
  * critical section unless it can prove otherwise.  Note that disabling
  * of preemption (including disabling irqs) counts as an RCU-sched
- * read-side critical section.
+ * read-side critical section.  This is useful for debug checks in functions
+ * that required that they be called within an RCU-sched read-side
+ * critical section.
  *
  * Check debug_lockdep_rcu_enabled() to prevent false positives during boot
  * and while lockdep is disabled.
@@ -211,7 +283,11 @@ static inline int rcu_read_lock_sched_held(void)
 
 extern int rcu_my_thread_group_empty(void);
 
-#define __do_rcu_dereference_check(c)                                  \
+/**
+ * rcu_lockdep_assert - emit lockdep splat if specified condition not met
+ * @c: condition to check
+ */
+#define rcu_lockdep_assert(c)                                          \
        do {                                                            \
                static bool __warned;                                   \
                if (debug_lockdep_rcu_enabled() && !__warned && !(c)) { \
@@ -220,41 +296,163 @@ extern int rcu_my_thread_group_empty(void);
                }                                                       \
        } while (0)
 
+#else /* #ifdef CONFIG_PROVE_RCU */
+
+#define rcu_lockdep_assert(c) do { } while (0)
+
+#endif /* #else #ifdef CONFIG_PROVE_RCU */
+
+/*
+ * Helper functions for rcu_dereference_check(), rcu_dereference_protected()
+ * and rcu_assign_pointer().  Some of these could be folded into their
+ * callers, but they are left separate in order to ease introduction of
+ * multiple flavors of pointers to match the multiple flavors of RCU
+ * (e.g., __rcu_bh, * __rcu_sched, and __srcu), should this make sense in
+ * the future.
+ */
+
+#ifdef __CHECKER__
+#define rcu_dereference_sparse(p, space) \
+       ((void)(((typeof(*p) space *)p) == p))
+#else /* #ifdef __CHECKER__ */
+#define rcu_dereference_sparse(p, space)
+#endif /* #else #ifdef __CHECKER__ */
+
+#define __rcu_access_pointer(p, space) \
+       ({ \
+               typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
+               rcu_dereference_sparse(p, space); \
+               ((typeof(*p) __force __kernel *)(_________p1)); \
+       })
+#define __rcu_dereference_check(p, c, space) \
+       ({ \
+               typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
+               rcu_lockdep_assert(c); \
+               rcu_dereference_sparse(p, space); \
+               smp_read_barrier_depends(); \
+               ((typeof(*p) __force __kernel *)(_________p1)); \
+       })
+#define __rcu_dereference_protected(p, c, space) \
+       ({ \
+               rcu_lockdep_assert(c); \
+               rcu_dereference_sparse(p, space); \
+               ((typeof(*p) __force __kernel *)(p)); \
+       })
+
+#define __rcu_dereference_index_check(p, c) \
+       ({ \
+               typeof(p) _________p1 = ACCESS_ONCE(p); \
+               rcu_lockdep_assert(c); \
+               smp_read_barrier_depends(); \
+               (_________p1); \
+       })
+#define __rcu_assign_pointer(p, v, space) \
+       ({ \
+               if (!__builtin_constant_p(v) || \
+                   ((v) != NULL)) \
+                       smp_wmb(); \
+               (p) = (typeof(*v) __force space *)(v); \
+       })
+
+
+/**
+ * rcu_access_pointer() - fetch RCU pointer with no dereferencing
+ * @p: The pointer to read
+ *
+ * Return the value of the specified RCU-protected pointer, but omit the
+ * smp_read_barrier_depends() and keep the ACCESS_ONCE().  This is useful
+ * when the value of this pointer is accessed, but the pointer is not
+ * dereferenced, for example, when testing an RCU-protected pointer against
+ * NULL.  Although rcu_access_pointer() may also be used in cases where
+ * update-side locks prevent the value of the pointer from changing, you
+ * should instead use rcu_dereference_protected() for this use case.
+ */
+#define rcu_access_pointer(p) __rcu_access_pointer((p), __rcu)
+
 /**
- * rcu_dereference_check - rcu_dereference with debug checking
+ * rcu_dereference_check() - rcu_dereference with debug checking
  * @p: The pointer to read, prior to dereferencing
  * @c: The conditions under which the dereference will take place
  *
  * Do an rcu_dereference(), but check that the conditions under which the
- * dereference will take place are correct.  Typically the conditions indicate
- * the various locking conditions that should be held at that point.  The check
- * should return true if the conditions are satisfied.
+ * dereference will take place are correct.  Typically the conditions
+ * indicate the various locking conditions that should be held at that
+ * point.  The check should return true if the conditions are satisfied.
+ * An implicit check for being in an RCU read-side critical section
+ * (rcu_read_lock()) is included.
  *
  * For example:
  *
- *     bar = rcu_dereference_check(foo->bar, rcu_read_lock_held() ||
- *                                           lockdep_is_held(&foo->lock));
+ *     bar = rcu_dereference_check(foo->bar, lockdep_is_held(&foo->lock));
  *
  * could be used to indicate to lockdep that foo->bar may only be dereferenced
- * if either the RCU read lock is held, or that the lock required to replace
+ * if either rcu_read_lock() is held, or that the lock required to replace
  * the bar struct at foo->bar is held.
  *
  * Note that the list of conditions may also include indications of when a lock
  * need not be held, for example during initialisation or destruction of the
  * target struct:
  *
- *     bar = rcu_dereference_check(foo->bar, rcu_read_lock_held() ||
- *                                           lockdep_is_held(&foo->lock) ||
+ *     bar = rcu_dereference_check(foo->bar, lockdep_is_held(&foo->lock) ||
  *                                           atomic_read(&foo->usage) == 0);
+ *
+ * Inserts memory barriers on architectures that require them
+ * (currently only the Alpha), prevents the compiler from refetching
+ * (and from merging fetches), and, more importantly, documents exactly
+ * which pointers are protected by RCU and checks that the pointer is
+ * annotated as __rcu.
  */
 #define rcu_dereference_check(p, c) \
-       ({ \
-               __do_rcu_dereference_check(c); \
-               rcu_dereference_raw(p); \
-       })
+       __rcu_dereference_check((p), rcu_read_lock_held() || (c), __rcu)
+
+/**
+ * rcu_dereference_bh_check() - rcu_dereference_bh with debug checking
+ * @p: The pointer to read, prior to dereferencing
+ * @c: The conditions under which the dereference will take place
+ *
+ * This is the RCU-bh counterpart to rcu_dereference_check().
+ */
+#define rcu_dereference_bh_check(p, c) \
+       __rcu_dereference_check((p), rcu_read_lock_bh_held() || (c), __rcu)
 
 /**
- * rcu_dereference_protected - fetch RCU pointer when updates prevented
+ * rcu_dereference_sched_check() - rcu_dereference_sched with debug checking
+ * @p: The pointer to read, prior to dereferencing
+ * @c: The conditions under which the dereference will take place
+ *
+ * This is the RCU-sched counterpart to rcu_dereference_check().
+ */
+#define rcu_dereference_sched_check(p, c) \
+       __rcu_dereference_check((p), rcu_read_lock_sched_held() || (c), \
+                               __rcu)
+
+#define rcu_dereference_raw(p) rcu_dereference_check(p, 1) /*@@@ needed? @@@*/
+
+/**
+ * rcu_dereference_index_check() - rcu_dereference for indices with debug checking
+ * @p: The pointer to read, prior to dereferencing
+ * @c: The conditions under which the dereference will take place
+ *
+ * Similar to rcu_dereference_check(), but omits the sparse checking.
+ * This allows rcu_dereference_index_check() to be used on integers,
+ * which can then be used as array indices.  Attempting to use
+ * rcu_dereference_check() on an integer will give compiler warnings
+ * because the sparse address-space mechanism relies on dereferencing
+ * the RCU-protected pointer.  Dereferencing integers is not something
+ * that even gcc will put up with.
+ *
+ * Note that this function does not implicitly check for RCU read-side
+ * critical sections.  If this function gains lots of uses, it might
+ * make sense to provide versions for each flavor of RCU, but it does
+ * not make sense as of early 2010.
+ */
+#define rcu_dereference_index_check(p, c) \
+       __rcu_dereference_index_check((p), (c))
+
+/**
+ * rcu_dereference_protected() - fetch RCU pointer when updates prevented
+ * @p: The pointer to read, prior to dereferencing
+ * @c: The conditions under which the dereference will take place
  *
  * Return the value of the specified RCU-protected pointer, but omit
  * both the smp_read_barrier_depends() and the ACCESS_ONCE().  This
@@ -263,35 +461,61 @@ extern int rcu_my_thread_group_empty(void);
  * prevent the compiler from repeating this reference or combining it
  * with other references, so it should not be used without protection
  * of appropriate locks.
+ *
+ * This function is only for update-side use.  Using this function
+ * when protected only by rcu_read_lock() will result in infrequent
+ * but very ugly failures.
  */
 #define rcu_dereference_protected(p, c) \
-       ({ \
-               __do_rcu_dereference_check(c); \
-               (p); \
-       })
+       __rcu_dereference_protected((p), (c), __rcu)
 
-#else /* #ifdef CONFIG_PROVE_RCU */
+/**
+ * rcu_dereference_bh_protected() - fetch RCU-bh pointer when updates prevented
+ * @p: The pointer to read, prior to dereferencing
+ * @c: The conditions under which the dereference will take place
+ *
+ * This is the RCU-bh counterpart to rcu_dereference_protected().
+ */
+#define rcu_dereference_bh_protected(p, c) \
+       __rcu_dereference_protected((p), (c), __rcu)
 
-#define rcu_dereference_check(p, c)    rcu_dereference_raw(p)
-#define rcu_dereference_protected(p, c) (p)
+/**
+ * rcu_dereference_sched_protected() - fetch RCU-sched pointer when updates prevented
+ * @p: The pointer to read, prior to dereferencing
+ * @c: The conditions under which the dereference will take place
+ *
+ * This is the RCU-sched counterpart to rcu_dereference_protected().
+ */
+#define rcu_dereference_sched_protected(p, c) \
+       __rcu_dereference_protected((p), (c), __rcu)
 
-#endif /* #else #ifdef CONFIG_PROVE_RCU */
 
 /**
- * rcu_access_pointer - fetch RCU pointer with no dereferencing
+ * rcu_dereference() - fetch RCU-protected pointer for dereferencing
+ * @p: The pointer to read, prior to dereferencing
  *
- * Return the value of the specified RCU-protected pointer, but omit the
- * smp_read_barrier_depends() and keep the ACCESS_ONCE().  This is useful
- * when the value of this pointer is accessed, but the pointer is not
- * dereferenced, for example, when testing an RCU-protected pointer against
- * NULL.  This may also be used in cases where update-side locks prevent
- * the value of the pointer from changing, but rcu_dereference_protected()
- * is a lighter-weight primitive for this use case.
+ * This is a simple wrapper around rcu_dereference_check().
+ */
+#define rcu_dereference(p) rcu_dereference_check(p, 0)
+
+/**
+ * rcu_dereference_bh() - fetch an RCU-bh-protected pointer for dereferencing
+ * @p: The pointer to read, prior to dereferencing
+ *
+ * Makes rcu_dereference_check() do the dirty work.
+ */
+#define rcu_dereference_bh(p) rcu_dereference_bh_check(p, 0)
+
+/**
+ * rcu_dereference_sched() - fetch RCU-sched-protected pointer for dereferencing
+ * @p: The pointer to read, prior to dereferencing
+ *
+ * Makes rcu_dereference_check() do the dirty work.
  */
-#define rcu_access_pointer(p)  ACCESS_ONCE(p)
+#define rcu_dereference_sched(p) rcu_dereference_sched_check(p, 0)
 
 /**
- * rcu_read_lock - mark the beginning of an RCU read-side critical section.
+ * rcu_read_lock() - mark the beginning of an RCU read-side critical section
  *
  * When synchronize_rcu() is invoked on one CPU while other CPUs
  * are within RCU read-side critical sections, then the
@@ -302,7 +526,7 @@ extern int rcu_my_thread_group_empty(void);
  * until after the all the other CPUs exit their critical sections.
  *
  * Note, however, that RCU callbacks are permitted to run concurrently
- * with RCU read-side critical sections.  One way that this can happen
+ * with new RCU read-side critical sections.  One way that this can happen
  * is via the following sequence of events: (1) CPU 0 enters an RCU
  * read-side critical section, (2) CPU 1 invokes call_rcu() to register
  * an RCU callback, (3) CPU 0 exits the RCU read-side critical section,
@@ -317,7 +541,20 @@ extern int rcu_my_thread_group_empty(void);
  * will be deferred until the outermost RCU read-side critical section
  * completes.
  *
- * It is illegal to block while in an RCU read-side critical section.
+ * You can avoid reading and understanding the next paragraph by
+ * following this rule: don't put anything in an rcu_read_lock() RCU
+ * read-side critical section that would block in a !PREEMPT kernel.
+ * But if you want the full story, read on!
+ *
+ * In non-preemptible RCU implementations (TREE_RCU and TINY_RCU), it
+ * is illegal to block while in an RCU read-side critical section.  In
+ * preemptible RCU implementations (TREE_PREEMPT_RCU and TINY_PREEMPT_RCU)
+ * in CONFIG_PREEMPT kernel builds, RCU read-side critical sections may
+ * be preempted, but explicit blocking is illegal.  Finally, in preemptible
+ * RCU implementations in real-time (CONFIG_PREEMPT_RT) kernel builds,
+ * RCU read-side critical sections may be preempted and they may also
+ * block, but only when acquiring spinlocks that are subject to priority
+ * inheritance.
  */
 static inline void rcu_read_lock(void)
 {
@@ -337,7 +574,7 @@ static inline void rcu_read_lock(void)
  */
 
 /**
- * rcu_read_unlock - marks the end of an RCU read-side critical section.
+ * rcu_read_unlock() - marks the end of an RCU read-side critical section.
  *
  * See rcu_read_lock() for more information.
  */
@@ -349,15 +586,16 @@ static inline void rcu_read_unlock(void)
 }
 
 /**
- * rcu_read_lock_bh - mark the beginning of a softirq-only RCU critical section
+ * rcu_read_lock_bh() - mark the beginning of an RCU-bh critical section
  *
  * This is equivalent of rcu_read_lock(), but to be used when updates
- * are being done using call_rcu_bh(). Since call_rcu_bh() callbacks
- * consider completion of a softirq handler to be a quiescent state,
- * a process in RCU read-side critical section must be protected by
- * disabling softirqs. Read-side critical sections in interrupt context
- * can use just rcu_read_lock().
- *
+ * are being done using call_rcu_bh() or synchronize_rcu_bh(). Since
+ * both call_rcu_bh() and synchronize_rcu_bh() consider completion of a
+ * softirq handler to be a quiescent state, a process in RCU read-side
+ * critical section must be protected by disabling softirqs. Read-side
+ * critical sections in interrupt context can use just rcu_read_lock(),
+ * though this should at least be commented to avoid confusing people
+ * reading the code.
  */
 static inline void rcu_read_lock_bh(void)
 {
@@ -379,13 +617,12 @@ static inline void rcu_read_unlock_bh(void)
 }
 
 /**
- * rcu_read_lock_sched - mark the beginning of a RCU-classic critical section
+ * rcu_read_lock_sched() - mark the beginning of a RCU-sched critical section
  *
- * Should be used with either
- * - synchronize_sched()
- * or
- * - call_rcu_sched() and rcu_barrier_sched()
- * on the write-side to insure proper synchronization.
+ * This is equivalent of rcu_read_lock(), but to be used when updates
+ * are being done using call_rcu_sched() or synchronize_rcu_sched().
+ * Read-side critical sections can also be introduced by anything that
+ * disables preemption, including local_irq_disable() and friends.
  */
 static inline void rcu_read_lock_sched(void)
 {
@@ -420,54 +657,14 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
        preempt_enable_notrace();
 }
 
-
 /**
- * rcu_dereference_raw - fetch an RCU-protected pointer
+ * rcu_assign_pointer() - assign to RCU-protected pointer
+ * @p: pointer to assign to
+ * @v: value to assign (publish)
  *
- * The caller must be within some flavor of RCU read-side critical
- * section, or must be otherwise preventing the pointer from changing,
- * for example, by holding an appropriate lock.  This pointer may later
- * be safely dereferenced.  It is the caller's responsibility to have
- * done the right thing, as this primitive does no checking of any kind.
- *
- * Inserts memory barriers on architectures that require them
- * (currently only the Alpha), and, more importantly, documents
- * exactly which pointers are protected by RCU.
- */
-#define rcu_dereference_raw(p) ({ \
-                               typeof(p) _________p1 = ACCESS_ONCE(p); \
-                               smp_read_barrier_depends(); \
-                               (_________p1); \
-                               })
-
-/**
- * rcu_dereference - fetch an RCU-protected pointer, checking for RCU
- *
- * Makes rcu_dereference_check() do the dirty work.
- */
-#define rcu_dereference(p) \
-       rcu_dereference_check(p, rcu_read_lock_held())
-
-/**
- * rcu_dereference_bh - fetch an RCU-protected pointer, checking for RCU-bh
- *
- * Makes rcu_dereference_check() do the dirty work.
- */
-#define rcu_dereference_bh(p) \
-               rcu_dereference_check(p, rcu_read_lock_bh_held() || irqs_disabled())
-
-/**
- * rcu_dereference_sched - fetch RCU-protected pointer, checking for RCU-sched
- *
- * Makes rcu_dereference_check() do the dirty work.
- */
-#define rcu_dereference_sched(p) \
-               rcu_dereference_check(p, rcu_read_lock_sched_held())
-
-/**
- * rcu_assign_pointer - assign (publicize) a pointer to a newly
- * initialized structure that will be dereferenced by RCU read-side
- * critical sections.  Returns the value assigned.
+ * Assigns the specified value to the specified RCU-protected
+ * pointer, ensuring that any concurrent RCU readers will see
+ * any prior initialization.  Returns the value assigned.
  *
  * Inserts memory barriers on architectures that require them
  * (pretty much all of them other than x86), and also prevents
@@ -476,14 +673,17 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
  * call documents which pointers will be dereferenced by RCU read-side
  * code.
  */
-
 #define rcu_assign_pointer(p, v) \
-       ({ \
-               if (!__builtin_constant_p(v) || \
-                   ((v) != NULL)) \
-                       smp_wmb(); \
-               (p) = (v); \
-       })
+       __rcu_assign_pointer((p), (v), __rcu)
+
+/**
+ * RCU_INIT_POINTER() - initialize an RCU protected pointer
+ *
+ * Initialize an RCU-protected pointer in such a way to avoid RCU-lockdep
+ * splats.
+ */
+#define RCU_INIT_POINTER(p, v) \
+               p = (typeof(*v) __force __rcu *)(v)
 
 /* Infrastructure to implement the synchronize_() primitives. */
 
@@ -494,26 +694,37 @@ struct rcu_synchronize {
 
 extern void wakeme_after_rcu(struct rcu_head  *head);
 
+#ifdef CONFIG_PREEMPT_RCU
+
 /**
- * call_rcu - Queue an RCU callback for invocation after a grace period.
+ * call_rcu() - Queue an RCU callback for invocation after a grace period.
  * @head: structure to be used for queueing the RCU updates.
- * @func: actual update function to be invoked after the grace period
+ * @func: actual callback function to be invoked after the grace period
  *
- * The update function will be invoked some time after a full grace
- * period elapses, in other words after all currently executing RCU
- * read-side critical sections have completed.  RCU read-side critical
+ * The callback function will be invoked some time after a full grace
+ * period elapses, in other words after all pre-existing RCU read-side
+ * critical sections have completed.  However, the callback function
+ * might well execute concurrently with RCU read-side critical sections
+ * that started after call_rcu() was invoked.  RCU read-side critical
  * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
  * and may be nested.
  */
 extern void call_rcu(struct rcu_head *head,
                              void (*func)(struct rcu_head *head));
 
+#else /* #ifdef CONFIG_PREEMPT_RCU */
+
+/* In classic RCU, call_rcu() is just call_rcu_sched(). */
+#define        call_rcu        call_rcu_sched
+
+#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
+
 /**
- * call_rcu_bh - Queue an RCU for invocation after a quicker grace period.
+ * call_rcu_bh() - Queue an RCU for invocation after a quicker grace period.
  * @head: structure to be used for queueing the RCU updates.
- * @func: actual update function to be invoked after the grace period
+ * @func: actual callback function to be invoked after the grace period
  *
- * The update function will be invoked some time after a full grace
+ * The callback function will be invoked some time after a full grace
  * period elapses, in other words after all currently executing RCU
  * read-side critical sections have completed. call_rcu_bh() assumes
  * that the read-side critical sections end on completion of a softirq
@@ -566,37 +777,4 @@ static inline void debug_rcu_head_unqueue(struct rcu_head *head)
 }
 #endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */
 
-#ifndef CONFIG_PROVE_RCU
-#define __do_rcu_dereference_check(c) do { } while (0)
-#endif /* #ifdef CONFIG_PROVE_RCU */
-
-#define __rcu_dereference_index_check(p, c) \
-       ({ \
-               typeof(p) _________p1 = ACCESS_ONCE(p); \
-               __do_rcu_dereference_check(c); \
-               smp_read_barrier_depends(); \
-               (_________p1); \
-       })
-
-/**
- * rcu_dereference_index_check() - rcu_dereference for indices with debug checking
- * @p: The pointer to read, prior to dereferencing
- * @c: The conditions under which the dereference will take place
- *
- * Similar to rcu_dereference_check(), but omits the sparse checking.
- * This allows rcu_dereference_index_check() to be used on integers,
- * which can then be used as array indices.  Attempting to use
- * rcu_dereference_check() on an integer will give compiler warnings
- * because the sparse address-space mechanism relies on dereferencing
- * the RCU-protected pointer.  Dereferencing integers is not something
- * that even gcc will put up with.
- *
- * Note that this function does not implicitly check for RCU read-side
- * critical sections.  If this function gains lots of uses, it might
- * make sense to provide versions for each flavor of RCU, but it does
- * not make sense as of early 2010.
- */
-#define rcu_dereference_index_check(p, c) \
-       __rcu_dereference_index_check((p), (c))
-
 #endif /* __LINUX_RCUPDATE_H */
index e2e893144a8450848cf50f8672368aa79c0a0001..13877cb93a6000043f11a6704f2d90b0cc04552d 100644 (file)
 
 #include <linux/cache.h>
 
-void rcu_sched_qs(int cpu);
-void rcu_bh_qs(int cpu);
-static inline void rcu_note_context_switch(int cpu)
-{
-       rcu_sched_qs(cpu);
-}
+#define rcu_init_sched()       do { } while (0)
 
-#define __rcu_read_lock()      preempt_disable()
-#define __rcu_read_unlock()    preempt_enable()
-#define __rcu_read_lock_bh()   local_bh_disable()
-#define __rcu_read_unlock_bh() local_bh_enable()
-#define call_rcu_sched         call_rcu
+#ifdef CONFIG_TINY_RCU
 
-#define rcu_init_sched()       do { } while (0)
-extern void rcu_check_callbacks(int cpu, int user);
+static inline void synchronize_rcu_expedited(void)
+{
+       synchronize_sched();    /* Only one CPU, so pretty fast anyway!!! */
+}
 
-static inline int rcu_needs_cpu(int cpu)
+static inline void rcu_barrier(void)
 {
-       return 0;
+       rcu_barrier_sched();  /* Only one CPU, so only one list of callbacks! */
 }
 
-/*
- * Return the number of grace periods.
- */
-static inline long rcu_batches_completed(void)
+#else /* #ifdef CONFIG_TINY_RCU */
+
+void rcu_barrier(void);
+void synchronize_rcu_expedited(void);
+
+#endif /* #else #ifdef CONFIG_TINY_RCU */
+
+static inline void synchronize_rcu_bh(void)
 {
-       return 0;
+       synchronize_sched();
 }
 
-/*
- * Return the number of bottom-half grace periods.
- */
-static inline long rcu_batches_completed_bh(void)
+static inline void synchronize_rcu_bh_expedited(void)
 {
-       return 0;
+       synchronize_sched();
 }
 
-static inline void rcu_force_quiescent_state(void)
+#ifdef CONFIG_TINY_RCU
+
+static inline void rcu_preempt_note_context_switch(void)
 {
 }
 
-static inline void rcu_bh_force_quiescent_state(void)
+static inline void exit_rcu(void)
 {
 }
 
-static inline void rcu_sched_force_quiescent_state(void)
+static inline int rcu_needs_cpu(int cpu)
 {
+       return 0;
 }
 
-extern void synchronize_sched(void);
+#else /* #ifdef CONFIG_TINY_RCU */
+
+void rcu_preempt_note_context_switch(void);
+extern void exit_rcu(void);
+int rcu_preempt_needs_cpu(void);
 
-static inline void synchronize_rcu(void)
+static inline int rcu_needs_cpu(int cpu)
 {
-       synchronize_sched();
+       return rcu_preempt_needs_cpu();
 }
 
-static inline void synchronize_rcu_bh(void)
+#endif /* #else #ifdef CONFIG_TINY_RCU */
+
+static inline void rcu_note_context_switch(int cpu)
 {
-       synchronize_sched();
+       rcu_sched_qs(cpu);
+       rcu_preempt_note_context_switch();
 }
 
-static inline void synchronize_rcu_expedited(void)
+/*
+ * Return the number of grace periods.
+ */
+static inline long rcu_batches_completed(void)
 {
-       synchronize_sched();
+       return 0;
 }
 
-static inline void synchronize_rcu_bh_expedited(void)
+/*
+ * Return the number of bottom-half grace periods.
+ */
+static inline long rcu_batches_completed_bh(void)
 {
-       synchronize_sched();
+       return 0;
 }
 
-struct notifier_block;
-
-#ifdef CONFIG_NO_HZ
-
-extern void rcu_enter_nohz(void);
-extern void rcu_exit_nohz(void);
-
-#else /* #ifdef CONFIG_NO_HZ */
-
-static inline void rcu_enter_nohz(void)
+static inline void rcu_force_quiescent_state(void)
 {
 }
 
-static inline void rcu_exit_nohz(void)
+static inline void rcu_bh_force_quiescent_state(void)
 {
 }
 
-#endif /* #else #ifdef CONFIG_NO_HZ */
-
-static inline void exit_rcu(void)
+static inline void rcu_sched_force_quiescent_state(void)
 {
 }
 
-static inline int rcu_preempt_depth(void)
+static inline void rcu_cpu_stall_reset(void)
 {
-       return 0;
 }
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
index c0ed1c056f290701def0e0116b6aad72ada30c91..95518e6287946177e0eceb5cbf201ebfcaf0e072 100644 (file)
 #ifndef __LINUX_RCUTREE_H
 #define __LINUX_RCUTREE_H
 
-struct notifier_block;
-
-extern void rcu_sched_qs(int cpu);
-extern void rcu_bh_qs(int cpu);
 extern void rcu_note_context_switch(int cpu);
 extern int rcu_needs_cpu(int cpu);
+extern void rcu_cpu_stall_reset(void);
 
 #ifdef CONFIG_TREE_PREEMPT_RCU
 
-extern void __rcu_read_lock(void);
-extern void __rcu_read_unlock(void);
-extern void synchronize_rcu(void);
 extern void exit_rcu(void);
 
-/*
- * Defined as macro as it is a very low level header
- * included from areas that don't even know about current
- */
-#define rcu_preempt_depth() (current->rcu_read_lock_nesting)
-
 #else /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 
-static inline void __rcu_read_lock(void)
-{
-       preempt_disable();
-}
-
-static inline void __rcu_read_unlock(void)
-{
-       preempt_enable();
-}
-
-#define synchronize_rcu synchronize_sched
-
 static inline void exit_rcu(void)
 {
 }
 
-static inline int rcu_preempt_depth(void)
-{
-       return 0;
-}
-
 #endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */
 
-static inline void __rcu_read_lock_bh(void)
-{
-       local_bh_disable();
-}
-static inline void __rcu_read_unlock_bh(void)
-{
-       local_bh_enable();
-}
-
-extern void call_rcu_sched(struct rcu_head *head,
-                          void (*func)(struct rcu_head *rcu));
 extern void synchronize_rcu_bh(void);
-extern void synchronize_sched(void);
 extern void synchronize_rcu_expedited(void);
 
 static inline void synchronize_rcu_bh_expedited(void)
@@ -95,7 +54,7 @@ static inline void synchronize_rcu_bh_expedited(void)
        synchronize_sched_expedited();
 }
 
-extern void rcu_check_callbacks(int cpu, int user);
+extern void rcu_barrier(void);
 
 extern long rcu_batches_completed(void);
 extern long rcu_batches_completed_bh(void);
@@ -104,18 +63,6 @@ extern void rcu_force_quiescent_state(void);
 extern void rcu_bh_force_quiescent_state(void);
 extern void rcu_sched_force_quiescent_state(void);
 
-#ifdef CONFIG_NO_HZ
-void rcu_enter_nohz(void);
-void rcu_exit_nohz(void);
-#else /* CONFIG_NO_HZ */
-static inline void rcu_enter_nohz(void)
-{
-}
-static inline void rcu_exit_nohz(void)
-{
-}
-#endif /* CONFIG_NO_HZ */
-
 /* A context switch is a grace period for RCU-sched and RCU-bh. */
 static inline int rcu_blocking_is_gp(void)
 {
index bc8c3881c729fb29128b373b8fb6e0ad68feac45..f31db23687828da2e209696c8612cb3f7a195801 100644 (file)
@@ -3,6 +3,7 @@
 
 #ifdef CONFIG_PM_TRACE
 #include <asm/resume-trace.h>
+#include <linux/types.h>
 
 extern int pm_trace_enabled;
 
@@ -14,6 +15,7 @@ static inline int pm_trace_is_enabled(void)
 struct device;
 extern void set_trace_device(struct device *);
 extern void generate_resume_trace(const void *tracedata, unsigned int user);
+extern int show_trace_dev_match(char *buf, size_t size);
 
 #define TRACE_DEVICE(dev) do { \
        if (pm_trace_enabled) \
index 1e2a6db2d7dd03466bf850dc5011860c23e8f9c9..0383601a927c48fa6ccba55de8ebf347573ef8ea 100644 (file)
@@ -875,6 +875,7 @@ enum sched_domain_level {
        SD_LV_NONE = 0,
        SD_LV_SIBLING,
        SD_LV_MC,
+       SD_LV_BOOK,
        SD_LV_CPU,
        SD_LV_NODE,
        SD_LV_ALLNODES,
@@ -1160,6 +1161,13 @@ struct sched_rt_entity {
 
 struct rcu_node;
 
+enum perf_event_task_context {
+       perf_invalid_context = -1,
+       perf_hw_context = 0,
+       perf_sw_context,
+       perf_nr_task_contexts,
+};
+
 struct task_struct {
        volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
        void *stack;
@@ -1202,11 +1210,13 @@ struct task_struct {
        unsigned int policy;
        cpumask_t cpus_allowed;
 
-#ifdef CONFIG_TREE_PREEMPT_RCU
+#ifdef CONFIG_PREEMPT_RCU
        int rcu_read_lock_nesting;
        char rcu_read_unlock_special;
-       struct rcu_node *rcu_blocked_node;
        struct list_head rcu_node_entry;
+#endif /* #ifdef CONFIG_PREEMPT_RCU */
+#ifdef CONFIG_TREE_PREEMPT_RCU
+       struct rcu_node *rcu_blocked_node;
 #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
 
 #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
@@ -1288,9 +1298,9 @@ struct task_struct {
        struct list_head cpu_timers[3];
 
 /* process credentials */
-       const struct cred *real_cred;   /* objective and real subjective task
+       const struct cred __rcu *real_cred; /* objective and real subjective task
                                         * credentials (COW) */
-       const struct cred *cred;        /* effective (overridable) subjective task
+       const struct cred __rcu *cred;  /* effective (overridable) subjective task
                                         * credentials (COW) */
        struct mutex cred_guard_mutex;  /* guard against foreign influences on
                                         * credential calculations
@@ -1418,7 +1428,7 @@ struct task_struct {
 #endif
 #ifdef CONFIG_CGROUPS
        /* Control Group info protected by css_set_lock */
-       struct css_set *cgroups;
+       struct css_set __rcu *cgroups;
        /* cg_list protected by css_set_lock and tsk->alloc_lock */
        struct list_head cg_list;
 #endif
@@ -1431,7 +1441,7 @@ struct task_struct {
        struct futex_pi_state *pi_state_cache;
 #endif
 #ifdef CONFIG_PERF_EVENTS
-       struct perf_event_context *perf_event_ctxp;
+       struct perf_event_context *perf_event_ctxp[perf_nr_task_contexts];
        struct mutex perf_event_mutex;
        struct list_head perf_event_list;
 #endif
@@ -1681,8 +1691,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 /*
  * Per process flags
  */
-#define PF_ALIGNWARN   0x00000001      /* Print alignment warning msgs */
-                                       /* Not implemented yet, only for 486*/
+#define PF_KSOFTIRQD   0x00000001      /* I am ksoftirqd */
 #define PF_STARTING    0x00000002      /* being created */
 #define PF_EXITING     0x00000004      /* getting shut down */
 #define PF_EXITPIDONE  0x00000008      /* pi exit done on shut down */
@@ -1740,7 +1749,7 @@ extern void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *
 #define tsk_used_math(p) ((p)->flags & PF_USED_MATH)
 #define used_math() tsk_used_math(current)
 
-#ifdef CONFIG_TREE_PREEMPT_RCU
+#ifdef CONFIG_PREEMPT_RCU
 
 #define RCU_READ_UNLOCK_BLOCKED (1 << 0) /* blocked while in RCU read-side. */
 #define RCU_READ_UNLOCK_NEED_QS (1 << 1) /* RCU core needs CPU response. */
@@ -1749,7 +1758,9 @@ static inline void rcu_copy_process(struct task_struct *p)
 {
        p->rcu_read_lock_nesting = 0;
        p->rcu_read_unlock_special = 0;
+#ifdef CONFIG_TREE_PREEMPT_RCU
        p->rcu_blocked_node = NULL;
+#endif
        INIT_LIST_HEAD(&p->rcu_node_entry);
 }
 
@@ -1826,6 +1837,19 @@ extern void sched_clock_idle_sleep_event(void);
 extern void sched_clock_idle_wakeup_event(u64 delta_ns);
 #endif
 
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+/*
+ * An i/f to runtime opt-in for irq time accounting based off of sched_clock.
+ * The reason for this explicit opt-in is not to have perf penalty with
+ * slow sched_clocks.
+ */
+extern void enable_sched_clock_irqtime(void);
+extern void disable_sched_clock_irqtime(void);
+#else
+static inline void enable_sched_clock_irqtime(void) {}
+static inline void disable_sched_clock_irqtime(void) {}
+#endif
+
 extern unsigned long long
 task_sched_runtime(struct task_struct *task);
 extern unsigned long long thread_group_sched_runtime(struct task_struct *task);
@@ -2367,9 +2391,9 @@ extern int __cond_resched_lock(spinlock_t *lock);
 
 extern int __cond_resched_softirq(void);
 
-#define cond_resched_softirq() ({                              \
-       __might_sleep(__FILE__, __LINE__, SOFTIRQ_OFFSET);      \
-       __cond_resched_softirq();                               \
+#define cond_resched_softirq() ({                                      \
+       __might_sleep(__FILE__, __LINE__, SOFTIRQ_DISABLE_OFFSET);      \
+       __cond_resched_softirq();                                       \
 })
 
 /*
index a22219afff092952bbe276cb9da1d0509ddf196c..b8246a8df7d2dc2ecc864ac192d694b369dd12d6 100644 (file)
@@ -74,7 +74,7 @@ extern int cap_file_mmap(struct file *file, unsigned long reqprot,
 extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags);
 extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                          unsigned long arg4, unsigned long arg5);
-extern int cap_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp);
+extern int cap_task_setscheduler(struct task_struct *p);
 extern int cap_task_setioprio(struct task_struct *p, int ioprio);
 extern int cap_task_setnice(struct task_struct *p, int nice);
 extern int cap_syslog(int type, bool from_file);
@@ -959,6 +959,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     Sets the new child socket's sid to the openreq sid.
  * @inet_conn_established:
  *     Sets the connection's peersid to the secmark on skb.
+ * @secmark_relabel_packet:
+ *     check if the process should be allowed to relabel packets to the given secid
+ * @security_secmark_refcount_inc
+ *     tells the LSM to increment the number of secmark labeling rules loaded
+ * @security_secmark_refcount_dec
+ *     tells the LSM to decrement the number of secmark labeling rules loaded
  * @req_classify_flow:
  *     Sets the flow's sid to the openreq sid.
  * @tun_dev_create:
@@ -1279,9 +1285,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     Return 0 if permission is granted.
  *
  * @secid_to_secctx:
- *     Convert secid to security context.
+ *     Convert secid to security context.  If secdata is NULL the length of
+ *     the result will be returned in seclen, but no secdata will be returned.
+ *     This does mean that the length could change between calls to check the
+ *     length and the next call which actually allocates and returns the secdata.
  *     @secid contains the security ID.
  *     @secdata contains the pointer that stores the converted security context.
+ *     @seclen pointer which contains the length of the data
  * @secctx_to_secid:
  *     Convert security context to secid.
  *     @secid contains the pointer to the generated security ID.
@@ -1501,8 +1511,7 @@ struct security_operations {
        int (*task_getioprio) (struct task_struct *p);
        int (*task_setrlimit) (struct task_struct *p, unsigned int resource,
                        struct rlimit *new_rlim);
-       int (*task_setscheduler) (struct task_struct *p, int policy,
-                                 struct sched_param *lp);
+       int (*task_setscheduler) (struct task_struct *p);
        int (*task_getscheduler) (struct task_struct *p);
        int (*task_movememory) (struct task_struct *p);
        int (*task_kill) (struct task_struct *p,
@@ -1594,6 +1603,9 @@ struct security_operations {
                                  struct request_sock *req);
        void (*inet_csk_clone) (struct sock *newsk, const struct request_sock *req);
        void (*inet_conn_established) (struct sock *sk, struct sk_buff *skb);
+       int (*secmark_relabel_packet) (u32 secid);
+       void (*secmark_refcount_inc) (void);
+       void (*secmark_refcount_dec) (void);
        void (*req_classify_flow) (const struct request_sock *req, struct flowi *fl);
        int (*tun_dev_create)(void);
        void (*tun_dev_post_create)(struct sock *sk);
@@ -1752,8 +1764,7 @@ int security_task_setioprio(struct task_struct *p, int ioprio);
 int security_task_getioprio(struct task_struct *p);
 int security_task_setrlimit(struct task_struct *p, unsigned int resource,
                struct rlimit *new_rlim);
-int security_task_setscheduler(struct task_struct *p,
-                               int policy, struct sched_param *lp);
+int security_task_setscheduler(struct task_struct *p);
 int security_task_getscheduler(struct task_struct *p);
 int security_task_movememory(struct task_struct *p);
 int security_task_kill(struct task_struct *p, struct siginfo *info,
@@ -2320,11 +2331,9 @@ static inline int security_task_setrlimit(struct task_struct *p,
        return 0;
 }
 
-static inline int security_task_setscheduler(struct task_struct *p,
-                                            int policy,
-                                            struct sched_param *lp)
+static inline int security_task_setscheduler(struct task_struct *p)
 {
-       return cap_task_setscheduler(p, policy, lp);
+       return cap_task_setscheduler(p);
 }
 
 static inline int security_task_getscheduler(struct task_struct *p)
@@ -2551,6 +2560,9 @@ void security_inet_csk_clone(struct sock *newsk,
                        const struct request_sock *req);
 void security_inet_conn_established(struct sock *sk,
                        struct sk_buff *skb);
+int security_secmark_relabel_packet(u32 secid);
+void security_secmark_refcount_inc(void);
+void security_secmark_refcount_dec(void);
 int security_tun_dev_create(void);
 void security_tun_dev_post_create(struct sock *sk);
 int security_tun_dev_attach(struct sock *sk);
@@ -2705,6 +2717,19 @@ static inline void security_inet_conn_established(struct sock *sk,
 {
 }
 
+static inline int security_secmark_relabel_packet(u32 secid)
+{
+       return 0;
+}
+
+static inline void security_secmark_refcount_inc(void)
+{
+}
+
+static inline void security_secmark_refcount_dec(void)
+{
+}
+
 static inline int security_tun_dev_create(void)
 {
        return 0;
index 82e0f26a12996a1bcce6efddd07e734313162c19..44f4596126904f7d0357654c999ed2ae13258c82 100644 (file)
@@ -20,75 +20,12 @@ struct kern_ipc_perm;
 
 #ifdef CONFIG_SECURITY_SELINUX
 
-/**
- *     selinux_string_to_sid - map a security context string to a security ID
- *     @str: the security context string to be mapped
- *     @sid: ID value returned via this.
- *
- *     Returns 0 if successful, with the SID stored in sid.  A value
- *     of zero for sid indicates no SID could be determined (but no error
- *     occurred).
- */
-int selinux_string_to_sid(char *str, u32 *sid);
-
-/**
- *     selinux_secmark_relabel_packet_permission - secmark permission check
- *     @sid: SECMARK ID value to be applied to network packet
- *
- *     Returns 0 if the current task is allowed to set the SECMARK label of
- *     packets with the supplied security ID.  Note that it is implicit that
- *     the packet is always being relabeled from the default unlabeled value,
- *     and that the access control decision is made in the AVC.
- */
-int selinux_secmark_relabel_packet_permission(u32 sid);
-
-/**
- *     selinux_secmark_refcount_inc - increments the secmark use counter
- *
- *     SELinux keeps track of the current SECMARK targets in use so it knows
- *     when to apply SECMARK label access checks to network packets.  This
- *     function incements this reference count to indicate that a new SECMARK
- *     target has been configured.
- */
-void selinux_secmark_refcount_inc(void);
-
-/**
- *     selinux_secmark_refcount_dec - decrements the secmark use counter
- *
- *     SELinux keeps track of the current SECMARK targets in use so it knows
- *     when to apply SECMARK label access checks to network packets.  This
- *     function decements this reference count to indicate that one of the
- *     existing SECMARK targets has been removed/flushed.
- */
-void selinux_secmark_refcount_dec(void);
-
 /**
  * selinux_is_enabled - is SELinux enabled?
  */
 bool selinux_is_enabled(void);
 #else
 
-static inline int selinux_string_to_sid(const char *str, u32 *sid)
-{
-       *sid = 0;
-       return 0;
-}
-
-static inline int selinux_secmark_relabel_packet_permission(u32 sid)
-{
-       return 0;
-}
-
-static inline void selinux_secmark_refcount_inc(void)
-{
-       return;
-}
-
-static inline void selinux_secmark_refcount_dec(void)
-{
-       return;
-}
-
 static inline bool selinux_is_enabled(void)
 {
        return false;
index f8854655860e3a10f5d708b9b749c43ead2bd48d..80e535897de6ce85d26627144875a4914ff2aacc 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/preempt.h>
 #include <linux/linkage.h>
 #include <linux/compiler.h>
+#include <linux/irqflags.h>
 #include <linux/thread_info.h>
 #include <linux/kernel.h>
 #include <linux/stringify.h>
index 4d5d2f546dbff11ee6a4abb6ad2cc53770d45aeb..58971e891f489950102d41f75bea118a22604f23 100644 (file)
@@ -108,19 +108,43 @@ static inline int srcu_read_lock_held(struct srcu_struct *sp)
 #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */
 
 /**
- * srcu_dereference - fetch SRCU-protected pointer with checking
+ * srcu_dereference_check - fetch SRCU-protected pointer for later dereferencing
+ * @p: the pointer to fetch and protect for later dereferencing
+ * @sp: pointer to the srcu_struct, which is used to check that we
+ *     really are in an SRCU read-side critical section.
+ * @c: condition to check for update-side use
  *
- * Makes rcu_dereference_check() do the dirty work.
+ * If PROVE_RCU is enabled, invoking this outside of an RCU read-side
+ * critical section will result in an RCU-lockdep splat, unless @c evaluates
+ * to 1.  The @c argument will normally be a logical expression containing
+ * lockdep_is_held() calls.
  */
-#define srcu_dereference(p, sp) \
-               rcu_dereference_check(p, srcu_read_lock_held(sp))
+#define srcu_dereference_check(p, sp, c) \
+       __rcu_dereference_check((p), srcu_read_lock_held(sp) || (c), __rcu)
+
+/**
+ * srcu_dereference - fetch SRCU-protected pointer for later dereferencing
+ * @p: the pointer to fetch and protect for later dereferencing
+ * @sp: pointer to the srcu_struct, which is used to check that we
+ *     really are in an SRCU read-side critical section.
+ *
+ * Makes rcu_dereference_check() do the dirty work.  If PROVE_RCU
+ * is enabled, invoking this outside of an RCU read-side critical
+ * section will result in an RCU-lockdep splat.
+ */
+#define srcu_dereference(p, sp) srcu_dereference_check((p), (sp), 0)
 
 /**
  * srcu_read_lock - register a new reader for an SRCU-protected structure.
  * @sp: srcu_struct in which to register the new reader.
  *
  * Enter an SRCU read-side critical section.  Note that SRCU read-side
- * critical sections may be nested.
+ * critical sections may be nested.  However, it is illegal to
+ * call anything that waits on an SRCU grace period for the same
+ * srcu_struct, whether directly or indirectly.  Please note that
+ * one way to indirectly wait on an SRCU grace period is to acquire
+ * a mutex that is held elsewhere while calling synchronize_srcu() or
+ * synchronize_srcu_expedited().
  */
 static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp)
 {
index 6b524a0d02e42b14419c5ae75133360a1f4874a5..1808960c50595908935455ca90a80fc02e421ef0 100644 (file)
@@ -126,8 +126,8 @@ int __stop_machine(int (*fn)(void *), void *data, const struct cpumask *cpus);
 
 #else   /* CONFIG_STOP_MACHINE && CONFIG_SMP */
 
-static inline int stop_machine(int (*fn)(void *), void *data,
-                              const struct cpumask *cpus)
+static inline int __stop_machine(int (*fn)(void *), void *data,
+                                const struct cpumask *cpus)
 {
        int ret;
        local_irq_disable();
@@ -136,5 +136,11 @@ static inline int stop_machine(int (*fn)(void *), void *data,
        return ret;
 }
 
+static inline int stop_machine(int (*fn)(void *), void *data,
+                              const struct cpumask *cpus)
+{
+       return __stop_machine(fn, data, cpus);
+}
+
 #endif /* CONFIG_STOP_MACHINE && CONFIG_SMP */
 #endif /* _LINUX_STOP_MACHINE */
index 671538d25bc15b623155f2b7b7fd269ce394b5d6..8eee9dbbfe7aaddbdb5aaebfbaf5ad82669f846d 100644 (file)
@@ -69,7 +69,7 @@ struct gss_cl_ctx {
        enum rpc_gss_proc       gc_proc;
        u32                     gc_seq;
        spinlock_t              gc_seq_lock;
-       struct gss_ctx          *gc_gss_ctx;
+       struct gss_ctx __rcu    *gc_gss_ctx;
        struct xdr_netobj       gc_wire_ctx;
        u32                     gc_win;
        unsigned long           gc_expiry;
@@ -80,7 +80,7 @@ struct gss_upcall_msg;
 struct gss_cred {
        struct rpc_cred         gc_base;
        enum rpc_gss_svc        gc_service;
-       struct gss_cl_ctx       *gc_ctx;
+       struct gss_cl_ctx __rcu *gc_ctx;
        struct gss_upcall_msg   *gc_upcall;
        unsigned long           gc_upcall_timestamp;
        unsigned char           gc_machine_cred : 1;
index 4af270ec2204424db83ee330a74e891adb99959b..26697514c5ece07d72f6e07022f43ee86d187de0 100644 (file)
@@ -293,8 +293,8 @@ extern int unregister_pm_notifier(struct notifier_block *nb);
 extern bool events_check_enabled;
 
 extern bool pm_check_wakeup_events(void);
-extern bool pm_get_wakeup_count(unsigned long *count);
-extern bool pm_save_wakeup_count(unsigned long count);
+extern bool pm_get_wakeup_count(unsigned int *count);
+extern bool pm_save_wakeup_count(unsigned int count);
 #else /* !CONFIG_PM_SLEEP */
 
 static inline int register_pm_notifier(struct notifier_block *nb)
@@ -308,6 +308,8 @@ static inline int unregister_pm_notifier(struct notifier_block *nb)
 }
 
 #define pm_notifier(fn, pri)   do { (void)(fn); } while (0)
+
+static inline bool pm_check_wakeup_events(void) { return true; }
 #endif /* !CONFIG_PM_SLEEP */
 
 extern struct mutex pm_mutex;
index 96eb576d82fdadbd6a3cce0253325c733f6603f3..30b881555fa576fc4a0fb9a82f8418fac72aefa2 100644 (file)
@@ -164,6 +164,10 @@ int sysfs_add_file_to_group(struct kobject *kobj,
                        const struct attribute *attr, const char *group);
 void sysfs_remove_file_from_group(struct kobject *kobj,
                        const struct attribute *attr, const char *group);
+int sysfs_merge_group(struct kobject *kobj,
+                      const struct attribute_group *grp);
+void sysfs_unmerge_group(struct kobject *kobj,
+                      const struct attribute_group *grp);
 
 void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
 void sysfs_notify_dirent(struct sysfs_dirent *sd);
@@ -302,6 +306,17 @@ static inline void sysfs_remove_file_from_group(struct kobject *kobj,
 {
 }
 
+static inline int sysfs_merge_group(struct kobject *kobj,
+                      const struct attribute_group *grp)
+{
+       return 0;
+}
+
+static inline void sysfs_unmerge_group(struct kobject *kobj,
+                      const struct attribute_group *grp)
+{
+}
+
 static inline void sysfs_notify(struct kobject *kobj, const char *dir,
                                const char *attr)
 {
index a8cc4e13434c4261ae8ab536566b23fcd777286a..c90696544176902262699186b32dc1c515311a15 100644 (file)
@@ -23,12 +23,12 @@ struct restart_block {
                };
                /* For futex_wait and futex_wait_requeue_pi */
                struct {
-                       u32 *uaddr;
+                       u32 __user *uaddr;
                        u32 val;
                        u32 flags;
                        u32 bitset;
                        u64 time;
-                       u32 *uaddr2;
+                       u32 __user *uaddr2;
                } futex;
                /* For nanosleep */
                struct {
index 64e084ff5e5c9a6e68257068821b79110a760f02..b91a40e847d236d9046dc3154a7e7a58ea594776 100644 (file)
@@ -201,6 +201,12 @@ int arch_update_cpu_topology(void);
        .balance_interval       = 64,                                   \
 }
 
+#ifdef CONFIG_SCHED_BOOK
+#ifndef SD_BOOK_INIT
+#error Please define an appropriate SD_BOOK_INIT in include/asm/topology.h!!!
+#endif
+#endif /* CONFIG_SCHED_BOOK */
+
 #ifdef CONFIG_NUMA
 #ifndef SD_NODE_INIT
 #error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
index 103d1b61aacba635bb7c81cef9e32b70fe220bb7..a4a90b6726ce6129b43174609fb3e35a2bd088ae 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/rcupdate.h>
+#include <linux/jump_label.h>
 
 struct module;
 struct tracepoint;
@@ -145,7 +146,9 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin,
        extern struct tracepoint __tracepoint_##name;                   \
        static inline void trace_##name(proto)                          \
        {                                                               \
-               if (unlikely(__tracepoint_##name.state))                \
+               JUMP_LABEL(&__tracepoint_##name.state, do_trace);       \
+               return;                                                 \
+do_trace:                                                              \
                        __DO_TRACE(&__tracepoint_##name,                \
                                TP_PROTO(data_proto),                   \
                                TP_ARGS(data_args));                    \
index ef6c24a529e1a23188a27b60a0d6e73e84fb7003..a4dc5b027bd9cc7731b7fab1146508896c0b215c 100644 (file)
@@ -51,7 +51,8 @@ static inline u32 task_cls_classid(struct task_struct *p)
                return 0;
 
        rcu_read_lock();
-       id = rcu_dereference(net_cls_subsys_id);
+       id = rcu_dereference_index_check(net_cls_subsys_id,
+                                        rcu_read_lock_held());
        if (id >= 0)
                classid = container_of(task_subsys_state(p, id),
                                       struct cgroup_cls_state, css)->classid;
index e624dae54fa49b7d713b78641c7f18c2e3cfbae2..caf17db87dbc8983f4aeef52a54c2424a7d21054 100644 (file)
@@ -75,7 +75,7 @@ struct nf_conntrack_helper;
 /* nf_conn feature for connections that have a helper */
 struct nf_conn_help {
        /* Helper. if any */
-       struct nf_conntrack_helper *helper;
+       struct nf_conntrack_helper __rcu *helper;
 
        union nf_conntrack_help help;
 
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
deleted file mode 100644 (file)
index 68d8bde..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * cs.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.
- *
- * The initial developer of the original code is David A. Hinds
- * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
- * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
- *
- * (C) 1999             David A. Hinds
- */
-
-#ifndef _LINUX_CS_H
-#define _LINUX_CS_H
-
-#ifdef __KERNEL__
-#include <linux/interrupt.h>
-#endif
-
-/* ModifyConfiguration */
-typedef struct modconf_t {
-    u_int      Attributes;
-    u_int      Vcc, Vpp1, Vpp2;
-} modconf_t;
-
-/* Attributes for ModifyConfiguration */
-#define CONF_IRQ_CHANGE_VALID  0x0100
-#define CONF_VCC_CHANGE_VALID  0x0200
-#define CONF_VPP1_CHANGE_VALID 0x0400
-#define CONF_VPP2_CHANGE_VALID 0x0800
-#define CONF_IO_CHANGE_WIDTH   0x1000
-
-/* For RequestConfiguration */
-typedef struct config_req_t {
-    u_int      Attributes;
-    u_int      Vpp; /* both Vpp1 and Vpp2 */
-    u_int      IntType;
-    u_int      ConfigBase;
-    u_char     Status, Pin, Copy, ExtStatus;
-    u_char     ConfigIndex;
-    u_int      Present;
-} config_req_t;
-
-/* Attributes for RequestConfiguration */
-#define CONF_ENABLE_IRQ                0x01
-#define CONF_ENABLE_DMA                0x02
-#define CONF_ENABLE_SPKR       0x04
-#define CONF_ENABLE_PULSE_IRQ  0x08
-#define CONF_VALID_CLIENT      0x100
-
-/* IntType field */
-#define INT_MEMORY             0x01
-#define INT_MEMORY_AND_IO      0x02
-#define INT_CARDBUS            0x04
-#define INT_ZOOMED_VIDEO       0x08
-
-/* Configuration registers present */
-#define PRESENT_OPTION         0x001
-#define PRESENT_STATUS         0x002
-#define PRESENT_PIN_REPLACE    0x004
-#define PRESENT_COPY           0x008
-#define PRESENT_EXT_STATUS     0x010
-#define PRESENT_IOBASE_0       0x020
-#define PRESENT_IOBASE_1       0x040
-#define PRESENT_IOBASE_2       0x080
-#define PRESENT_IOBASE_3       0x100
-#define PRESENT_IOSIZE         0x200
-
-/* For RequestWindow */
-typedef struct win_req_t {
-    u_int      Attributes;
-    u_long     Base;
-    u_int      Size;
-    u_int      AccessSpeed;
-} win_req_t;
-
-/* Attributes for RequestWindow */
-#define WIN_MEMORY_TYPE_CM     0x00 /* default */
-#define WIN_MEMORY_TYPE_AM     0x20 /* MAP_ATTRIB */
-#define WIN_DATA_WIDTH_8       0x00 /* default */
-#define WIN_DATA_WIDTH_16      0x02 /* MAP_16BIT */
-#define WIN_ENABLE             0x01 /* MAP_ACTIVE */
-#define WIN_USE_WAIT           0x40 /* MAP_USE_WAIT */
-
-#define WIN_FLAGS_MAP          0x63 /* MAP_ATTRIB | MAP_16BIT | MAP_ACTIVE |
-                                       MAP_USE_WAIT */
-#define WIN_FLAGS_REQ          0x1c /* mapping to socket->win[i]:
-                                       0x04 -> 0
-                                       0x08 -> 1
-                                       0x0c -> 2
-                                       0x10 -> 3 */
-
-#endif /* _LINUX_CS_H */
index 70c58ed2278c43f80a355b7aac9c30f40bd2a315..d830c87ff0a724fc73a9e5b93158b8b3588eef92 100644 (file)
 
 #ifdef __KERNEL__
 #include <linux/device.h>
+#include <linux/interrupt.h>
 #include <pcmcia/ss.h>
 #include <asm/atomic.h>
 
+
 /*
  * PCMCIA device drivers (16-bit cards only; 32-bit cards require CardBus
  * a.k.a. PCI drivers
@@ -36,8 +38,6 @@ struct pcmcia_device;
 struct config_t;
 struct net_device;
 
-typedef struct resource *window_handle_t;
-
 /* dynamic device IDs for PCMCIA device drivers. See
  * Documentation/pcmcia/driver.txt for details.
 */
@@ -47,6 +47,8 @@ struct pcmcia_dynids {
 };
 
 struct pcmcia_driver {
+       const char              *name;
+
        int (*probe)            (struct pcmcia_device *dev);
        void (*remove)          (struct pcmcia_device *dev);
 
@@ -90,15 +92,17 @@ struct pcmcia_device {
 
        struct list_head        socket_device_list;
 
-       /* deprecated, will be cleaned up soon */
-       config_req_t            conf;
-       window_handle_t         win;
-
        /* device setup */
        unsigned int            irq;
        struct resource         *resource[PCMCIA_NUM_RESOURCES];
+       resource_size_t         card_addr;      /* for the 1st IOMEM resource */
+       unsigned int            vpp;
 
-       unsigned int            io_lines; /* number of I/O lines */
+       unsigned int            config_flags;   /* CONF_ENABLE_ flags below */
+       unsigned int            config_base;
+       unsigned int            config_index;
+       unsigned int            config_regs;    /* PRESENT_ flags below */
+       unsigned int            io_lines;       /* number of I/O lines */
 
        /* Is the device suspended? */
        u16                     suspended:1;
@@ -174,9 +178,6 @@ int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse);
 /* loop CIS entries for valid configuration */
 int pcmcia_loop_config(struct pcmcia_device *p_dev,
                       int      (*conf_check)   (struct pcmcia_device *p_dev,
-                                                cistpl_cftable_entry_t *cf,
-                                                cistpl_cftable_entry_t *dflt,
-                                                unsigned int vcc,
                                                 void *priv_data),
                       void *priv_data);
 
@@ -206,16 +207,17 @@ pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev,
 int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev,
                                irq_handler_t handler);
 
-int pcmcia_request_configuration(struct pcmcia_device *p_dev,
-                                config_req_t *req);
+int pcmcia_enable_device(struct pcmcia_device *p_dev);
 
-int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req,
-                         window_handle_t *wh);
-int pcmcia_release_window(struct pcmcia_device *p_dev, window_handle_t win);
-int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t win,
+int pcmcia_request_window(struct pcmcia_device *p_dev, struct resource *res,
+                       unsigned int speed);
+int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res);
+int pcmcia_map_mem_page(struct pcmcia_device *p_dev, struct resource *res,
                        unsigned int offset);
 
-int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
+int pcmcia_fixup_vpp(struct pcmcia_device *p_dev, unsigned char new_vpp);
+int pcmcia_fixup_iowidth(struct pcmcia_device *p_dev);
+
 void pcmcia_disable_device(struct pcmcia_device *p_dev);
 
 /* IO ports */
@@ -224,15 +226,46 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev);
 #define IO_DATA_PATH_WIDTH_16  0x08
 #define IO_DATA_PATH_WIDTH_AUTO        0x10
 
-/* convert flag found in cfgtable to data path width parameter */
-static inline int pcmcia_io_cfg_data_width(unsigned int flags)
-{
-       if (!(flags & CISTPL_IO_8BIT))
-               return IO_DATA_PATH_WIDTH_16;
-       if (!(flags & CISTPL_IO_16BIT))
-               return IO_DATA_PATH_WIDTH_8;
-       return IO_DATA_PATH_WIDTH_AUTO;
-}
+/* IO memory */
+#define WIN_MEMORY_TYPE_CM     0x00 /* default */
+#define WIN_MEMORY_TYPE_AM     0x20 /* MAP_ATTRIB */
+#define WIN_DATA_WIDTH_8       0x00 /* default */
+#define WIN_DATA_WIDTH_16      0x02 /* MAP_16BIT */
+#define WIN_ENABLE             0x01 /* MAP_ACTIVE */
+#define WIN_USE_WAIT           0x40 /* MAP_USE_WAIT */
+
+#define WIN_FLAGS_MAP          0x63 /* MAP_ATTRIB | MAP_16BIT | MAP_ACTIVE |
+                                       MAP_USE_WAIT */
+#define WIN_FLAGS_REQ          0x1c /* mapping to socket->win[i]:
+                                       0x04 -> 0
+                                       0x08 -> 1
+                                       0x0c -> 2
+                                       0x10 -> 3 */
+
+/* config_reg{ister}s present for this PCMCIA device */
+#define PRESENT_OPTION         0x001
+#define PRESENT_STATUS         0x002
+#define PRESENT_PIN_REPLACE    0x004
+#define PRESENT_COPY           0x008
+#define PRESENT_EXT_STATUS     0x010
+#define PRESENT_IOBASE_0       0x020
+#define PRESENT_IOBASE_1       0x040
+#define PRESENT_IOBASE_2       0x080
+#define PRESENT_IOBASE_3       0x100
+#define PRESENT_IOSIZE         0x200
+
+/* flags to be passed to pcmcia_enable_device() */
+#define CONF_ENABLE_IRQ         0x0001
+#define CONF_ENABLE_SPKR        0x0002
+#define CONF_ENABLE_PULSE_IRQ   0x0004
+#define CONF_ENABLE_ESR         0x0008
+
+/* flags used by pcmcia_loop_config() autoconfiguration */
+#define CONF_AUTO_CHECK_VCC    0x0100 /* check for matching Vcc? */
+#define CONF_AUTO_SET_VPP      0x0200 /* set Vpp? */
+#define CONF_AUTO_AUDIO                0x0400 /* enable audio line? */
+#define CONF_AUTO_SET_IO       0x0800 /* set ->resource[0,1] */
+#define CONF_AUTO_SET_IOMEM    0x1000 /* set ->resource[2] */
 
 #endif /* __KERNEL__ */
 
index 626b63c33d9e0e374387ca106063d19048899bb5..731cde010f424250cc8fe5f45aae772b0f2877f4 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/sched.h>       /* task_struct, completion */
 #include <linux/mutex.h>
 
-#include <pcmcia/cs.h>
 #ifdef CONFIG_CARDBUS
 #include <linux/pci.h>
 #endif
index 0e4cfb694fe70630457af67e1b1bc568f56c9b09..1c09820df58564f8d0430d996998edc6f8d893c0 100644 (file)
@@ -5,7 +5,9 @@
 #define _TRACE_IRQ_H
 
 #include <linux/tracepoint.h>
-#include <linux/interrupt.h>
+
+struct irqaction;
+struct softirq_action;
 
 #define softirq_name(sirq) { sirq##_SOFTIRQ, #sirq }
 #define show_softirq_name(val)                         \
@@ -84,56 +86,62 @@ TRACE_EVENT(irq_handler_exit,
 
 DECLARE_EVENT_CLASS(softirq,
 
-       TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+       TP_PROTO(unsigned int vec_nr),
 
-       TP_ARGS(h, vec),
+       TP_ARGS(vec_nr),
 
        TP_STRUCT__entry(
-               __field(        int,    vec                     )
+               __field(        unsigned int,   vec     )
        ),
 
        TP_fast_assign(
-               __entry->vec = (int)(h - vec);
+               __entry->vec = vec_nr;
        ),
 
-       TP_printk("vec=%d [action=%s]", __entry->vec,
+       TP_printk("vec=%u [action=%s]", __entry->vec,
                  show_softirq_name(__entry->vec))
 );
 
 /**
  * softirq_entry - called immediately before the softirq handler
- * @h: pointer to struct softirq_action
- * @vec: pointer to first struct softirq_action in softirq_vec array
+ * @vec_nr:  softirq vector number
  *
- * The @h parameter, contains a pointer to the struct softirq_action
- * which has a pointer to the action handler that is called. By subtracting
- * the @vec pointer from the @h pointer, we can determine the softirq
- * number. Also, when used in combination with the softirq_exit tracepoint
- * we can determine the softirq latency.
+ * When used in combination with the softirq_exit tracepoint
+ * we can determine the softirq handler runtine.
  */
 DEFINE_EVENT(softirq, softirq_entry,
 
-       TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+       TP_PROTO(unsigned int vec_nr),
 
-       TP_ARGS(h, vec)
+       TP_ARGS(vec_nr)
 );
 
 /**
  * softirq_exit - called immediately after the softirq handler returns
- * @h: pointer to struct softirq_action
- * @vec: pointer to first struct softirq_action in softirq_vec array
+ * @vec_nr:  softirq vector number
  *
- * The @h parameter contains a pointer to the struct softirq_action
- * that has handled the softirq. By subtracting the @vec pointer from
- * the @h pointer, we can determine the softirq number. Also, when used in
- * combination with the softirq_entry tracepoint we can determine the softirq
- * latency.
+ * When used in combination with the softirq_entry tracepoint
+ * we can determine the softirq handler runtine.
  */
 DEFINE_EVENT(softirq, softirq_exit,
 
-       TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+       TP_PROTO(unsigned int vec_nr),
+
+       TP_ARGS(vec_nr)
+);
+
+/**
+ * softirq_raise - called immediately when a softirq is raised
+ * @vec_nr:  softirq vector number
+ *
+ * When used in combination with the softirq_entry tracepoint
+ * we can determine the softirq raise to run latency.
+ */
+DEFINE_EVENT(softirq, softirq_raise,
+
+       TP_PROTO(unsigned int vec_nr),
 
-       TP_ARGS(h, vec)
+       TP_ARGS(vec_nr)
 );
 
 #endif /*  _TRACE_IRQ_H */
index 188deca2f3c7721a1baac60cc07e8d7006442c71..8fe1e93f531dd81a8e549689a1b8e9b551231e9e 100644 (file)
@@ -6,10 +6,31 @@
 
 #include <linux/netdevice.h>
 #include <linux/tracepoint.h>
+#include <linux/ftrace.h>
+
+#define NO_DEV "(no_device)"
+
+TRACE_EVENT(napi_poll,
 
-DECLARE_TRACE(napi_poll,
        TP_PROTO(struct napi_struct *napi),
-       TP_ARGS(napi));
+
+       TP_ARGS(napi),
+
+       TP_STRUCT__entry(
+               __field(        struct napi_struct *,   napi)
+               __string(       dev_name, napi->dev ? napi->dev->name : NO_DEV)
+       ),
+
+       TP_fast_assign(
+               __entry->napi = napi;
+               __assign_str(dev_name, napi->dev ? napi->dev->name : NO_DEV);
+       ),
+
+       TP_printk("napi poll on napi struct %p for device %s",
+               __entry->napi, __get_str(dev_name))
+);
+
+#undef NO_DEV
 
 #endif /* _TRACE_NAPI_H_ */
 
diff --git a/include/trace/events/net.h b/include/trace/events/net.h
new file mode 100644 (file)
index 0000000..5f247f5
--- /dev/null
@@ -0,0 +1,82 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM net
+
+#if !defined(_TRACE_NET_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_NET_H
+
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(net_dev_xmit,
+
+       TP_PROTO(struct sk_buff *skb,
+                int rc),
+
+       TP_ARGS(skb, rc),
+
+       TP_STRUCT__entry(
+               __field(        void *,         skbaddr         )
+               __field(        unsigned int,   len             )
+               __field(        int,            rc              )
+               __string(       name,           skb->dev->name  )
+       ),
+
+       TP_fast_assign(
+               __entry->skbaddr = skb;
+               __entry->len = skb->len;
+               __entry->rc = rc;
+               __assign_str(name, skb->dev->name);
+       ),
+
+       TP_printk("dev=%s skbaddr=%p len=%u rc=%d",
+               __get_str(name), __entry->skbaddr, __entry->len, __entry->rc)
+);
+
+DECLARE_EVENT_CLASS(net_dev_template,
+
+       TP_PROTO(struct sk_buff *skb),
+
+       TP_ARGS(skb),
+
+       TP_STRUCT__entry(
+               __field(        void *,         skbaddr         )
+               __field(        unsigned int,   len             )
+               __string(       name,           skb->dev->name  )
+       ),
+
+       TP_fast_assign(
+               __entry->skbaddr = skb;
+               __entry->len = skb->len;
+               __assign_str(name, skb->dev->name);
+       ),
+
+       TP_printk("dev=%s skbaddr=%p len=%u",
+               __get_str(name), __entry->skbaddr, __entry->len)
+)
+
+DEFINE_EVENT(net_dev_template, net_dev_queue,
+
+       TP_PROTO(struct sk_buff *skb),
+
+       TP_ARGS(skb)
+);
+
+DEFINE_EVENT(net_dev_template, netif_receive_skb,
+
+       TP_PROTO(struct sk_buff *skb),
+
+       TP_ARGS(skb)
+);
+
+DEFINE_EVENT(net_dev_template, netif_rx,
+
+       TP_PROTO(struct sk_buff *skb),
+
+       TP_ARGS(skb)
+);
+#endif /* _TRACE_NET_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 35a2a6e7bf1e74992b8b83b242c4a507fed4246f..286784d69b8f480343244d8046327a5a7d9883d9 100644 (file)
 #ifndef _TRACE_POWER_ENUM_
 #define _TRACE_POWER_ENUM_
 enum {
-       POWER_NONE = 0,
-       POWER_CSTATE = 1,
-       POWER_PSTATE = 2,
+       POWER_NONE      = 0,
+       POWER_CSTATE    = 1,    /* C-State */
+       POWER_PSTATE    = 2,    /* Fequency change or DVFS */
+       POWER_SSTATE    = 3,    /* Suspend */
 };
 #endif
 
+/*
+ * The power events are used for cpuidle & suspend (power_start, power_end)
+ *  and for cpufreq (power_frequency)
+ */
 DECLARE_EVENT_CLASS(power,
 
        TP_PROTO(unsigned int type, unsigned int state, unsigned int cpu_id),
@@ -70,6 +75,85 @@ TRACE_EVENT(power_end,
 
 );
 
+/*
+ * The clock events are used for clock enable/disable and for
+ *  clock rate change
+ */
+DECLARE_EVENT_CLASS(clock,
+
+       TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id),
+
+       TP_ARGS(name, state, cpu_id),
+
+       TP_STRUCT__entry(
+               __string(       name,           name            )
+               __field(        u64,            state           )
+               __field(        u64,            cpu_id          )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, name);
+               __entry->state = state;
+               __entry->cpu_id = cpu_id;
+       ),
+
+       TP_printk("%s state=%lu cpu_id=%lu", __get_str(name),
+               (unsigned long)__entry->state, (unsigned long)__entry->cpu_id)
+);
+
+DEFINE_EVENT(clock, clock_enable,
+
+       TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id),
+
+       TP_ARGS(name, state, cpu_id)
+);
+
+DEFINE_EVENT(clock, clock_disable,
+
+       TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id),
+
+       TP_ARGS(name, state, cpu_id)
+);
+
+DEFINE_EVENT(clock, clock_set_rate,
+
+       TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id),
+
+       TP_ARGS(name, state, cpu_id)
+);
+
+/*
+ * The power domain events are used for power domains transitions
+ */
+DECLARE_EVENT_CLASS(power_domain,
+
+       TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id),
+
+       TP_ARGS(name, state, cpu_id),
+
+       TP_STRUCT__entry(
+               __string(       name,           name            )
+               __field(        u64,            state           )
+               __field(        u64,            cpu_id          )
+       ),
+
+       TP_fast_assign(
+               __assign_str(name, name);
+               __entry->state = state;
+               __entry->cpu_id = cpu_id;
+),
+
+       TP_printk("%s state=%lu cpu_id=%lu", __get_str(name),
+               (unsigned long)__entry->state, (unsigned long)__entry->cpu_id)
+);
+
+DEFINE_EVENT(power_domain, power_domain_target,
+
+       TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id),
+
+       TP_ARGS(name, state, cpu_id)
+);
+
 #endif /* _TRACE_POWER_H */
 
 /* This part must be outside protection */
index 9208c92aeab5eee575b21f3000ea8034f6c00788..f6334782a593847907b82fcfc5756040b1bd6ff8 100644 (file)
@@ -362,6 +362,35 @@ TRACE_EVENT(sched_stat_runtime,
                        (unsigned long long)__entry->vruntime)
 );
 
+/*
+ * Tracepoint for showing priority inheritance modifying a tasks
+ * priority.
+ */
+TRACE_EVENT(sched_pi_setprio,
+
+       TP_PROTO(struct task_struct *tsk, int newprio),
+
+       TP_ARGS(tsk, newprio),
+
+       TP_STRUCT__entry(
+               __array( char,  comm,   TASK_COMM_LEN   )
+               __field( pid_t, pid                     )
+               __field( int,   oldprio                 )
+               __field( int,   newprio                 )
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN);
+               __entry->pid            = tsk->pid;
+               __entry->oldprio        = tsk->prio;
+               __entry->newprio        = newprio;
+       ),
+
+       TP_printk("comm=%s pid=%d oldprio=%d newprio=%d",
+                       __entry->comm, __entry->pid,
+                       __entry->oldprio, __entry->newprio)
+);
+
 #endif /* _TRACE_SCHED_H */
 
 /* This part must be outside protection */
index 4b2be6dc76f091647eb30f30a40a49218def8682..75ce9d500d8e3c62dbfffbc0acafca13d11d90aa 100644 (file)
@@ -35,6 +35,23 @@ TRACE_EVENT(kfree_skb,
                __entry->skbaddr, __entry->protocol, __entry->location)
 );
 
+TRACE_EVENT(consume_skb,
+
+       TP_PROTO(struct sk_buff *skb),
+
+       TP_ARGS(skb),
+
+       TP_STRUCT__entry(
+               __field(        void *, skbaddr )
+       ),
+
+       TP_fast_assign(
+               __entry->skbaddr = skb;
+       ),
+
+       TP_printk("skbaddr=%p", __entry->skbaddr)
+);
+
 TRACE_EVENT(skb_copy_datagram_iovec,
 
        TP_PROTO(const struct sk_buff *skb, int len),
index 2de5b1cbadd9e47138f879d23cc4d2d5066d32d7..36890f0c8456db1eb212abc46a876e145fa8e0ca 100644 (file)
@@ -21,6 +21,13 @@ config CONSTRUCTORS
        depends on !UML
        default y
 
+config HAVE_IRQ_WORK
+       bool
+
+config IRQ_WORK
+       bool
+       depends on HAVE_IRQ_WORK
+
 menu "General setup"
 
 config EXPERIMENTAL
@@ -332,6 +339,8 @@ config AUDIT_TREE
        depends on AUDITSYSCALL
        select FSNOTIFY
 
+source "kernel/irq/Kconfig"
+
 menu "RCU Subsystem"
 
 choice
@@ -340,6 +349,7 @@ choice
 
 config TREE_RCU
        bool "Tree-based hierarchical RCU"
+       depends on !PREEMPT && SMP
        help
          This option selects the RCU implementation that is
          designed for very large SMP system with hundreds or
@@ -347,7 +357,7 @@ config TREE_RCU
          smaller systems.
 
 config TREE_PREEMPT_RCU
-       bool "Preemptable tree-based hierarchical RCU"
+       bool "Preemptible tree-based hierarchical RCU"
        depends on PREEMPT
        help
          This option selects the RCU implementation that is
@@ -365,8 +375,22 @@ config TINY_RCU
          is not required.  This option greatly reduces the
          memory footprint of RCU.
 
+config TINY_PREEMPT_RCU
+       bool "Preemptible UP-only small-memory-footprint RCU"
+       depends on !SMP && PREEMPT
+       help
+         This option selects the RCU implementation that is designed
+         for real-time UP systems.  This option greatly reduces the
+         memory footprint of RCU.
+
 endchoice
 
+config PREEMPT_RCU
+       def_bool ( TREE_PREEMPT_RCU || TINY_PREEMPT_RCU )
+       help
+         This option enables preemptible-RCU code that is common between
+         the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations.
+
 config RCU_TRACE
        bool "Enable tracing for RCU"
        depends on TREE_RCU || TREE_PREEMPT_RCU
@@ -387,9 +411,12 @@ config RCU_FANOUT
        help
          This option controls the fanout of hierarchical implementations
          of RCU, allowing RCU to work efficiently on machines with
-         large numbers of CPUs.  This value must be at least the cube
-         root of NR_CPUS, which allows NR_CPUS up to 32,768 for 32-bit
-         systems and up to 262,144 for 64-bit systems.
+         large numbers of CPUs.  This value must be at least the fourth
+         root of NR_CPUS, which allows NR_CPUS to be insanely large.
+         The default value of RCU_FANOUT should be used for production
+         systems, but if you are stress-testing the RCU implementation
+         itself, small RCU_FANOUT values allow you to test large-system
+         code paths on small(er) systems.
 
          Select a specific number if testing RCU itself.
          Take the default if unsure.
@@ -987,6 +1014,7 @@ config PERF_EVENTS
        default y if (PROFILING || PERF_COUNTERS)
        depends on HAVE_PERF_EVENTS
        select ANON_INODES
+       select IRQ_WORK
        help
          Enable kernel support for various performance events provided
          by software and hardware.
index 94ab488039aab1dde97d442f785046475f09c978..9684c9670b48ef2157919ea97bea37c81e32f2f8 100644 (file)
@@ -556,7 +556,6 @@ asmlinkage void __init start_kernel(void)
 
        local_irq_disable();
        early_boot_irqs_off();
-       early_init_irq_lock_class();
 
 /*
  * Interrupts are still disabled. Do necessary setups, then
index 0b72d1a74be07c25b99a8da670ec4cfb0963cf77..0b5ff083fa22fa381a6fc1f092a824f255bda01a 100644 (file)
@@ -10,8 +10,7 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
            kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
            hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
            notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
-           async.o range.o
-obj-$(CONFIG_HAVE_EARLY_RES) += early_res.o
+           async.o range.o jump_label.o
 obj-y += groups.o
 
 ifdef CONFIG_FUNCTION_TRACER
@@ -23,6 +22,7 @@ CFLAGS_REMOVE_rtmutex-debug.o = -pg
 CFLAGS_REMOVE_cgroup-debug.o = -pg
 CFLAGS_REMOVE_sched_clock.o = -pg
 CFLAGS_REMOVE_perf_event.o = -pg
+CFLAGS_REMOVE_irq_work.o = -pg
 endif
 
 obj-$(CONFIG_FREEZER) += freezer.o
@@ -86,6 +86,7 @@ obj-$(CONFIG_TREE_RCU) += rcutree.o
 obj-$(CONFIG_TREE_PREEMPT_RCU) += rcutree.o
 obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o
 obj-$(CONFIG_TINY_RCU) += rcutiny.o
+obj-$(CONFIG_TINY_PREEMPT_RCU) += rcutiny.o
 obj-$(CONFIG_RELAY) += relay.o
 obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
 obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
@@ -100,6 +101,7 @@ obj-$(CONFIG_TRACING) += trace/
 obj-$(CONFIG_X86_DS) += trace/
 obj-$(CONFIG_RING_BUFFER) += trace/
 obj-$(CONFIG_SMP) += sched_cpupri.o
+obj-$(CONFIG_IRQ_WORK) += irq_work.o
 obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
 obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o
index c9483d8f6140ed6cb4e06fa6139e2aeb907b3d47..291ba3d04beab08f0edc4a0239bae956941e50d9 100644 (file)
@@ -138,7 +138,7 @@ struct css_id {
         * is called after synchronize_rcu(). But for safe use, css_is_removed()
         * css_tryget() should be used for avoiding race.
         */
-       struct cgroup_subsys_state *css;
+       struct cgroup_subsys_state __rcu *css;
        /*
         * ID of this css.
         */
index b23c0979bbe7212a748a9aac70697e92ee54f448..51b143e2a07a49603d9aa462728f6a45032c01d9 100644 (file)
@@ -1397,7 +1397,7 @@ static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cont,
        if (tsk->flags & PF_THREAD_BOUND)
                return -EINVAL;
 
-       ret = security_task_setscheduler(tsk, 0, NULL);
+       ret = security_task_setscheduler(tsk);
        if (ret)
                return ret;
        if (threadgroup) {
@@ -1405,7 +1405,7 @@ static int cpuset_can_attach(struct cgroup_subsys *ss, struct cgroup *cont,
 
                rcu_read_lock();
                list_for_each_entry_rcu(c, &tsk->thread_group, thread_group) {
-                       ret = security_task_setscheduler(c, 0, NULL);
+                       ret = security_task_setscheduler(c);
                        if (ret) {
                                rcu_read_unlock();
                                return ret;
diff --git a/kernel/early_res.c b/kernel/early_res.c
deleted file mode 100644 (file)
index 7bfae88..0000000
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * early_res, could be used to replace bootmem
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/mm.h>
-#include <linux/early_res.h>
-#include <linux/slab.h>
-#include <linux/kmemleak.h>
-
-/*
- * Early reserved memory areas.
- */
-/*
- * need to make sure this one is bigger enough before
- * find_fw_memmap_area could be used
- */
-#define MAX_EARLY_RES_X 32
-
-struct early_res {
-       u64 start, end;
-       char name[15];
-       char overlap_ok;
-};
-static struct early_res early_res_x[MAX_EARLY_RES_X] __initdata;
-
-static int max_early_res __initdata = MAX_EARLY_RES_X;
-static struct early_res *early_res __initdata = &early_res_x[0];
-static int early_res_count __initdata;
-
-static int __init find_overlapped_early(u64 start, u64 end)
-{
-       int i;
-       struct early_res *r;
-
-       for (i = 0; i < max_early_res && early_res[i].end; i++) {
-               r = &early_res[i];
-               if (end > r->start && start < r->end)
-                       break;
-       }
-
-       return i;
-}
-
-/*
- * Drop the i-th range from the early reservation map,
- * by copying any higher ranges down one over it, and
- * clearing what had been the last slot.
- */
-static void __init drop_range(int i)
-{
-       int j;
-
-       for (j = i + 1; j < max_early_res && early_res[j].end; j++)
-               ;
-
-       memmove(&early_res[i], &early_res[i + 1],
-              (j - 1 - i) * sizeof(struct early_res));
-
-       early_res[j - 1].end = 0;
-       early_res_count--;
-}
-
-static void __init drop_range_partial(int i, u64 start, u64 end)
-{
-       u64 common_start, common_end;
-       u64 old_start, old_end;
-
-       old_start = early_res[i].start;
-       old_end = early_res[i].end;
-       common_start = max(old_start, start);
-       common_end = min(old_end, end);
-
-       /* no overlap ? */
-       if (common_start >= common_end)
-               return;
-
-       if (old_start < common_start) {
-               /* make head segment */
-               early_res[i].end = common_start;
-               if (old_end > common_end) {
-                       char name[15];
-
-                       /*
-                        * Save a local copy of the name, since the
-                        * early_res array could get resized inside
-                        * reserve_early_without_check() ->
-                        * __check_and_double_early_res(), which would
-                        * make the current name pointer invalid.
-                        */
-                       strncpy(name, early_res[i].name,
-                                        sizeof(early_res[i].name) - 1);
-                       /* add another for left over on tail */
-                       reserve_early_without_check(common_end, old_end, name);
-               }
-               return;
-       } else {
-               if (old_end > common_end) {
-                       /* reuse the entry for tail left */
-                       early_res[i].start = common_end;
-                       return;
-               }
-               /* all covered */
-               drop_range(i);
-       }
-}
-
-/*
- * Split any existing ranges that:
- *  1) are marked 'overlap_ok', and
- *  2) overlap with the stated range [start, end)
- * into whatever portion (if any) of the existing range is entirely
- * below or entirely above the stated range.  Drop the portion
- * of the existing range that overlaps with the stated range,
- * which will allow the caller of this routine to then add that
- * stated range without conflicting with any existing range.
- */
-static void __init drop_overlaps_that_are_ok(u64 start, u64 end)
-{
-       int i;
-       struct early_res *r;
-       u64 lower_start, lower_end;
-       u64 upper_start, upper_end;
-       char name[15];
-
-       for (i = 0; i < max_early_res && early_res[i].end; i++) {
-               r = &early_res[i];
-
-               /* Continue past non-overlapping ranges */
-               if (end <= r->start || start >= r->end)
-                       continue;
-
-               /*
-                * Leave non-ok overlaps as is; let caller
-                * panic "Overlapping early reservations"
-                * when it hits this overlap.
-                */
-               if (!r->overlap_ok)
-                       return;
-
-               /*
-                * We have an ok overlap.  We will drop it from the early
-                * reservation map, and add back in any non-overlapping
-                * portions (lower or upper) as separate, overlap_ok,
-                * non-overlapping ranges.
-                */
-
-               /* 1. Note any non-overlapping (lower or upper) ranges. */
-               strncpy(name, r->name, sizeof(name) - 1);
-
-               lower_start = lower_end = 0;
-               upper_start = upper_end = 0;
-               if (r->start < start) {
-                       lower_start = r->start;
-                       lower_end = start;
-               }
-               if (r->end > end) {
-                       upper_start = end;
-                       upper_end = r->end;
-               }
-
-               /* 2. Drop the original ok overlapping range */
-               drop_range(i);
-
-               i--;            /* resume for-loop on copied down entry */
-
-               /* 3. Add back in any non-overlapping ranges. */
-               if (lower_end)
-                       reserve_early_overlap_ok(lower_start, lower_end, name);
-               if (upper_end)
-                       reserve_early_overlap_ok(upper_start, upper_end, name);
-       }
-}
-
-static void __init __reserve_early(u64 start, u64 end, char *name,
-                                               int overlap_ok)
-{
-       int i;
-       struct early_res *r;
-
-       i = find_overlapped_early(start, end);
-       if (i >= max_early_res)
-               panic("Too many early reservations");
-       r = &early_res[i];
-       if (r->end)
-               panic("Overlapping early reservations "
-                     "%llx-%llx %s to %llx-%llx %s\n",
-                     start, end - 1, name ? name : "", r->start,
-                     r->end - 1, r->name);
-       r->start = start;
-       r->end = end;
-       r->overlap_ok = overlap_ok;
-       if (name)
-               strncpy(r->name, name, sizeof(r->name) - 1);
-       early_res_count++;
-}
-
-/*
- * A few early reservtations come here.
- *
- * The 'overlap_ok' in the name of this routine does -not- mean it
- * is ok for these reservations to overlap an earlier reservation.
- * Rather it means that it is ok for subsequent reservations to
- * overlap this one.
- *
- * Use this entry point to reserve early ranges when you are doing
- * so out of "Paranoia", reserving perhaps more memory than you need,
- * just in case, and don't mind a subsequent overlapping reservation
- * that is known to be needed.
- *
- * The drop_overlaps_that_are_ok() call here isn't really needed.
- * It would be needed if we had two colliding 'overlap_ok'
- * reservations, so that the second such would not panic on the
- * overlap with the first.  We don't have any such as of this
- * writing, but might as well tolerate such if it happens in
- * the future.
- */
-void __init reserve_early_overlap_ok(u64 start, u64 end, char *name)
-{
-       drop_overlaps_that_are_ok(start, end);
-       __reserve_early(start, end, name, 1);
-}
-
-static void __init __check_and_double_early_res(u64 ex_start, u64 ex_end)
-{
-       u64 start, end, size, mem;
-       struct early_res *new;
-
-       /* do we have enough slots left ? */
-       if ((max_early_res - early_res_count) > max(max_early_res/8, 2))
-               return;
-
-       /* double it */
-       mem = -1ULL;
-       size = sizeof(struct early_res) * max_early_res * 2;
-       if (early_res == early_res_x)
-               start = 0;
-       else
-               start = early_res[0].end;
-       end = ex_start;
-       if (start + size < end)
-               mem = find_fw_memmap_area(start, end, size,
-                                        sizeof(struct early_res));
-       if (mem == -1ULL) {
-               start = ex_end;
-               end = get_max_mapped();
-               if (start + size < end)
-                       mem = find_fw_memmap_area(start, end, size,
-                                                sizeof(struct early_res));
-       }
-       if (mem == -1ULL)
-               panic("can not find more space for early_res array");
-
-       new = __va(mem);
-       /* save the first one for own */
-       new[0].start = mem;
-       new[0].end = mem + size;
-       new[0].overlap_ok = 0;
-       /* copy old to new */
-       if (early_res == early_res_x) {
-               memcpy(&new[1], &early_res[0],
-                        sizeof(struct early_res) * max_early_res);
-               memset(&new[max_early_res+1], 0,
-                        sizeof(struct early_res) * (max_early_res - 1));
-               early_res_count++;
-       } else {
-               memcpy(&new[1], &early_res[1],
-                        sizeof(struct early_res) * (max_early_res - 1));
-               memset(&new[max_early_res], 0,
-                        sizeof(struct early_res) * max_early_res);
-       }
-       memset(&early_res[0], 0, sizeof(struct early_res) * max_early_res);
-       early_res = new;
-       max_early_res *= 2;
-       printk(KERN_DEBUG "early_res array is doubled to %d at [%llx - %llx]\n",
-               max_early_res, mem, mem + size - 1);
-}
-
-/*
- * Most early reservations come here.
- *
- * We first have drop_overlaps_that_are_ok() drop any pre-existing
- * 'overlap_ok' ranges, so that we can then reserve this memory
- * range without risk of panic'ing on an overlapping overlap_ok
- * early reservation.
- */
-void __init reserve_early(u64 start, u64 end, char *name)
-{
-       if (start >= end)
-               return;
-
-       __check_and_double_early_res(start, end);
-
-       drop_overlaps_that_are_ok(start, end);
-       __reserve_early(start, end, name, 0);
-}
-
-void __init reserve_early_without_check(u64 start, u64 end, char *name)
-{
-       struct early_res *r;
-
-       if (start >= end)
-               return;
-
-       __check_and_double_early_res(start, end);
-
-       r = &early_res[early_res_count];
-
-       r->start = start;
-       r->end = end;
-       r->overlap_ok = 0;
-       if (name)
-               strncpy(r->name, name, sizeof(r->name) - 1);
-       early_res_count++;
-}
-
-void __init free_early(u64 start, u64 end)
-{
-       struct early_res *r;
-       int i;
-
-       kmemleak_free_part(__va(start), end - start);
-
-       i = find_overlapped_early(start, end);
-       r = &early_res[i];
-       if (i >= max_early_res || r->end != end || r->start != start)
-               panic("free_early on not reserved area: %llx-%llx!",
-                        start, end - 1);
-
-       drop_range(i);
-}
-
-void __init free_early_partial(u64 start, u64 end)
-{
-       struct early_res *r;
-       int i;
-
-       kmemleak_free_part(__va(start), end - start);
-
-       if (start == end)
-               return;
-
-       if (WARN_ONCE(start > end, "  wrong range [%#llx, %#llx]\n", start, end))
-               return;
-
-try_next:
-       i = find_overlapped_early(start, end);
-       if (i >= max_early_res)
-               return;
-
-       r = &early_res[i];
-       /* hole ? */
-       if (r->end >= end && r->start <= start) {
-               drop_range_partial(i, start, end);
-               return;
-       }
-
-       drop_range_partial(i, start, end);
-       goto try_next;
-}
-
-#ifdef CONFIG_NO_BOOTMEM
-static void __init subtract_early_res(struct range *range, int az)
-{
-       int i, count;
-       u64 final_start, final_end;
-       int idx = 0;
-
-       count  = 0;
-       for (i = 0; i < max_early_res && early_res[i].end; i++)
-               count++;
-
-       /* need to skip first one ?*/
-       if (early_res != early_res_x)
-               idx = 1;
-
-#define DEBUG_PRINT_EARLY_RES 1
-
-#if DEBUG_PRINT_EARLY_RES
-       printk(KERN_INFO "Subtract (%d early reservations)\n", count);
-#endif
-       for (i = idx; i < count; i++) {
-               struct early_res *r = &early_res[i];
-#if DEBUG_PRINT_EARLY_RES
-               printk(KERN_INFO "  #%d [%010llx - %010llx] %15s\n", i,
-                       r->start, r->end, r->name);
-#endif
-               final_start = PFN_DOWN(r->start);
-               final_end = PFN_UP(r->end);
-               if (final_start >= final_end)
-                       continue;
-               subtract_range(range, az, final_start, final_end);
-       }
-
-}
-
-int __init get_free_all_memory_range(struct range **rangep, int nodeid)
-{
-       int i, count;
-       u64 start = 0, end;
-       u64 size;
-       u64 mem;
-       struct range *range;
-       int nr_range;
-
-       count  = 0;
-       for (i = 0; i < max_early_res && early_res[i].end; i++)
-               count++;
-
-       count *= 2;
-
-       size = sizeof(struct range) * count;
-       end = get_max_mapped();
-#ifdef MAX_DMA32_PFN
-       if (end > (MAX_DMA32_PFN << PAGE_SHIFT))
-               start = MAX_DMA32_PFN << PAGE_SHIFT;
-#endif
-       mem = find_fw_memmap_area(start, end, size, sizeof(struct range));
-       if (mem == -1ULL)
-               panic("can not find more space for range free");
-
-       range = __va(mem);
-       /* use early_node_map[] and early_res to get range array at first */
-       memset(range, 0, size);
-       nr_range = 0;
-
-       /* need to go over early_node_map to find out good range for node */
-       nr_range = add_from_early_node_map(range, count, nr_range, nodeid);
-#ifdef CONFIG_X86_32
-       subtract_range(range, count, max_low_pfn, -1ULL);
-#endif
-       subtract_early_res(range, count);
-       nr_range = clean_sort_range(range, count);
-
-       /* need to clear it ? */
-       if (nodeid == MAX_NUMNODES) {
-               memset(&early_res[0], 0,
-                        sizeof(struct early_res) * max_early_res);
-               early_res = NULL;
-               max_early_res = 0;
-       }
-
-       *rangep = range;
-       return nr_range;
-}
-#else
-void __init early_res_to_bootmem(u64 start, u64 end)
-{
-       int i, count;
-       u64 final_start, final_end;
-       int idx = 0;
-
-       count  = 0;
-       for (i = 0; i < max_early_res && early_res[i].end; i++)
-               count++;
-
-       /* need to skip first one ?*/
-       if (early_res != early_res_x)
-               idx = 1;
-
-       printk(KERN_INFO "(%d/%d early reservations) ==> bootmem [%010llx - %010llx]\n",
-                        count - idx, max_early_res, start, end);
-       for (i = idx; i < count; i++) {
-               struct early_res *r = &early_res[i];
-               printk(KERN_INFO "  #%d [%010llx - %010llx] %16s", i,
-                       r->start, r->end, r->name);
-               final_start = max(start, r->start);
-               final_end = min(end, r->end);
-               if (final_start >= final_end) {
-                       printk(KERN_CONT "\n");
-                       continue;
-               }
-               printk(KERN_CONT " ==> [%010llx - %010llx]\n",
-                       final_start, final_end);
-               reserve_bootmem_generic(final_start, final_end - final_start,
-                               BOOTMEM_DEFAULT);
-       }
-       /* clear them */
-       memset(&early_res[0], 0, sizeof(struct early_res) * max_early_res);
-       early_res = NULL;
-       max_early_res = 0;
-       early_res_count = 0;
-}
-#endif
-
-/* Check for already reserved areas */
-static inline int __init bad_addr(u64 *addrp, u64 size, u64 align)
-{
-       int i;
-       u64 addr = *addrp;
-       int changed = 0;
-       struct early_res *r;
-again:
-       i = find_overlapped_early(addr, addr + size);
-       r = &early_res[i];
-       if (i < max_early_res && r->end) {
-               *addrp = addr = round_up(r->end, align);
-               changed = 1;
-               goto again;
-       }
-       return changed;
-}
-
-/* Check for already reserved areas */
-static inline int __init bad_addr_size(u64 *addrp, u64 *sizep, u64 align)
-{
-       int i;
-       u64 addr = *addrp, last;
-       u64 size = *sizep;
-       int changed = 0;
-again:
-       last = addr + size;
-       for (i = 0; i < max_early_res && early_res[i].end; i++) {
-               struct early_res *r = &early_res[i];
-               if (last > r->start && addr < r->start) {
-                       size = r->start - addr;
-                       changed = 1;
-                       goto again;
-               }
-               if (last > r->end && addr < r->end) {
-                       addr = round_up(r->end, align);
-                       size = last - addr;
-                       changed = 1;
-                       goto again;
-               }
-               if (last <= r->end && addr >= r->start) {
-                       (*sizep)++;
-                       return 0;
-               }
-       }
-       if (changed) {
-               *addrp = addr;
-               *sizep = size;
-       }
-       return changed;
-}
-
-/*
- * Find a free area with specified alignment in a specific range.
- * only with the area.between start to end is active range from early_node_map
- * so they are good as RAM
- */
-u64 __init find_early_area(u64 ei_start, u64 ei_last, u64 start, u64 end,
-                        u64 size, u64 align)
-{
-       u64 addr, last;
-
-       addr = round_up(ei_start, align);
-       if (addr < start)
-               addr = round_up(start, align);
-       if (addr >= ei_last)
-               goto out;
-       while (bad_addr(&addr, size, align) && addr+size <= ei_last)
-               ;
-       last = addr + size;
-       if (last > ei_last)
-               goto out;
-       if (last > end)
-               goto out;
-
-       return addr;
-
-out:
-       return -1ULL;
-}
-
-u64 __init find_early_area_size(u64 ei_start, u64 ei_last, u64 start,
-                        u64 *sizep, u64 align)
-{
-       u64 addr, last;
-
-       addr = round_up(ei_start, align);
-       if (addr < start)
-               addr = round_up(start, align);
-       if (addr >= ei_last)
-               goto out;
-       *sizep = ei_last - addr;
-       while (bad_addr_size(&addr, sizep, align) && addr + *sizep <= ei_last)
-               ;
-       last = addr + *sizep;
-       if (last > ei_last)
-               goto out;
-
-       return addr;
-
-out:
-       return -1ULL;
-}
index 03120229db2802929065a210930e41c7fa701ba0..e2bdf37f9fdea71a15acb3523ec20b63a6aa42d3 100644 (file)
@@ -149,9 +149,7 @@ static void delayed_put_task_struct(struct rcu_head *rhp)
 {
        struct task_struct *tsk = container_of(rhp, struct task_struct, rcu);
 
-#ifdef CONFIG_PERF_EVENTS
-       WARN_ON_ONCE(tsk->perf_event_ctxp);
-#endif
+       perf_event_delayed_put(tsk);
        trace_sched_process_free(tsk);
        put_task_struct(tsk);
 }
index 6a3a5fa1526d87d16b362e20d7d62e6809285c18..a118bf160e0b05a4b24404beda19d07adead5161 100644 (file)
@@ -91,6 +91,7 @@ struct futex_pi_state {
 
 /**
  * struct futex_q - The hashed futex queue entry, one per waiting task
+ * @list:              priority-sorted list of tasks waiting on this futex
  * @task:              the task waiting on the futex
  * @lock_ptr:          the hash bucket lock
  * @key:               the key the futex is hashed on
@@ -104,7 +105,7 @@ struct futex_pi_state {
  *
  * A futex_q has a woken state, just like tasks have TASK_RUNNING.
  * It is considered woken when plist_node_empty(&q->list) || q->lock_ptr == 0.
- * The order of wakup is always to make the first condition true, then
+ * The order of wakeup is always to make the first condition true, then
  * the second.
  *
  * PI futexes are typically woken before they are removed from the hash list via
@@ -295,7 +296,7 @@ void put_futex_key(int fshared, union futex_key *key)
  * Slow path to fixup the fault we just took in the atomic write
  * access to @uaddr.
  *
- * We have no generic implementation of a non destructive write to the
+ * We have no generic implementation of a non-destructive write to the
  * user address. We know that we faulted in the atomic pagefault
  * disabled section so we can as well avoid the #PF overhead by
  * calling get_user_pages() right away.
@@ -515,7 +516,7 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb,
                         */
                        pi_state = this->pi_state;
                        /*
-                        * Userspace might have messed up non PI and PI futexes
+                        * Userspace might have messed up non-PI and PI futexes
                         */
                        if (unlikely(!pi_state))
                                return -EINVAL;
@@ -736,8 +737,8 @@ static void wake_futex(struct futex_q *q)
 
        /*
         * We set q->lock_ptr = NULL _before_ we wake up the task. If
-        * a non futex wake up happens on another CPU then the task
-        * might exit and p would dereference a non existing task
+        * a non-futex wake up happens on another CPU then the task
+        * might exit and p would dereference a non-existing task
         * struct. Prevent this by holding a reference on p across the
         * wake up.
         */
@@ -1131,11 +1132,13 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex,
 
 /**
  * futex_requeue() - Requeue waiters from uaddr1 to uaddr2
- * uaddr1:     source futex user address
- * uaddr2:     target futex user address
- * nr_wake:    number of waiters to wake (must be 1 for requeue_pi)
- * nr_requeue: number of waiters to requeue (0-INT_MAX)
- * requeue_pi: if we are attempting to requeue from a non-pi futex to a
+ * @uaddr1:    source futex user address
+ * @fshared:   0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
+ * @uaddr2:    target futex user address
+ * @nr_wake:   number of waiters to wake (must be 1 for requeue_pi)
+ * @nr_requeue:        number of waiters to requeue (0-INT_MAX)
+ * @cmpval:    @uaddr1 expected value (or %NULL)
+ * @requeue_pi:        if we are attempting to requeue from a non-pi futex to a
  *             pi futex (pi to pi requeue is not supported)
  *
  * Requeue waiters on uaddr1 to uaddr2. In the requeue_pi case, try to acquire
@@ -1360,10 +1363,10 @@ out:
 
 /* The key must be already stored in q->key. */
 static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
+       __acquires(&hb->lock)
 {
        struct futex_hash_bucket *hb;
 
-       get_futex_key_refs(&q->key);
        hb = hash_futex(&q->key);
        q->lock_ptr = &hb->lock;
 
@@ -1373,9 +1376,9 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q)
 
 static inline void
 queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb)
+       __releases(&hb->lock)
 {
        spin_unlock(&hb->lock);
-       drop_futex_key_refs(&q->key);
 }
 
 /**
@@ -1391,6 +1394,7 @@ queue_unlock(struct futex_q *q, struct futex_hash_bucket *hb)
  * an example).
  */
 static inline void queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
+       __releases(&hb->lock)
 {
        int prio;
 
@@ -1471,6 +1475,7 @@ retry:
  * and dropped here.
  */
 static void unqueue_me_pi(struct futex_q *q)
+       __releases(q->lock_ptr)
 {
        WARN_ON(plist_node_empty(&q->list));
        plist_del(&q->list, &q->list.plist);
@@ -1480,8 +1485,6 @@ static void unqueue_me_pi(struct futex_q *q)
        q->pi_state = NULL;
 
        spin_unlock(q->lock_ptr);
-
-       drop_futex_key_refs(&q->key);
 }
 
 /*
@@ -1812,7 +1815,10 @@ static int futex_wait(u32 __user *uaddr, int fshared,
        }
 
 retry:
-       /* Prepare to wait on uaddr. */
+       /*
+        * Prepare to wait on uaddr. On success, holds hb lock and increments
+        * q.key refs.
+        */
        ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
        if (ret)
                goto out;
@@ -1822,28 +1828,27 @@ retry:
 
        /* If we were woken (and unqueued), we succeeded, whatever. */
        ret = 0;
+       /* unqueue_me() drops q.key ref */
        if (!unqueue_me(&q))
-               goto out_put_key;
+               goto out;
        ret = -ETIMEDOUT;
        if (to && !to->task)
-               goto out_put_key;
+               goto out;
 
        /*
         * We expect signal_pending(current), but we might be the
         * victim of a spurious wakeup as well.
         */
-       if (!signal_pending(current)) {
-               put_futex_key(fshared, &q.key);
+       if (!signal_pending(current))
                goto retry;
-       }
 
        ret = -ERESTARTSYS;
        if (!abs_time)
-               goto out_put_key;
+               goto out;
 
        restart = &current_thread_info()->restart_block;
        restart->fn = futex_wait_restart;
-       restart->futex.uaddr = (u32 *)uaddr;
+       restart->futex.uaddr = uaddr;
        restart->futex.val = val;
        restart->futex.time = abs_time->tv64;
        restart->futex.bitset = bitset;
@@ -1856,8 +1861,6 @@ retry:
 
        ret = -ERESTART_RESTARTBLOCK;
 
-out_put_key:
-       put_futex_key(fshared, &q.key);
 out:
        if (to) {
                hrtimer_cancel(&to->timer);
@@ -1869,7 +1872,7 @@ out:
 
 static long futex_wait_restart(struct restart_block *restart)
 {
-       u32 __user *uaddr = (u32 __user *)restart->futex.uaddr;
+       u32 __user *uaddr = restart->futex.uaddr;
        int fshared = 0;
        ktime_t t, *tp = NULL;
 
@@ -2236,7 +2239,10 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
        q.rt_waiter = &rt_waiter;
        q.requeue_pi_key = &key2;
 
-       /* Prepare to wait on uaddr. */
+       /*
+        * Prepare to wait on uaddr. On success, increments q.key (key1) ref
+        * count.
+        */
        ret = futex_wait_setup(uaddr, val, fshared, &q, &hb);
        if (ret)
                goto out_key2;
@@ -2254,7 +2260,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, int fshared,
         * In order for us to be here, we know our q.key == key2, and since
         * we took the hb->lock above, we also know that futex_requeue() has
         * completed and we no longer have to concern ourselves with a wakeup
-        * race with the atomic proxy lock acquition by the requeue code.
+        * race with the atomic proxy lock acquisition by the requeue code. The
+        * futex_requeue dropped our key1 reference and incremented our key2
+        * reference count.
         */
 
        /* Check if the requeue code acquired the second futex for us. */
@@ -2458,7 +2466,7 @@ retry:
  */
 static inline int fetch_robust_entry(struct robust_list __user **entry,
                                     struct robust_list __user * __user *head,
-                                    int *pi)
+                                    unsigned int *pi)
 {
        unsigned long uentry;
 
@@ -2647,7 +2655,7 @@ static int __init futex_init(void)
         * of the complex code paths. Also we want to prevent
         * registration of robust lists in that case. NULL is
         * guaranteed to fault and we get -EFAULT on functional
-        * implementation, the non functional ones will return
+        * implementation, the non-functional ones will return
         * -ENOSYS.
         */
        curval = cmpxchg_futex_value_locked(NULL, 0, 0);
index d49afb2395e5cab17dd85417c95741c60c12a4cf..06da4dfc339b7362716858f92bec749962241808 100644 (file)
@@ -19,7 +19,7 @@
  */
 static inline int
 fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry,
-                  compat_uptr_t __user *head, int *pi)
+                  compat_uptr_t __user *head, unsigned int *pi)
 {
        if (get_user(*uentry, head))
                return -EFAULT;
index 0c642d51aac2d8ab82c782a786eb13b90c0985c1..53ead174da2f0a7c7849df4ef81b60a96fe7c4f6 100644 (file)
@@ -98,7 +98,7 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
        printk(KERN_ERR "\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
                        " disables this message.\n");
        sched_show_task(t);
-       __debug_show_held_locks(t);
+       debug_show_held_locks(t);
 
        touch_nmi_watchdog();
 
@@ -111,7 +111,7 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
  * periodically exit the critical section and enter a new one.
  *
  * For preemptible RCU it is sufficient to call rcu_read_unlock in order
- * exit the grace period. For classic RCU, a reschedule is required.
+ * to exit the grace period. For classic RCU, a reschedule is required.
  */
 static void rcu_lock_break(struct task_struct *g, struct task_struct *t)
 {
index c7c2aed9e2dcc2e52669e7d3880be0666c496bff..2c9120f0afca9872cc4edba57d4e5cfe9311788f 100644 (file)
@@ -113,12 +113,12 @@ static unsigned int max_task_bp_pinned(int cpu, enum bp_type_idx type)
  */
 static int task_bp_pinned(struct perf_event *bp, enum bp_type_idx type)
 {
-       struct perf_event_context *ctx = bp->ctx;
+       struct task_struct *tsk = bp->hw.bp_target;
        struct perf_event *iter;
        int count = 0;
 
        list_for_each_entry(iter, &bp_task_head, hw.bp_list) {
-               if (iter->ctx == ctx && find_slot_idx(iter) == type)
+               if (iter->hw.bp_target == tsk && find_slot_idx(iter) == type)
                        count += hw_breakpoint_weight(iter);
        }
 
@@ -134,7 +134,7 @@ fetch_bp_busy_slots(struct bp_busy_slots *slots, struct perf_event *bp,
                    enum bp_type_idx type)
 {
        int cpu = bp->cpu;
-       struct task_struct *tsk = bp->ctx->task;
+       struct task_struct *tsk = bp->hw.bp_target;
 
        if (cpu >= 0) {
                slots->pinned = per_cpu(nr_cpu_bp_pinned[type], cpu);
@@ -213,7 +213,7 @@ toggle_bp_slot(struct perf_event *bp, bool enable, enum bp_type_idx type,
               int weight)
 {
        int cpu = bp->cpu;
-       struct task_struct *tsk = bp->ctx->task;
+       struct task_struct *tsk = bp->hw.bp_target;
 
        /* Pinned counter cpu profiling */
        if (!tsk) {
@@ -433,8 +433,7 @@ register_user_hw_breakpoint(struct perf_event_attr *attr,
                            perf_overflow_handler_t triggered,
                            struct task_struct *tsk)
 {
-       return perf_event_create_kernel_counter(attr, -1, task_pid_vnr(tsk),
-                                               triggered);
+       return perf_event_create_kernel_counter(attr, -1, tsk, triggered);
 }
 EXPORT_SYMBOL_GPL(register_user_hw_breakpoint);
 
@@ -516,7 +515,7 @@ register_wide_hw_breakpoint(struct perf_event_attr *attr,
        get_online_cpus();
        for_each_online_cpu(cpu) {
                pevent = per_cpu_ptr(cpu_events, cpu);
-               bp = perf_event_create_kernel_counter(attr, cpu, -1, triggered);
+               bp = perf_event_create_kernel_counter(attr, cpu, NULL, triggered);
 
                *pevent = bp;
 
@@ -566,6 +565,61 @@ static struct notifier_block hw_breakpoint_exceptions_nb = {
        .priority = 0x7fffffff
 };
 
+static void bp_perf_event_destroy(struct perf_event *event)
+{
+       release_bp_slot(event);
+}
+
+static int hw_breakpoint_event_init(struct perf_event *bp)
+{
+       int err;
+
+       if (bp->attr.type != PERF_TYPE_BREAKPOINT)
+               return -ENOENT;
+
+       err = register_perf_hw_breakpoint(bp);
+       if (err)
+               return err;
+
+       bp->destroy = bp_perf_event_destroy;
+
+       return 0;
+}
+
+static int hw_breakpoint_add(struct perf_event *bp, int flags)
+{
+       if (!(flags & PERF_EF_START))
+               bp->hw.state = PERF_HES_STOPPED;
+
+       return arch_install_hw_breakpoint(bp);
+}
+
+static void hw_breakpoint_del(struct perf_event *bp, int flags)
+{
+       arch_uninstall_hw_breakpoint(bp);
+}
+
+static void hw_breakpoint_start(struct perf_event *bp, int flags)
+{
+       bp->hw.state = 0;
+}
+
+static void hw_breakpoint_stop(struct perf_event *bp, int flags)
+{
+       bp->hw.state = PERF_HES_STOPPED;
+}
+
+static struct pmu perf_breakpoint = {
+       .task_ctx_nr    = perf_sw_context, /* could eventually get its own */
+
+       .event_init     = hw_breakpoint_event_init,
+       .add            = hw_breakpoint_add,
+       .del            = hw_breakpoint_del,
+       .start          = hw_breakpoint_start,
+       .stop           = hw_breakpoint_stop,
+       .read           = hw_breakpoint_pmu_read,
+};
+
 static int __init init_hw_breakpoint(void)
 {
        unsigned int **task_bp_pinned;
@@ -587,6 +641,8 @@ static int __init init_hw_breakpoint(void)
 
        constraints_initialized = 1;
 
+       perf_pmu_register(&perf_breakpoint);
+
        return register_die_notifier(&hw_breakpoint_exceptions_nb);
 
  err_alloc:
@@ -602,8 +658,3 @@ static int __init init_hw_breakpoint(void)
 core_initcall(init_hw_breakpoint);
 
 
-struct pmu perf_ops_bp = {
-       .enable         = arch_install_hw_breakpoint,
-       .disable        = arch_uninstall_hw_breakpoint,
-       .read           = hw_breakpoint_pmu_read,
-};
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
new file mode 100644 (file)
index 0000000..31d766b
--- /dev/null
@@ -0,0 +1,53 @@
+config HAVE_GENERIC_HARDIRQS
+       def_bool n
+
+if HAVE_GENERIC_HARDIRQS
+menu "IRQ subsystem"
+#
+# Interrupt subsystem related configuration options
+#
+config GENERIC_HARDIRQS
+       def_bool y
+
+config GENERIC_HARDIRQS_NO__DO_IRQ
+       def_bool y
+
+# Select this to disable the deprecated stuff
+config GENERIC_HARDIRQS_NO_DEPRECATED
+       def_bool n
+
+# Options selectable by the architecture code
+config HAVE_SPARSE_IRQ
+       def_bool n
+
+config GENERIC_IRQ_PROBE
+       def_bool n
+
+config GENERIC_PENDING_IRQ
+       def_bool n
+
+config AUTO_IRQ_AFFINITY
+       def_bool n
+
+config IRQ_PER_CPU
+       def_bool n
+
+config HARDIRQS_SW_RESEND
+       def_bool n
+
+config SPARSE_IRQ
+       bool "Support sparse irq numbering"
+       depends on HAVE_SPARSE_IRQ
+       ---help---
+
+         Sparse irq numbering is useful for distro kernels that want
+         to define a high CONFIG_NR_CPUS value but still want to have
+         low kernel memory footprint on smaller machines.
+
+         ( Sparse irqs can also be beneficial on NUMA boxes, as they spread
+           out the interrupt descriptors in a more NUMA-friendly way. )
+
+         If you don't know what to do here, say N.
+
+endmenu
+endif
index 7d047808419da88e273fba8cd1efd88d9aaa5bcd..54329cd7b3ee3cb5ed2084e2072933b183e8a446 100644 (file)
@@ -1,7 +1,6 @@
 
-obj-y := handle.o manage.o spurious.o resend.o chip.o devres.o
+obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o
 obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
-obj-$(CONFIG_NUMA_IRQ_DESC) += numa_migrate.o
 obj-$(CONFIG_PM_SLEEP) += pm.o
index 2295a31ef110dab62a6e665358a9cb290fbe990e..505798f86c36d774afaa4938f2097ac32cd21e0a 100644 (file)
@@ -57,9 +57,10 @@ unsigned long probe_irq_on(void)
                         * Some chips need to know about probing in
                         * progress:
                         */
-                       if (desc->chip->set_type)
-                               desc->chip->set_type(i, IRQ_TYPE_PROBE);
-                       desc->chip->startup(i);
+                       if (desc->irq_data.chip->irq_set_type)
+                               desc->irq_data.chip->irq_set_type(&desc->irq_data,
+                                                        IRQ_TYPE_PROBE);
+                       desc->irq_data.chip->irq_startup(&desc->irq_data);
                }
                raw_spin_unlock_irq(&desc->lock);
        }
@@ -76,7 +77,7 @@ unsigned long probe_irq_on(void)
                raw_spin_lock_irq(&desc->lock);
                if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
                        desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
-                       if (desc->chip->startup(i))
+                       if (desc->irq_data.chip->irq_startup(&desc->irq_data))
                                desc->status |= IRQ_PENDING;
                }
                raw_spin_unlock_irq(&desc->lock);
@@ -98,7 +99,7 @@ unsigned long probe_irq_on(void)
                        /* It triggered already - consider it spurious. */
                        if (!(status & IRQ_WAITING)) {
                                desc->status = status & ~IRQ_AUTODETECT;
-                               desc->chip->shutdown(i);
+                               desc->irq_data.chip->irq_shutdown(&desc->irq_data);
                        } else
                                if (i < 32)
                                        mask |= 1 << i;
@@ -137,7 +138,7 @@ unsigned int probe_irq_mask(unsigned long val)
                                mask |= 1 << i;
 
                        desc->status = status & ~IRQ_AUTODETECT;
-                       desc->chip->shutdown(i);
+                       desc->irq_data.chip->irq_shutdown(&desc->irq_data);
                }
                raw_spin_unlock_irq(&desc->lock);
        }
@@ -181,7 +182,7 @@ int probe_irq_off(unsigned long val)
                                nr_of_irqs++;
                        }
                        desc->status = status & ~IRQ_AUTODETECT;
-                       desc->chip->shutdown(i);
+                       desc->irq_data.chip->irq_shutdown(&desc->irq_data);
                }
                raw_spin_unlock_irq(&desc->lock);
        }
index b7091d5ca2f829ae61f0140ae6b1901213bfab62..baa5c4acad83cc4bd9efad28719d054afc960012 100644 (file)
 
 #include "internals.h"
 
-static void dynamic_irq_init_x(unsigned int irq, bool keep_chip_data)
-{
-       struct irq_desc *desc;
-       unsigned long flags;
-
-       desc = irq_to_desc(irq);
-       if (!desc) {
-               WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
-               return;
-       }
-
-       /* Ensure we don't have left over values from a previous use of this irq */
-       raw_spin_lock_irqsave(&desc->lock, flags);
-       desc->status = IRQ_DISABLED;
-       desc->chip = &no_irq_chip;
-       desc->handle_irq = handle_bad_irq;
-       desc->depth = 1;
-       desc->msi_desc = NULL;
-       desc->handler_data = NULL;
-       if (!keep_chip_data)
-               desc->chip_data = NULL;
-       desc->action = NULL;
-       desc->irq_count = 0;
-       desc->irqs_unhandled = 0;
-#ifdef CONFIG_SMP
-       cpumask_setall(desc->affinity);
-#ifdef CONFIG_GENERIC_PENDING_IRQ
-       cpumask_clear(desc->pending_mask);
-#endif
-#endif
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/**
- *     dynamic_irq_init - initialize a dynamically allocated irq
- *     @irq:   irq number to initialize
- */
-void dynamic_irq_init(unsigned int irq)
-{
-       dynamic_irq_init_x(irq, false);
-}
-
-/**
- *     dynamic_irq_init_keep_chip_data - initialize a dynamically allocated irq
- *     @irq:   irq number to initialize
- *
- *     does not set irq_to_desc(irq)->chip_data to NULL
- */
-void dynamic_irq_init_keep_chip_data(unsigned int irq)
-{
-       dynamic_irq_init_x(irq, true);
-}
-
-static void dynamic_irq_cleanup_x(unsigned int irq, bool keep_chip_data)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-       unsigned long flags;
-
-       if (!desc) {
-               WARN(1, KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq);
-               return;
-       }
-
-       raw_spin_lock_irqsave(&desc->lock, flags);
-       if (desc->action) {
-               raw_spin_unlock_irqrestore(&desc->lock, flags);
-               WARN(1, KERN_ERR "Destroying IRQ%d without calling free_irq\n",
-                       irq);
-               return;
-       }
-       desc->msi_desc = NULL;
-       desc->handler_data = NULL;
-       if (!keep_chip_data)
-               desc->chip_data = NULL;
-       desc->handle_irq = handle_bad_irq;
-       desc->chip = &no_irq_chip;
-       desc->name = NULL;
-       clear_kstat_irqs(desc);
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-/**
- *     dynamic_irq_cleanup - cleanup a dynamically allocated irq
- *     @irq:   irq number to initialize
- */
-void dynamic_irq_cleanup(unsigned int irq)
-{
-       dynamic_irq_cleanup_x(irq, false);
-}
-
-/**
- *     dynamic_irq_cleanup_keep_chip_data - cleanup a dynamically allocated irq
- *     @irq:   irq number to initialize
- *
- *     does not set irq_to_desc(irq)->chip_data to NULL
- */
-void dynamic_irq_cleanup_keep_chip_data(unsigned int irq)
-{
-       dynamic_irq_cleanup_x(irq, true);
-}
-
-
 /**
  *     set_irq_chip - set the irq chip for an irq
  *     @irq:   irq number
@@ -140,7 +38,7 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip)
 
        raw_spin_lock_irqsave(&desc->lock, flags);
        irq_chip_set_defaults(chip);
-       desc->chip = chip;
+       desc->irq_data.chip = chip;
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 
        return 0;
@@ -193,7 +91,7 @@ int set_irq_data(unsigned int irq, void *data)
        }
 
        raw_spin_lock_irqsave(&desc->lock, flags);
-       desc->handler_data = data;
+       desc->irq_data.handler_data = data;
        raw_spin_unlock_irqrestore(&desc->lock, flags);
        return 0;
 }
@@ -218,7 +116,7 @@ int set_irq_msi(unsigned int irq, struct msi_desc *entry)
        }
 
        raw_spin_lock_irqsave(&desc->lock, flags);
-       desc->msi_desc = entry;
+       desc->irq_data.msi_desc = entry;
        if (entry)
                entry->irq = irq;
        raw_spin_unlock_irqrestore(&desc->lock, flags);
@@ -243,19 +141,27 @@ int set_irq_chip_data(unsigned int irq, void *data)
                return -EINVAL;
        }
 
-       if (!desc->chip) {
+       if (!desc->irq_data.chip) {
                printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq);
                return -EINVAL;
        }
 
        raw_spin_lock_irqsave(&desc->lock, flags);
-       desc->chip_data = data;
+       desc->irq_data.chip_data = data;
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 
        return 0;
 }
 EXPORT_SYMBOL(set_irq_chip_data);
 
+struct irq_data *irq_get_irq_data(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       return desc ? &desc->irq_data : NULL;
+}
+EXPORT_SYMBOL_GPL(irq_get_irq_data);
+
 /**
  *     set_irq_nested_thread - Set/Reset the IRQ_NESTED_THREAD flag of an irq
  *
@@ -287,93 +193,216 @@ EXPORT_SYMBOL_GPL(set_irq_nested_thread);
 /*
  * default enable function
  */
-static void default_enable(unsigned int irq)
+static void default_enable(struct irq_data *data)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_desc *desc = irq_data_to_desc(data);
 
-       desc->chip->unmask(irq);
+       desc->irq_data.chip->irq_unmask(&desc->irq_data);
        desc->status &= ~IRQ_MASKED;
 }
 
 /*
  * default disable function
  */
-static void default_disable(unsigned int irq)
+static void default_disable(struct irq_data *data)
 {
 }
 
 /*
  * default startup function
  */
-static unsigned int default_startup(unsigned int irq)
+static unsigned int default_startup(struct irq_data *data)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_desc *desc = irq_data_to_desc(data);
 
-       desc->chip->enable(irq);
+       desc->irq_data.chip->irq_enable(data);
        return 0;
 }
 
 /*
  * default shutdown function
  */
-static void default_shutdown(unsigned int irq)
+static void default_shutdown(struct irq_data *data)
 {
-       struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_desc *desc = irq_data_to_desc(data);
 
-       desc->chip->mask(irq);
+       desc->irq_data.chip->irq_mask(&desc->irq_data);
        desc->status |= IRQ_MASKED;
 }
 
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
+/* Temporary migration helpers */
+static void compat_irq_mask(struct irq_data *data)
+{
+       data->chip->mask(data->irq);
+}
+
+static void compat_irq_unmask(struct irq_data *data)
+{
+       data->chip->unmask(data->irq);
+}
+
+static void compat_irq_ack(struct irq_data *data)
+{
+       data->chip->ack(data->irq);
+}
+
+static void compat_irq_mask_ack(struct irq_data *data)
+{
+       data->chip->mask_ack(data->irq);
+}
+
+static void compat_irq_eoi(struct irq_data *data)
+{
+       data->chip->eoi(data->irq);
+}
+
+static void compat_irq_enable(struct irq_data *data)
+{
+       data->chip->enable(data->irq);
+}
+
+static void compat_irq_disable(struct irq_data *data)
+{
+       data->chip->disable(data->irq);
+}
+
+static void compat_irq_shutdown(struct irq_data *data)
+{
+       data->chip->shutdown(data->irq);
+}
+
+static unsigned int compat_irq_startup(struct irq_data *data)
+{
+       return data->chip->startup(data->irq);
+}
+
+static int compat_irq_set_affinity(struct irq_data *data,
+                                  const struct cpumask *dest, bool force)
+{
+       return data->chip->set_affinity(data->irq, dest);
+}
+
+static int compat_irq_set_type(struct irq_data *data, unsigned int type)
+{
+       return data->chip->set_type(data->irq, type);
+}
+
+static int compat_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+       return data->chip->set_wake(data->irq, on);
+}
+
+static int compat_irq_retrigger(struct irq_data *data)
+{
+       return data->chip->retrigger(data->irq);
+}
+
+static void compat_bus_lock(struct irq_data *data)
+{
+       data->chip->bus_lock(data->irq);
+}
+
+static void compat_bus_sync_unlock(struct irq_data *data)
+{
+       data->chip->bus_sync_unlock(data->irq);
+}
+#endif
+
 /*
  * Fixup enable/disable function pointers
  */
 void irq_chip_set_defaults(struct irq_chip *chip)
 {
-       if (!chip->enable)
-               chip->enable = default_enable;
-       if (!chip->disable)
-               chip->disable = default_disable;
-       if (!chip->startup)
-               chip->startup = default_startup;
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
        /*
-        * We use chip->disable, when the user provided its own. When
-        * we have default_disable set for chip->disable, then we need
+        * Compat fixup functions need to be before we set the
+        * defaults for enable/disable/startup/shutdown
+        */
+       if (chip->enable)
+               chip->irq_enable = compat_irq_enable;
+       if (chip->disable)
+               chip->irq_disable = compat_irq_disable;
+       if (chip->shutdown)
+               chip->irq_shutdown = compat_irq_shutdown;
+       if (chip->startup)
+               chip->irq_startup = compat_irq_startup;
+#endif
+       /*
+        * The real defaults
+        */
+       if (!chip->irq_enable)
+               chip->irq_enable = default_enable;
+       if (!chip->irq_disable)
+               chip->irq_disable = default_disable;
+       if (!chip->irq_startup)
+               chip->irq_startup = default_startup;
+       /*
+        * We use chip->irq_disable, when the user provided its own. When
+        * we have default_disable set for chip->irq_disable, then we need
         * to use default_shutdown, otherwise the irq line is not
         * disabled on free_irq():
         */
-       if (!chip->shutdown)
-               chip->shutdown = chip->disable != default_disable ?
-                       chip->disable : default_shutdown;
-       if (!chip->name)
-               chip->name = chip->typename;
+       if (!chip->irq_shutdown)
+               chip->irq_shutdown = chip->irq_disable != default_disable ?
+                       chip->irq_disable : default_shutdown;
+
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
        if (!chip->end)
                chip->end = dummy_irq_chip.end;
+
+       /*
+        * Now fix up the remaining compat handlers
+        */
+       if (chip->bus_lock)
+               chip->irq_bus_lock = compat_bus_lock;
+       if (chip->bus_sync_unlock)
+               chip->irq_bus_sync_unlock = compat_bus_sync_unlock;
+       if (chip->mask)
+               chip->irq_mask = compat_irq_mask;
+       if (chip->unmask)
+               chip->irq_unmask = compat_irq_unmask;
+       if (chip->ack)
+               chip->irq_ack = compat_irq_ack;
+       if (chip->mask_ack)
+               chip->irq_mask_ack = compat_irq_mask_ack;
+       if (chip->eoi)
+               chip->irq_eoi = compat_irq_eoi;
+       if (chip->set_affinity)
+               chip->irq_set_affinity = compat_irq_set_affinity;
+       if (chip->set_type)
+               chip->irq_set_type = compat_irq_set_type;
+       if (chip->set_wake)
+               chip->irq_set_wake = compat_irq_set_wake;
+       if (chip->retrigger)
+               chip->irq_retrigger = compat_irq_retrigger;
+#endif
 }
 
-static inline void mask_ack_irq(struct irq_desc *desc, int irq)
+static inline void mask_ack_irq(struct irq_desc *desc)
 {
-       if (desc->chip->mask_ack)
-               desc->chip->mask_ack(irq);
+       if (desc->irq_data.chip->irq_mask_ack)
+               desc->irq_data.chip->irq_mask_ack(&desc->irq_data);
        else {
-               desc->chip->mask(irq);
-               if (desc->chip->ack)
-                       desc->chip->ack(irq);
+               desc->irq_data.chip->irq_mask(&desc->irq_data);
+               if (desc->irq_data.chip->irq_ack)
+                       desc->irq_data.chip->irq_ack(&desc->irq_data);
        }
        desc->status |= IRQ_MASKED;
 }
 
-static inline void mask_irq(struct irq_desc *desc, int irq)
+static inline void mask_irq(struct irq_desc *desc)
 {
-       if (desc->chip->mask) {
-               desc->chip->mask(irq);
+       if (desc->irq_data.chip->irq_mask) {
+               desc->irq_data.chip->irq_mask(&desc->irq_data);
                desc->status |= IRQ_MASKED;
        }
 }
 
-static inline void unmask_irq(struct irq_desc *desc, int irq)
+static inline void unmask_irq(struct irq_desc *desc)
 {
-       if (desc->chip->unmask) {
-               desc->chip->unmask(irq);
+       if (desc->irq_data.chip->irq_unmask) {
+               desc->irq_data.chip->irq_unmask(&desc->irq_data);
                desc->status &= ~IRQ_MASKED;
        }
 }
@@ -476,7 +505,7 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
        irqreturn_t action_ret;
 
        raw_spin_lock(&desc->lock);
-       mask_ack_irq(desc, irq);
+       mask_ack_irq(desc);
 
        if (unlikely(desc->status & IRQ_INPROGRESS))
                goto out_unlock;
@@ -502,7 +531,7 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
        desc->status &= ~IRQ_INPROGRESS;
 
        if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT)))
-               unmask_irq(desc, irq);
+               unmask_irq(desc);
 out_unlock:
        raw_spin_unlock(&desc->lock);
 }
@@ -539,7 +568,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
        action = desc->action;
        if (unlikely(!action || (desc->status & IRQ_DISABLED))) {
                desc->status |= IRQ_PENDING;
-               mask_irq(desc, irq);
+               mask_irq(desc);
                goto out;
        }
 
@@ -554,7 +583,7 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
        raw_spin_lock(&desc->lock);
        desc->status &= ~IRQ_INPROGRESS;
 out:
-       desc->chip->eoi(irq);
+       desc->irq_data.chip->irq_eoi(&desc->irq_data);
 
        raw_spin_unlock(&desc->lock);
 }
@@ -590,14 +619,13 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
        if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||
                    !desc->action)) {
                desc->status |= (IRQ_PENDING | IRQ_MASKED);
-               mask_ack_irq(desc, irq);
+               mask_ack_irq(desc);
                goto out_unlock;
        }
        kstat_incr_irqs_this_cpu(irq, desc);
 
        /* Start handling the irq */
-       if (desc->chip->ack)
-               desc->chip->ack(irq);
+       desc->irq_data.chip->irq_ack(&desc->irq_data);
 
        /* Mark the IRQ currently in progress.*/
        desc->status |= IRQ_INPROGRESS;
@@ -607,7 +635,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
                irqreturn_t action_ret;
 
                if (unlikely(!action)) {
-                       mask_irq(desc, irq);
+                       mask_irq(desc);
                        goto out_unlock;
                }
 
@@ -619,7 +647,7 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc)
                if (unlikely((desc->status &
                               (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
                              (IRQ_PENDING | IRQ_MASKED))) {
-                       unmask_irq(desc, irq);
+                       unmask_irq(desc);
                }
 
                desc->status &= ~IRQ_PENDING;
@@ -650,15 +678,15 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
 
        kstat_incr_irqs_this_cpu(irq, desc);
 
-       if (desc->chip->ack)
-               desc->chip->ack(irq);
+       if (desc->irq_data.chip->irq_ack)
+               desc->irq_data.chip->irq_ack(&desc->irq_data);
 
        action_ret = handle_IRQ_event(irq, desc->action);
        if (!noirqdebug)
                note_interrupt(irq, desc, action_ret);
 
-       if (desc->chip->eoi)
-               desc->chip->eoi(irq);
+       if (desc->irq_data.chip->irq_eoi)
+               desc->irq_data.chip->irq_eoi(&desc->irq_data);
 }
 
 void
@@ -676,7 +704,7 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
 
        if (!handle)
                handle = handle_bad_irq;
-       else if (desc->chip == &no_irq_chip) {
+       else if (desc->irq_data.chip == &no_irq_chip) {
                printk(KERN_WARNING "Trying to install %sinterrupt handler "
                       "for IRQ%d\n", is_chained ? "chained " : "", irq);
                /*
@@ -686,16 +714,16 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
                 * prevent us to setup the interrupt at all. Switch it to
                 * dummy_irq_chip for easy transition.
                 */
-               desc->chip = &dummy_irq_chip;
+               desc->irq_data.chip = &dummy_irq_chip;
        }
 
-       chip_bus_lock(irq, desc);
+       chip_bus_lock(desc);
        raw_spin_lock_irqsave(&desc->lock, flags);
 
        /* Uninstall? */
        if (handle == handle_bad_irq) {
-               if (desc->chip != &no_irq_chip)
-                       mask_ack_irq(desc, irq);
+               if (desc->irq_data.chip != &no_irq_chip)
+                       mask_ack_irq(desc);
                desc->status |= IRQ_DISABLED;
                desc->depth = 1;
        }
@@ -706,10 +734,10 @@ __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
                desc->status &= ~IRQ_DISABLED;
                desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
                desc->depth = 0;
-               desc->chip->startup(irq);
+               desc->irq_data.chip->irq_startup(&desc->irq_data);
        }
        raw_spin_unlock_irqrestore(&desc->lock, flags);
-       chip_bus_sync_unlock(irq, desc);
+       chip_bus_sync_unlock(desc);
 }
 EXPORT_SYMBOL_GPL(__set_irq_handler);
 
@@ -729,32 +757,20 @@ set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
        __set_irq_handler(irq, handle, 0, name);
 }
 
-void set_irq_noprobe(unsigned int irq)
+void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
 {
        struct irq_desc *desc = irq_to_desc(irq);
        unsigned long flags;
 
-       if (!desc) {
-               printk(KERN_ERR "Trying to mark IRQ%d non-probeable\n", irq);
+       if (!desc)
                return;
-       }
-
-       raw_spin_lock_irqsave(&desc->lock, flags);
-       desc->status |= IRQ_NOPROBE;
-       raw_spin_unlock_irqrestore(&desc->lock, flags);
-}
-
-void set_irq_probe(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-       unsigned long flags;
 
-       if (!desc) {
-               printk(KERN_ERR "Trying to mark IRQ%d probeable\n", irq);
-               return;
-       }
+       /* Sanitize flags */
+       set &= IRQF_MODIFY_MASK;
+       clr &= IRQF_MODIFY_MASK;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
-       desc->status &= ~IRQ_NOPROBE;
+       desc->status &= ~clr;
+       desc->status |= set;
        raw_spin_unlock_irqrestore(&desc->lock, flags);
 }
diff --git a/kernel/irq/dummychip.c b/kernel/irq/dummychip.c
new file mode 100644 (file)
index 0000000..20dc547
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 2005-2006, Thomas Gleixner, Russell King
+ *
+ * This file contains the dummy interrupt chip implementation
+ */
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include "internals.h"
+
+/*
+ * What should we do if we get a hw irq event on an illegal vector?
+ * Each architecture has to answer this themself.
+ */
+static void ack_bad(struct irq_data *data)
+{
+       struct irq_desc *desc = irq_data_to_desc(data);
+
+       print_irq_desc(data->irq, desc);
+       ack_bad_irq(data->irq);
+}
+
+/*
+ * NOP functions
+ */
+static void noop(struct irq_data *data) { }
+
+static unsigned int noop_ret(struct irq_data *data)
+{
+       return 0;
+}
+
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
+static void compat_noop(unsigned int irq) { }
+#define END_INIT .end = compat_noop
+#else
+#define END_INIT
+#endif
+
+/*
+ * Generic no controller implementation
+ */
+struct irq_chip no_irq_chip = {
+       .name           = "none",
+       .irq_startup    = noop_ret,
+       .irq_shutdown   = noop,
+       .irq_enable     = noop,
+       .irq_disable    = noop,
+       .irq_ack        = ack_bad,
+       END_INIT
+};
+
+/*
+ * Generic dummy implementation which can be used for
+ * real dumb interrupt sources
+ */
+struct irq_chip dummy_irq_chip = {
+       .name           = "dummy",
+       .irq_startup    = noop_ret,
+       .irq_shutdown   = noop,
+       .irq_enable     = noop,
+       .irq_disable    = noop,
+       .irq_ack        = noop,
+       .irq_mask       = noop,
+       .irq_unmask     = noop,
+       END_INIT
+};
index 27e5c69112235c2f0cebe18981bb1f5504ed6807..e2347eb6330682501e99bb3214ccfa9015a8a521 100644 (file)
  */
 
 #include <linux/irq.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/module.h>
 #include <linux/random.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
-#include <linux/rculist.h>
-#include <linux/hash.h>
-#include <linux/radix-tree.h>
+
 #include <trace/events/irq.h>
 
 #include "internals.h"
 
-/*
- * lockdep: we want to handle all irq_desc locks as a single lock-class:
- */
-struct lock_class_key irq_desc_lock_class;
-
 /**
  * handle_bad_irq - handle spurious and unhandled irqs
  * @irq:       the interrupt number
@@ -43,304 +34,6 @@ void handle_bad_irq(unsigned int irq, struct irq_desc *desc)
        ack_bad_irq(irq);
 }
 
-#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
-static void __init init_irq_default_affinity(void)
-{
-       alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
-       cpumask_setall(irq_default_affinity);
-}
-#else
-static void __init init_irq_default_affinity(void)
-{
-}
-#endif
-
-/*
- * Linux has a controller-independent interrupt architecture.
- * Every controller has a 'controller-template', that is used
- * by the main code to do the right thing. Each driver-visible
- * interrupt source is transparently wired to the appropriate
- * controller. Thus drivers need not be aware of the
- * interrupt-controller.
- *
- * The code is designed to be easily extended with new/different
- * interrupt controllers, without having to do assembly magic or
- * having to touch the generic code.
- *
- * Controller mappings for all interrupt sources:
- */
-int nr_irqs = NR_IRQS;
-EXPORT_SYMBOL_GPL(nr_irqs);
-
-#ifdef CONFIG_SPARSE_IRQ
-
-static struct irq_desc irq_desc_init = {
-       .irq        = -1,
-       .status     = IRQ_DISABLED,
-       .chip       = &no_irq_chip,
-       .handle_irq = handle_bad_irq,
-       .depth      = 1,
-       .lock       = __RAW_SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
-};
-
-void __ref init_kstat_irqs(struct irq_desc *desc, int node, int nr)
-{
-       void *ptr;
-
-       ptr = kzalloc_node(nr * sizeof(*desc->kstat_irqs),
-                          GFP_ATOMIC, node);
-
-       /*
-        * don't overwite if can not get new one
-        * init_copy_kstat_irqs() could still use old one
-        */
-       if (ptr) {
-               printk(KERN_DEBUG "  alloc kstat_irqs on node %d\n", node);
-               desc->kstat_irqs = ptr;
-       }
-}
-
-static void init_one_irq_desc(int irq, struct irq_desc *desc, int node)
-{
-       memcpy(desc, &irq_desc_init, sizeof(struct irq_desc));
-
-       raw_spin_lock_init(&desc->lock);
-       desc->irq = irq;
-#ifdef CONFIG_SMP
-       desc->node = node;
-#endif
-       lockdep_set_class(&desc->lock, &irq_desc_lock_class);
-       init_kstat_irqs(desc, node, nr_cpu_ids);
-       if (!desc->kstat_irqs) {
-               printk(KERN_ERR "can not alloc kstat_irqs\n");
-               BUG_ON(1);
-       }
-       if (!alloc_desc_masks(desc, node, false)) {
-               printk(KERN_ERR "can not alloc irq_desc cpumasks\n");
-               BUG_ON(1);
-       }
-       init_desc_masks(desc);
-       arch_init_chip_data(desc, node);
-}
-
-/*
- * Protect the sparse_irqs:
- */
-DEFINE_RAW_SPINLOCK(sparse_irq_lock);
-
-static RADIX_TREE(irq_desc_tree, GFP_ATOMIC);
-
-static void set_irq_desc(unsigned int irq, struct irq_desc *desc)
-{
-       radix_tree_insert(&irq_desc_tree, irq, desc);
-}
-
-struct irq_desc *irq_to_desc(unsigned int irq)
-{
-       return radix_tree_lookup(&irq_desc_tree, irq);
-}
-
-void replace_irq_desc(unsigned int irq, struct irq_desc *desc)
-{
-       void **ptr;
-
-       ptr = radix_tree_lookup_slot(&irq_desc_tree, irq);
-       if (ptr)
-               radix_tree_replace_slot(ptr, desc);
-}
-
-static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = {
-       [0 ... NR_IRQS_LEGACY-1] = {
-               .irq        = -1,
-               .status     = IRQ_DISABLED,
-               .chip       = &no_irq_chip,
-               .handle_irq = handle_bad_irq,
-               .depth      = 1,
-               .lock       = __RAW_SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
-       }
-};
-
-static unsigned int *kstat_irqs_legacy;
-
-int __init early_irq_init(void)
-{
-       struct irq_desc *desc;
-       int legacy_count;
-       int node;
-       int i;
-
-       init_irq_default_affinity();
-
-        /* initialize nr_irqs based on nr_cpu_ids */
-       arch_probe_nr_irqs();
-       printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d\n", NR_IRQS, nr_irqs);
-
-       desc = irq_desc_legacy;
-       legacy_count = ARRAY_SIZE(irq_desc_legacy);
-       node = first_online_node;
-
-       /* allocate based on nr_cpu_ids */
-       kstat_irqs_legacy = kzalloc_node(NR_IRQS_LEGACY * nr_cpu_ids *
-                                         sizeof(int), GFP_NOWAIT, node);
-
-       for (i = 0; i < legacy_count; i++) {
-               desc[i].irq = i;
-#ifdef CONFIG_SMP
-               desc[i].node = node;
-#endif
-               desc[i].kstat_irqs = kstat_irqs_legacy + i * nr_cpu_ids;
-               lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
-               alloc_desc_masks(&desc[i], node, true);
-               init_desc_masks(&desc[i]);
-               set_irq_desc(i, &desc[i]);
-       }
-
-       return arch_early_irq_init();
-}
-
-struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node)
-{
-       struct irq_desc *desc;
-       unsigned long flags;
-
-       if (irq >= nr_irqs) {
-               WARN(1, "irq (%d) >= nr_irqs (%d) in irq_to_desc_alloc\n",
-                       irq, nr_irqs);
-               return NULL;
-       }
-
-       desc = irq_to_desc(irq);
-       if (desc)
-               return desc;
-
-       raw_spin_lock_irqsave(&sparse_irq_lock, flags);
-
-       /* We have to check it to avoid races with another CPU */
-       desc = irq_to_desc(irq);
-       if (desc)
-               goto out_unlock;
-
-       desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
-
-       printk(KERN_DEBUG "  alloc irq_desc for %d on node %d\n", irq, node);
-       if (!desc) {
-               printk(KERN_ERR "can not alloc irq_desc\n");
-               BUG_ON(1);
-       }
-       init_one_irq_desc(irq, desc, node);
-
-       set_irq_desc(irq, desc);
-
-out_unlock:
-       raw_spin_unlock_irqrestore(&sparse_irq_lock, flags);
-
-       return desc;
-}
-
-#else /* !CONFIG_SPARSE_IRQ */
-
-struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
-       [0 ... NR_IRQS-1] = {
-               .status = IRQ_DISABLED,
-               .chip = &no_irq_chip,
-               .handle_irq = handle_bad_irq,
-               .depth = 1,
-               .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
-       }
-};
-
-static unsigned int kstat_irqs_all[NR_IRQS][NR_CPUS];
-int __init early_irq_init(void)
-{
-       struct irq_desc *desc;
-       int count;
-       int i;
-
-       init_irq_default_affinity();
-
-       printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS);
-
-       desc = irq_desc;
-       count = ARRAY_SIZE(irq_desc);
-
-       for (i = 0; i < count; i++) {
-               desc[i].irq = i;
-               alloc_desc_masks(&desc[i], 0, true);
-               init_desc_masks(&desc[i]);
-               desc[i].kstat_irqs = kstat_irqs_all[i];
-       }
-       return arch_early_irq_init();
-}
-
-struct irq_desc *irq_to_desc(unsigned int irq)
-{
-       return (irq < NR_IRQS) ? irq_desc + irq : NULL;
-}
-
-struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node)
-{
-       return irq_to_desc(irq);
-}
-#endif /* !CONFIG_SPARSE_IRQ */
-
-void clear_kstat_irqs(struct irq_desc *desc)
-{
-       memset(desc->kstat_irqs, 0, nr_cpu_ids * sizeof(*(desc->kstat_irqs)));
-}
-
-/*
- * What should we do if we get a hw irq event on an illegal vector?
- * Each architecture has to answer this themself.
- */
-static void ack_bad(unsigned int irq)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-
-       print_irq_desc(irq, desc);
-       ack_bad_irq(irq);
-}
-
-/*
- * NOP functions
- */
-static void noop(unsigned int irq)
-{
-}
-
-static unsigned int noop_ret(unsigned int irq)
-{
-       return 0;
-}
-
-/*
- * Generic no controller implementation
- */
-struct irq_chip no_irq_chip = {
-       .name           = "none",
-       .startup        = noop_ret,
-       .shutdown       = noop,
-       .enable         = noop,
-       .disable        = noop,
-       .ack            = ack_bad,
-       .end            = noop,
-};
-
-/*
- * Generic dummy implementation which can be used for
- * real dumb interrupt sources
- */
-struct irq_chip dummy_irq_chip = {
-       .name           = "dummy",
-       .startup        = noop_ret,
-       .shutdown       = noop,
-       .enable         = noop,
-       .disable        = noop,
-       .ack            = noop,
-       .mask           = noop,
-       .unmask         = noop,
-       .end            = noop,
-};
-
 /*
  * Special, empty irq handler:
  */
@@ -457,20 +150,20 @@ unsigned int __do_IRQ(unsigned int irq)
                /*
                 * No locking required for CPU-local interrupts:
                 */
-               if (desc->chip->ack)
-                       desc->chip->ack(irq);
+               if (desc->irq_data.chip->ack)
+                       desc->irq_data.chip->ack(irq);
                if (likely(!(desc->status & IRQ_DISABLED))) {
                        action_ret = handle_IRQ_event(irq, desc->action);
                        if (!noirqdebug)
                                note_interrupt(irq, desc, action_ret);
                }
-               desc->chip->end(irq);
+               desc->irq_data.chip->end(irq);
                return 1;
        }
 
        raw_spin_lock(&desc->lock);
-       if (desc->chip->ack)
-               desc->chip->ack(irq);
+       if (desc->irq_data.chip->ack)
+               desc->irq_data.chip->ack(irq);
        /*
         * REPLAY is when Linux resends an IRQ that was dropped earlier
         * WAITING is used by probe to mark irqs that are being tested
@@ -530,27 +223,9 @@ out:
         * The ->end() handler has to deal with interrupts which got
         * disabled while the handler was running.
         */
-       desc->chip->end(irq);
+       desc->irq_data.chip->end(irq);
        raw_spin_unlock(&desc->lock);
 
        return 1;
 }
 #endif
-
-void early_init_irq_lock_class(void)
-{
-       struct irq_desc *desc;
-       int i;
-
-       for_each_irq_desc(i, desc) {
-               lockdep_set_class(&desc->lock, &irq_desc_lock_class);
-       }
-}
-
-unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
-{
-       struct irq_desc *desc = irq_to_desc(irq);
-       return desc ? desc->kstat_irqs[cpu] : 0;
-}
-EXPORT_SYMBOL(kstat_irqs_cpu);
-
index c63f3bc88f0b77727a45a2a8d44936d797aeaa01..4571ae7e085ac95ad6affb1f31d802f32064665e 100644 (file)
@@ -1,9 +1,12 @@
 /*
  * IRQ subsystem internal functions and variables:
  */
+#include <linux/irqdesc.h>
 
 extern int noirqdebug;
 
+#define irq_data_to_desc(data) container_of(data, struct irq_desc, irq_data)
+
 /* Set default functions for irq_chip structures: */
 extern void irq_chip_set_defaults(struct irq_chip *chip);
 
@@ -15,21 +18,19 @@ extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
 extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp);
 extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume);
 
-extern struct lock_class_key irq_desc_lock_class;
 extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
-extern void clear_kstat_irqs(struct irq_desc *desc);
-extern raw_spinlock_t sparse_irq_lock;
 
-#ifdef CONFIG_SPARSE_IRQ
-void replace_irq_desc(unsigned int irq, struct irq_desc *desc);
-#endif
+/* Resending of interrupts :*/
+void check_irq_resend(struct irq_desc *desc, unsigned int irq);
 
 #ifdef CONFIG_PROC_FS
 extern void register_irq_proc(unsigned int irq, struct irq_desc *desc);
+extern void unregister_irq_proc(unsigned int irq, struct irq_desc *desc);
 extern void register_handler_proc(unsigned int irq, struct irqaction *action);
 extern void unregister_handler_proc(unsigned int irq, struct irqaction *action);
 #else
 static inline void register_irq_proc(unsigned int irq, struct irq_desc *desc) { }
+static inline void unregister_irq_proc(unsigned int irq, struct irq_desc *desc) { }
 static inline void register_handler_proc(unsigned int irq,
                                         struct irqaction *action) { }
 static inline void unregister_handler_proc(unsigned int irq,
@@ -40,17 +41,27 @@ extern int irq_select_affinity_usr(unsigned int irq);
 
 extern void irq_set_thread_affinity(struct irq_desc *desc);
 
+#ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
+static inline void irq_end(unsigned int irq, struct irq_desc *desc)
+{
+       if (desc->irq_data.chip && desc->irq_data.chip->end)
+               desc->irq_data.chip->end(irq);
+}
+#else
+static inline void irq_end(unsigned int irq, struct irq_desc *desc) { }
+#endif
+
 /* Inline functions for support of irq chips on slow busses */
-static inline void chip_bus_lock(unsigned int irq, struct irq_desc *desc)
+static inline void chip_bus_lock(struct irq_desc *desc)
 {
-       if (unlikely(desc->chip->bus_lock))
-               desc->chip->bus_lock(irq);
+       if (unlikely(desc->irq_data.chip->irq_bus_lock))
+               desc->irq_data.chip->irq_bus_lock(&desc->irq_data);
 }
 
-static inline void chip_bus_sync_unlock(unsigned int irq, struct irq_desc *desc)
+static inline void chip_bus_sync_unlock(struct irq_desc *desc)
 {
-       if (unlikely(desc->chip->bus_sync_unlock))
-               desc->chip->bus_sync_unlock(irq);
+       if (unlikely(desc->irq_data.chip->irq_bus_sync_unlock))
+               desc->irq_data.chip->irq_bus_sync_unlock(&desc->irq_data);
 }
 
 /*
@@ -67,8 +78,8 @@ static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc)
                irq, desc, desc->depth, desc->irq_count, desc->irqs_unhandled);
        printk("->handle_irq():  %p, ", desc->handle_irq);
        print_symbol("%s\n", (unsigned long)desc->handle_irq);
-       printk("->chip(): %p, ", desc->chip);
-       print_symbol("%s\n", (unsigned long)desc->chip);
+       printk("->irq_data.chip(): %p, ", desc->irq_data.chip);
+       print_symbol("%s\n", (unsigned long)desc->irq_data.chip);
        printk("->action(): %p\n", desc->action);
        if (desc->action) {
                printk("->action->handler(): %p, ", desc->action->handler);
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
new file mode 100644 (file)
index 0000000..9d917ff
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar
+ * Copyright (C) 2005-2006, Thomas Gleixner, Russell King
+ *
+ * This file contains the interrupt descriptor management code
+ *
+ * Detailed information is available in Documentation/DocBook/genericirq
+ *
+ */
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/radix-tree.h>
+#include <linux/bitmap.h>
+
+#include "internals.h"
+
+/*
+ * lockdep: we want to handle all irq_desc locks as a single lock-class:
+ */
+static struct lock_class_key irq_desc_lock_class;
+
+#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
+static void __init init_irq_default_affinity(void)
+{
+       alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
+       cpumask_setall(irq_default_affinity);
+}
+#else
+static void __init init_irq_default_affinity(void)
+{
+}
+#endif
+
+#ifdef CONFIG_SMP
+static int alloc_masks(struct irq_desc *desc, gfp_t gfp, int node)
+{
+       if (!zalloc_cpumask_var_node(&desc->irq_data.affinity, gfp, node))
+               return -ENOMEM;
+
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+       if (!zalloc_cpumask_var_node(&desc->pending_mask, gfp, node)) {
+               free_cpumask_var(desc->irq_data.affinity);
+               return -ENOMEM;
+       }
+#endif
+       return 0;
+}
+
+static void desc_smp_init(struct irq_desc *desc, int node)
+{
+       desc->irq_data.node = node;
+       cpumask_copy(desc->irq_data.affinity, irq_default_affinity);
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+       cpumask_clear(desc->pending_mask);
+#endif
+}
+
+static inline int desc_node(struct irq_desc *desc)
+{
+       return desc->irq_data.node;
+}
+
+#else
+static inline int
+alloc_masks(struct irq_desc *desc, gfp_t gfp, int node) { return 0; }
+static inline void desc_smp_init(struct irq_desc *desc, int node) { }
+static inline int desc_node(struct irq_desc *desc) { return 0; }
+#endif
+
+static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node)
+{
+       desc->irq_data.irq = irq;
+       desc->irq_data.chip = &no_irq_chip;
+       desc->irq_data.chip_data = NULL;
+       desc->irq_data.handler_data = NULL;
+       desc->irq_data.msi_desc = NULL;
+       desc->status = IRQ_DEFAULT_INIT_FLAGS;
+       desc->handle_irq = handle_bad_irq;
+       desc->depth = 1;
+       desc->irq_count = 0;
+       desc->irqs_unhandled = 0;
+       desc->name = NULL;
+       memset(desc->kstat_irqs, 0, nr_cpu_ids * sizeof(*(desc->kstat_irqs)));
+       desc_smp_init(desc, node);
+}
+
+int nr_irqs = NR_IRQS;
+EXPORT_SYMBOL_GPL(nr_irqs);
+
+static DEFINE_MUTEX(sparse_irq_lock);
+static DECLARE_BITMAP(allocated_irqs, NR_IRQS);
+
+#ifdef CONFIG_SPARSE_IRQ
+
+static RADIX_TREE(irq_desc_tree, GFP_KERNEL);
+
+static void irq_insert_desc(unsigned int irq, struct irq_desc *desc)
+{
+       radix_tree_insert(&irq_desc_tree, irq, desc);
+}
+
+struct irq_desc *irq_to_desc(unsigned int irq)
+{
+       return radix_tree_lookup(&irq_desc_tree, irq);
+}
+
+static void delete_irq_desc(unsigned int irq)
+{
+       radix_tree_delete(&irq_desc_tree, irq);
+}
+
+#ifdef CONFIG_SMP
+static void free_masks(struct irq_desc *desc)
+{
+#ifdef CONFIG_GENERIC_PENDING_IRQ
+       free_cpumask_var(desc->pending_mask);
+#endif
+       free_cpumask_var(desc->irq_data.affinity);
+}
+#else
+static inline void free_masks(struct irq_desc *desc) { }
+#endif
+
+static struct irq_desc *alloc_desc(int irq, int node)
+{
+       struct irq_desc *desc;
+       gfp_t gfp = GFP_KERNEL;
+
+       desc = kzalloc_node(sizeof(*desc), gfp, node);
+       if (!desc)
+               return NULL;
+       /* allocate based on nr_cpu_ids */
+       desc->kstat_irqs = kzalloc_node(nr_cpu_ids * sizeof(*desc->kstat_irqs),
+                                        gfp, node);
+       if (!desc->kstat_irqs)
+               goto err_desc;
+
+       if (alloc_masks(desc, gfp, node))
+               goto err_kstat;
+
+       raw_spin_lock_init(&desc->lock);
+       lockdep_set_class(&desc->lock, &irq_desc_lock_class);
+
+       desc_set_defaults(irq, desc, node);
+
+       return desc;
+
+err_kstat:
+       kfree(desc->kstat_irqs);
+err_desc:
+       kfree(desc);
+       return NULL;
+}
+
+static void free_desc(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+
+       unregister_irq_proc(irq, desc);
+
+       mutex_lock(&sparse_irq_lock);
+       delete_irq_desc(irq);
+       mutex_unlock(&sparse_irq_lock);
+
+       free_masks(desc);
+       kfree(desc->kstat_irqs);
+       kfree(desc);
+}
+
+static int alloc_descs(unsigned int start, unsigned int cnt, int node)
+{
+       struct irq_desc *desc;
+       int i;
+
+       for (i = 0; i < cnt; i++) {
+               desc = alloc_desc(start + i, node);
+               if (!desc)
+                       goto err;
+               mutex_lock(&sparse_irq_lock);
+               irq_insert_desc(start + i, desc);
+               mutex_unlock(&sparse_irq_lock);
+       }
+       return start;
+
+err:
+       for (i--; i >= 0; i--)
+               free_desc(start + i);
+
+       mutex_lock(&sparse_irq_lock);
+       bitmap_clear(allocated_irqs, start, cnt);
+       mutex_unlock(&sparse_irq_lock);
+       return -ENOMEM;
+}
+
+struct irq_desc * __ref irq_to_desc_alloc_node(unsigned int irq, int node)
+{
+       int res = irq_alloc_descs(irq, irq, 1, node);
+
+       if (res == -EEXIST || res == irq)
+               return irq_to_desc(irq);
+       return NULL;
+}
+
+int __init early_irq_init(void)
+{
+       int i, initcnt, node = first_online_node;
+       struct irq_desc *desc;
+
+       init_irq_default_affinity();
+
+       /* Let arch update nr_irqs and return the nr of preallocated irqs */
+       initcnt = arch_probe_nr_irqs();
+       printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d %d\n", NR_IRQS, nr_irqs, initcnt);
+
+       for (i = 0; i < initcnt; i++) {
+               desc = alloc_desc(i, node);
+               set_bit(i, allocated_irqs);
+               irq_insert_desc(i, desc);
+       }
+       return arch_early_irq_init();
+}
+
+#else /* !CONFIG_SPARSE_IRQ */
+
+struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
+       [0 ... NR_IRQS-1] = {
+               .status         = IRQ_DEFAULT_INIT_FLAGS,
+               .handle_irq     = handle_bad_irq,
+               .depth          = 1,
+               .lock           = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
+       }
+};
+
+static unsigned int kstat_irqs_all[NR_IRQS][NR_CPUS];
+int __init early_irq_init(void)
+{
+       int count, i, node = first_online_node;
+       struct irq_desc *desc;
+
+       init_irq_default_affinity();
+
+       printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS);
+
+       desc = irq_desc;
+       count = ARRAY_SIZE(irq_desc);
+
+       for (i = 0; i < count; i++) {
+               desc[i].irq_data.irq = i;
+               desc[i].irq_data.chip = &no_irq_chip;
+               desc[i].kstat_irqs = kstat_irqs_all[i];
+               alloc_masks(desc + i, GFP_KERNEL, node);
+               desc_smp_init(desc + i, node);
+               lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
+       }
+       return arch_early_irq_init();
+}
+
+struct irq_desc *irq_to_desc(unsigned int irq)
+{
+       return (irq < NR_IRQS) ? irq_desc + irq : NULL;
+}
+
+struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node)
+{
+       return irq_to_desc(irq);
+}
+
+static void free_desc(unsigned int irq)
+{
+       dynamic_irq_cleanup(irq);
+}
+
+static inline int alloc_descs(unsigned int start, unsigned int cnt, int node)
+{
+       return start;
+}
+#endif /* !CONFIG_SPARSE_IRQ */
+
+/* Dynamic interrupt handling */
+
+/**
+ * irq_free_descs - free irq descriptors
+ * @from:      Start of descriptor range
+ * @cnt:       Number of consecutive irqs to free
+ */
+void irq_free_descs(unsigned int from, unsigned int cnt)
+{
+       int i;
+
+       if (from >= nr_irqs || (from + cnt) > nr_irqs)
+               return;
+
+       for (i = 0; i < cnt; i++)
+               free_desc(from + i);
+
+       mutex_lock(&sparse_irq_lock);
+       bitmap_clear(allocated_irqs, from, cnt);
+       mutex_unlock(&sparse_irq_lock);
+}
+
+/**
+ * irq_alloc_descs - allocate and initialize a range of irq descriptors
+ * @irq:       Allocate for specific irq number if irq >= 0
+ * @from:      Start the search from this irq number
+ * @cnt:       Number of consecutive irqs to allocate.
+ * @node:      Preferred node on which the irq descriptor should be allocated
+ *
+ * Returns the first irq number or error code
+ */
+int __ref
+irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node)
+{
+       int start, ret;
+
+       if (!cnt)
+               return -EINVAL;
+
+       mutex_lock(&sparse_irq_lock);
+
+       start = bitmap_find_next_zero_area(allocated_irqs, nr_irqs, from, cnt, 0);
+       ret = -EEXIST;
+       if (irq >=0 && start != irq)
+               goto err;
+
+       ret = -ENOMEM;
+       if (start >= nr_irqs)
+               goto err;
+
+       bitmap_set(allocated_irqs, start, cnt);
+       mutex_unlock(&sparse_irq_lock);
+       return alloc_descs(start, cnt, node);
+
+err:
+       mutex_unlock(&sparse_irq_lock);
+       return ret;
+}
+
+/**
+ * irq_reserve_irqs - mark irqs allocated
+ * @from:      mark from irq number
+ * @cnt:       number of irqs to mark
+ *
+ * Returns 0 on success or an appropriate error code
+ */
+int irq_reserve_irqs(unsigned int from, unsigned int cnt)
+{
+       unsigned int start;
+       int ret = 0;
+
+       if (!cnt || (from + cnt) > nr_irqs)
+               return -EINVAL;
+
+       mutex_lock(&sparse_irq_lock);
+       start = bitmap_find_next_zero_area(allocated_irqs, nr_irqs, from, cnt, 0);
+       if (start == from)
+               bitmap_set(allocated_irqs, start, cnt);
+       else
+               ret = -EEXIST;
+       mutex_unlock(&sparse_irq_lock);
+       return ret;
+}
+
+/**
+ * irq_get_next_irq - get next allocated irq number
+ * @offset:    where to start the search
+ *
+ * Returns next irq number after offset or nr_irqs if none is found.
+ */
+unsigned int irq_get_next_irq(unsigned int offset)
+{
+       return find_next_bit(allocated_irqs, nr_irqs, offset);
+}
+
+/**
+ * dynamic_irq_cleanup - cleanup a dynamically allocated irq
+ * @irq:       irq number to initialize
+ */
+void dynamic_irq_cleanup(unsigned int irq)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&desc->lock, flags);
+       desc_set_defaults(irq, desc, desc_node(desc));
+       raw_spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
+{
+       struct irq_desc *desc = irq_to_desc(irq);
+       return desc ? desc->kstat_irqs[cpu] : 0;
+}
index c3003e9d91a37da04c8c7ffc9aa5f986fc90fb04..644e8d5fa367e74c3cc06a2114f2e283c701b0e6 100644 (file)
@@ -73,8 +73,8 @@ int irq_can_set_affinity(unsigned int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
 
-       if (CHECK_IRQ_PER_CPU(desc->status) || !desc->chip ||
-           !desc->chip->set_affinity)
+       if (CHECK_IRQ_PER_CPU(desc->status) || !desc->irq_data.chip ||
+           !desc->irq_data.chip->irq_set_affinity)
                return 0;
 
        return 1;
@@ -109,17 +109,18 @@ void irq_set_thread_affinity(struct irq_desc *desc)
 int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
 {
        struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_chip *chip = desc->irq_data.chip;
        unsigned long flags;
 
-       if (!desc->chip->set_affinity)
+       if (!chip->irq_set_affinity)
                return -EINVAL;
 
        raw_spin_lock_irqsave(&desc->lock, flags);
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
        if (desc->status & IRQ_MOVE_PCNTXT) {
-               if (!desc->chip->set_affinity(irq, cpumask)) {
-                       cpumask_copy(desc->affinity, cpumask);
+               if (!chip->irq_set_affinity(&desc->irq_data, cpumask, false)) {
+                       cpumask_copy(desc->irq_data.affinity, cpumask);
                        irq_set_thread_affinity(desc);
                }
        }
@@ -128,8 +129,8 @@ int irq_set_affinity(unsigned int irq, const struct cpumask *cpumask)
                cpumask_copy(desc->pending_mask, cpumask);
        }
 #else
-       if (!desc->chip->set_affinity(irq, cpumask)) {
-               cpumask_copy(desc->affinity, cpumask);
+       if (!chip->irq_set_affinity(&desc->irq_data, cpumask, false)) {
+               cpumask_copy(desc->irq_data.affinity, cpumask);
                irq_set_thread_affinity(desc);
        }
 #endif
@@ -168,16 +169,16 @@ static int setup_affinity(unsigned int irq, struct irq_desc *desc)
         * one of the targets is online.
         */
        if (desc->status & (IRQ_AFFINITY_SET | IRQ_NO_BALANCING)) {
-               if (cpumask_any_and(desc->affinity, cpu_online_mask)
+               if (cpumask_any_and(desc->irq_data.affinity, cpu_online_mask)
                    < nr_cpu_ids)
                        goto set_affinity;
                else
                        desc->status &= ~IRQ_AFFINITY_SET;
        }
 
-       cpumask_and(desc->affinity, cpu_online_mask, irq_default_affinity);
+       cpumask_and(desc->irq_data.affinity, cpu_online_mask, irq_default_affinity);
 set_affinity:
-       desc->chip->set_affinity(irq, desc->affinity);
+       desc->irq_data.chip->irq_set_affinity(&desc->irq_data, desc->irq_data.affinity, false);
 
        return 0;
 }
@@ -223,7 +224,7 @@ void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
 
        if (!desc->depth++) {
                desc->status |= IRQ_DISABLED;
-               desc->chip->disable(irq);
+               desc->irq_data.chip->irq_disable(&desc->irq_data);
        }
 }
 
@@ -246,11 +247,11 @@ void disable_irq_nosync(unsigned int irq)
        if (!desc)
                return;
 
-       chip_bus_lock(irq, desc);
+       chip_bus_lock(desc);
        raw_spin_lock_irqsave(&desc->lock, flags);
        __disable_irq(desc, irq, false);
        raw_spin_unlock_irqrestore(&desc->lock, flags);
-       chip_bus_sync_unlock(irq, desc);
+       chip_bus_sync_unlock(desc);
 }
 EXPORT_SYMBOL(disable_irq_nosync);
 
@@ -313,7 +314,7 @@ void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume)
  *     IRQ line is re-enabled.
  *
  *     This function may be called from IRQ context only when
- *     desc->chip->bus_lock and desc->chip->bus_sync_unlock are NULL !
+ *     desc->irq_data.chip->bus_lock and desc->chip->bus_sync_unlock are NULL !
  */
 void enable_irq(unsigned int irq)
 {
@@ -323,11 +324,11 @@ void enable_irq(unsigned int irq)
        if (!desc)
                return;
 
-       chip_bus_lock(irq, desc);
+       chip_bus_lock(desc);
        raw_spin_lock_irqsave(&desc->lock, flags);
        __enable_irq(desc, irq, false);
        raw_spin_unlock_irqrestore(&desc->lock, flags);
-       chip_bus_sync_unlock(irq, desc);
+       chip_bus_sync_unlock(desc);
 }
 EXPORT_SYMBOL(enable_irq);
 
@@ -336,8 +337,8 @@ static int set_irq_wake_real(unsigned int irq, unsigned int on)
        struct irq_desc *desc = irq_to_desc(irq);
        int ret = -ENXIO;
 
-       if (desc->chip->set_wake)
-               ret = desc->chip->set_wake(irq, on);
+       if (desc->irq_data.chip->irq_set_wake)
+               ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on);
 
        return ret;
 }
@@ -429,12 +430,12 @@ void compat_irq_chip_set_default_handler(struct irq_desc *desc)
 }
 
 int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
-               unsigned long flags)
+                     unsigned long flags)
 {
        int ret;
-       struct irq_chip *chip = desc->chip;
+       struct irq_chip *chip = desc->irq_data.chip;
 
-       if (!chip || !chip->set_type) {
+       if (!chip || !chip->irq_set_type) {
                /*
                 * IRQF_TRIGGER_* but the PIC does not support multiple
                 * flow-types?
@@ -445,11 +446,11 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
        }
 
        /* caller masked out all except trigger mode flags */
-       ret = chip->set_type(irq, flags);
+       ret = chip->irq_set_type(&desc->irq_data, flags);
 
        if (ret)
-               pr_err("setting trigger mode %d for irq %u failed (%pF)\n",
-                               (int)flags, irq, chip->set_type);
+               pr_err("setting trigger mode %lu for irq %u failed (%pF)\n",
+                      flags, irq, chip->irq_set_type);
        else {
                if (flags & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
                        flags |= IRQ_LEVEL;
@@ -457,8 +458,8 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
                desc->status &= ~(IRQ_LEVEL | IRQ_TYPE_SENSE_MASK);
                desc->status |= flags;
 
-               if (chip != desc->chip)
-                       irq_chip_set_defaults(desc->chip);
+               if (chip != desc->irq_data.chip)
+                       irq_chip_set_defaults(desc->irq_data.chip);
        }
 
        return ret;
@@ -507,7 +508,7 @@ static int irq_wait_for_interrupt(struct irqaction *action)
 static void irq_finalize_oneshot(unsigned int irq, struct irq_desc *desc)
 {
 again:
-       chip_bus_lock(irq, desc);
+       chip_bus_lock(desc);
        raw_spin_lock_irq(&desc->lock);
 
        /*
@@ -521,17 +522,17 @@ again:
         */
        if (unlikely(desc->status & IRQ_INPROGRESS)) {
                raw_spin_unlock_irq(&desc->lock);
-               chip_bus_sync_unlock(irq, desc);
+               chip_bus_sync_unlock(desc);
                cpu_relax();
                goto again;
        }
 
        if (!(desc->status & IRQ_DISABLED) && (desc->status & IRQ_MASKED)) {
                desc->status &= ~IRQ_MASKED;
-               desc->chip->unmask(irq);
+               desc->irq_data.chip->irq_unmask(&desc->irq_data);
        }
        raw_spin_unlock_irq(&desc->lock);
-       chip_bus_sync_unlock(irq, desc);
+       chip_bus_sync_unlock(desc);
 }
 
 #ifdef CONFIG_SMP
@@ -556,7 +557,7 @@ irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action)
        }
 
        raw_spin_lock_irq(&desc->lock);
-       cpumask_copy(mask, desc->affinity);
+       cpumask_copy(mask, desc->irq_data.affinity);
        raw_spin_unlock_irq(&desc->lock);
 
        set_cpus_allowed_ptr(current, mask);
@@ -657,7 +658,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
        if (!desc)
                return -EINVAL;
 
-       if (desc->chip == &no_irq_chip)
+       if (desc->irq_data.chip == &no_irq_chip)
                return -ENOSYS;
        /*
         * Some drivers like serial.c use request_irq() heavily,
@@ -752,7 +753,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
        }
 
        if (!shared) {
-               irq_chip_set_defaults(desc->chip);
+               irq_chip_set_defaults(desc->irq_data.chip);
 
                init_waitqueue_head(&desc->wait_for_threads);
 
@@ -779,7 +780,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                if (!(desc->status & IRQ_NOAUTOEN)) {
                        desc->depth = 0;
                        desc->status &= ~IRQ_DISABLED;
-                       desc->chip->startup(irq);
+                       desc->irq_data.chip->irq_startup(&desc->irq_data);
                } else
                        /* Undo nested disables: */
                        desc->depth = 1;
@@ -912,17 +913,17 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
 
        /* Currently used only by UML, might disappear one day: */
 #ifdef CONFIG_IRQ_RELEASE_METHOD
-       if (desc->chip->release)
-               desc->chip->release(irq, dev_id);
+       if (desc->irq_data.chip->release)
+               desc->irq_data.chip->release(irq, dev_id);
 #endif
 
        /* If this was the last handler, shut down the IRQ line: */
        if (!desc->action) {
                desc->status |= IRQ_DISABLED;
-               if (desc->chip->shutdown)
-                       desc->chip->shutdown(irq);
+               if (desc->irq_data.chip->irq_shutdown)
+                       desc->irq_data.chip->irq_shutdown(&desc->irq_data);
                else
-                       desc->chip->disable(irq);
+                       desc->irq_data.chip->irq_disable(&desc->irq_data);
        }
 
 #ifdef CONFIG_SMP
@@ -997,9 +998,9 @@ void free_irq(unsigned int irq, void *dev_id)
        if (!desc)
                return;
 
-       chip_bus_lock(irq, desc);
+       chip_bus_lock(desc);
        kfree(__free_irq(irq, dev_id));
-       chip_bus_sync_unlock(irq, desc);
+       chip_bus_sync_unlock(desc);
 }
 EXPORT_SYMBOL(free_irq);
 
@@ -1086,9 +1087,9 @@ int request_threaded_irq(unsigned int irq, irq_handler_t handler,
        action->name = devname;
        action->dev_id = dev_id;
 
-       chip_bus_lock(irq, desc);
+       chip_bus_lock(desc);
        retval = __setup_irq(irq, desc, action);
-       chip_bus_sync_unlock(irq, desc);
+       chip_bus_sync_unlock(desc);
 
        if (retval)
                kfree(action);
index 241962280836ff73e8143dc8ebc63a83f53d9115..1d25419404803e60229dc15b1cc13980fe35db78 100644 (file)
@@ -7,6 +7,7 @@
 void move_masked_irq(int irq)
 {
        struct irq_desc *desc = irq_to_desc(irq);
+       struct irq_chip *chip = desc->irq_data.chip;
 
        if (likely(!(desc->status & IRQ_MOVE_PENDING)))
                return;
@@ -24,7 +25,7 @@ void move_masked_irq(int irq)
        if (unlikely(cpumask_empty(desc->pending_mask)))
                return;
 
-       if (!desc->chip->set_affinity)
+       if (!chip->irq_set_affinity)
                return;
 
        assert_raw_spin_locked(&desc->lock);
@@ -43,8 +44,9 @@ void move_masked_irq(int irq)
         */
        if (likely(cpumask_any_and(desc->pending_mask, cpu_online_mask)
                   < nr_cpu_ids))
-               if (!desc->chip->set_affinity(irq, desc->pending_mask)) {
-                       cpumask_copy(desc->affinity, desc->pending_mask);
+               if (!chip->irq_set_affinity(&desc->irq_data,
+                                           desc->pending_mask, false)) {
+                       cpumask_copy(desc->irq_data.affinity, desc->pending_mask);
                        irq_set_thread_affinity(desc);
                }
 
@@ -61,8 +63,8 @@ void move_native_irq(int irq)
        if (unlikely(desc->status & IRQ_DISABLED))
                return;
 
-       desc->chip->mask(irq);
+       desc->irq_data.chip->irq_mask(&desc->irq_data);
        move_masked_irq(irq);
-       desc->chip->unmask(irq);
+       desc->irq_data.chip->irq_unmask(&desc->irq_data);
 }
 
diff --git a/kernel/irq/numa_migrate.c b/kernel/irq/numa_migrate.c
deleted file mode 100644 (file)
index 65d3845..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * NUMA irq-desc migration code
- *
- * Migrate IRQ data structures (irq_desc, chip_data, etc.) over to
- * the new "home node" of the IRQ.
- */
-
-#include <linux/irq.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/random.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-
-#include "internals.h"
-
-static void init_copy_kstat_irqs(struct irq_desc *old_desc,
-                                struct irq_desc *desc,
-                                int node, int nr)
-{
-       init_kstat_irqs(desc, node, nr);
-
-       if (desc->kstat_irqs != old_desc->kstat_irqs)
-               memcpy(desc->kstat_irqs, old_desc->kstat_irqs,
-                        nr * sizeof(*desc->kstat_irqs));
-}
-
-static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc)
-{
-       if (old_desc->kstat_irqs == desc->kstat_irqs)
-               return;
-
-       kfree(old_desc->kstat_irqs);
-       old_desc->kstat_irqs = NULL;
-}
-
-static bool init_copy_one_irq_desc(int irq, struct irq_desc *old_desc,
-                struct irq_desc *desc, int node)
-{
-       memcpy(desc, old_desc, sizeof(struct irq_desc));
-       if (!alloc_desc_masks(desc, node, false)) {
-               printk(KERN_ERR "irq %d: can not get new irq_desc cpumask "
-                               "for migration.\n", irq);
-               return false;
-       }
-       raw_spin_lock_init(&desc->lock);
-       desc->node = node;
-       lockdep_set_class(&desc->lock, &irq_desc_lock_class);
-       init_copy_kstat_irqs(old_desc, desc, node, nr_cpu_ids);
-       init_copy_desc_masks(old_desc, desc);
-       arch_init_copy_chip_data(old_desc, desc, node);
-       return true;
-}
-
-static void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc)
-{
-       free_kstat_irqs(old_desc, desc);
-       free_desc_masks(old_desc, desc);
-       arch_free_chip_data(old_desc, desc);
-}
-
-static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc,
-                                               int node)
-{
-       struct irq_desc *desc;
-       unsigned int irq;
-       unsigned long flags;
-
-       irq = old_desc->irq;
-
-       raw_spin_lock_irqsave(&sparse_irq_lock, flags);
-
-       /* We have to check it to avoid races with another CPU */
-       desc = irq_to_desc(irq);
-
-       if (desc && old_desc != desc)
-               goto out_unlock;
-
-       desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
-       if (!desc) {
-               printk(KERN_ERR "irq %d: can not get new irq_desc "
-                               "for migration.\n", irq);
-               /* still use old one */
-               desc = old_desc;
-               goto out_unlock;
-       }
-       if (!init_copy_one_irq_desc(irq, old_desc, desc, node)) {
-               /* still use old one */
-               kfree(desc);
-               desc = old_desc;
-               goto out_unlock;
-       }
-
-       replace_irq_desc(irq, desc);
-       raw_spin_unlock_irqrestore(&sparse_irq_lock, flags);
-
-       /* free the old one */
-       free_one_irq_desc(old_desc, desc);
-       kfree(old_desc);
-
-       return desc;
-
-out_unlock:
-       raw_spin_unlock_irqrestore(&sparse_irq_lock, flags);
-
-       return desc;
-}
-
-struct irq_desc *move_irq_desc(struct irq_desc *desc, int node)
-{
-       /* those static or target node is -1, do not move them */
-       if (desc->irq < NR_IRQS_LEGACY || node == -1)
-               return desc;
-
-       if (desc->node != node)
-               desc = __real_move_irq_desc(desc, node);
-
-       return desc;
-}
-
index 09a2ee540bd246e127f07c653f262b22009488ae..01b1d3a88983f92c189e0c9b27f23ffe0e73f88f 100644 (file)
@@ -21,7 +21,7 @@ static struct proc_dir_entry *root_irq_dir;
 static int irq_affinity_proc_show(struct seq_file *m, void *v)
 {
        struct irq_desc *desc = irq_to_desc((long)m->private);
-       const struct cpumask *mask = desc->affinity;
+       const struct cpumask *mask = desc->irq_data.affinity;
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
        if (desc->status & IRQ_MOVE_PENDING)
@@ -65,7 +65,7 @@ static ssize_t irq_affinity_proc_write(struct file *file,
        cpumask_var_t new_value;
        int err;
 
-       if (!irq_to_desc(irq)->chip->set_affinity || no_irq_affinity ||
+       if (!irq_to_desc(irq)->irq_data.chip->irq_set_affinity || no_irq_affinity ||
            irq_balancing_disabled(irq))
                return -EIO;
 
@@ -185,7 +185,7 @@ static int irq_node_proc_show(struct seq_file *m, void *v)
 {
        struct irq_desc *desc = irq_to_desc((long) m->private);
 
-       seq_printf(m, "%d\n", desc->node);
+       seq_printf(m, "%d\n", desc->irq_data.node);
        return 0;
 }
 
@@ -269,7 +269,7 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
 {
        char name [MAX_NAMELEN];
 
-       if (!root_irq_dir || (desc->chip == &no_irq_chip) || desc->dir)
+       if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip) || desc->dir)
                return;
 
        memset(name, 0, MAX_NAMELEN);
@@ -297,6 +297,24 @@ void register_irq_proc(unsigned int irq, struct irq_desc *desc)
                         &irq_spurious_proc_fops, (void *)(long)irq);
 }
 
+void unregister_irq_proc(unsigned int irq, struct irq_desc *desc)
+{
+       char name [MAX_NAMELEN];
+
+       if (!root_irq_dir || !desc->dir)
+               return;
+#ifdef CONFIG_SMP
+       remove_proc_entry("smp_affinity", desc->dir);
+       remove_proc_entry("affinity_hint", desc->dir);
+       remove_proc_entry("node", desc->dir);
+#endif
+       remove_proc_entry("spurious", desc->dir);
+
+       memset(name, 0, MAX_NAMELEN);
+       sprintf(name, "%u", irq);
+       remove_proc_entry(name, root_irq_dir);
+}
+
 #undef MAX_NAMELEN
 
 void unregister_handler_proc(unsigned int irq, struct irqaction *action)
index 090c3763f3a294143b47d8a89cefff884fc1b826..891115a929aa1dfe223b01c5f50efbc0ec35a2f7 100644 (file)
@@ -60,7 +60,7 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq)
        /*
         * Make sure the interrupt is enabled, before resending it:
         */
-       desc->chip->enable(irq);
+       desc->irq_data.chip->irq_enable(&desc->irq_data);
 
        /*
         * We do not resend level type interrupts. Level type
@@ -70,7 +70,8 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq)
        if ((status & (IRQ_LEVEL | IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
                desc->status = (status & ~IRQ_PENDING) | IRQ_REPLAY;
 
-               if (!desc->chip->retrigger || !desc->chip->retrigger(irq)) {
+               if (!desc->irq_data.chip->irq_retrigger ||
+                   !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {
 #ifdef CONFIG_HARDIRQS_SW_RESEND
                        /* Set it pending and activate the softirq: */
                        set_bit(irq, irqs_resend);
index 89fb90ae534f551defdda8e43d7f1d274cb12b9e..3089d3b9d5f3912643d49bf46960fe7938a46e6a 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/moduleparam.h>
 #include <linux/timer.h>
 
+#include "internals.h"
+
 static int irqfixup __read_mostly;
 
 #define POLL_SPURIOUS_IRQ_INTERVAL (HZ/10)
@@ -78,8 +80,8 @@ static int try_one_irq(int irq, struct irq_desc *desc)
         * If we did actual work for the real IRQ line we must let the
         * IRQ controller clean up too
         */
-       if (work && desc->chip && desc->chip->end)
-               desc->chip->end(irq);
+       if (work)
+               irq_end(irq, desc);
        raw_spin_unlock(&desc->lock);
 
        return ok;
@@ -254,7 +256,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
                printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
                desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED;
                desc->depth++;
-               desc->chip->disable(irq);
+               desc->irq_data.chip->irq_disable(&desc->irq_data);
 
                mod_timer(&poll_spurious_irq_timer,
                          jiffies + POLL_SPURIOUS_IRQ_INTERVAL);
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
new file mode 100644 (file)
index 0000000..f16763f
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ *
+ * Provides a framework for enqueueing and running callbacks from hardirq
+ * context. The enqueueing is NMI-safe.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/irq_work.h>
+#include <linux/hardirq.h>
+
+/*
+ * An entry can be in one of four states:
+ *
+ * free             NULL, 0 -> {claimed}       : free to be used
+ * claimed   NULL, 3 -> {pending}       : claimed to be enqueued
+ * pending   next, 3 -> {busy}          : queued, pending callback
+ * busy      NULL, 2 -> {free, claimed} : callback in progress, can be claimed
+ *
+ * We use the lower two bits of the next pointer to keep PENDING and BUSY
+ * flags.
+ */
+
+#define IRQ_WORK_PENDING       1UL
+#define IRQ_WORK_BUSY          2UL
+#define IRQ_WORK_FLAGS         3UL
+
+static inline bool irq_work_is_set(struct irq_work *entry, int flags)
+{
+       return (unsigned long)entry->next & flags;
+}
+
+static inline struct irq_work *irq_work_next(struct irq_work *entry)
+{
+       unsigned long next = (unsigned long)entry->next;
+       next &= ~IRQ_WORK_FLAGS;
+       return (struct irq_work *)next;
+}
+
+static inline struct irq_work *next_flags(struct irq_work *entry, int flags)
+{
+       unsigned long next = (unsigned long)entry;
+       next |= flags;
+       return (struct irq_work *)next;
+}
+
+static DEFINE_PER_CPU(struct irq_work *, irq_work_list);
+
+/*
+ * Claim the entry so that no one else will poke at it.
+ */
+static bool irq_work_claim(struct irq_work *entry)
+{
+       struct irq_work *next, *nflags;
+
+       do {
+               next = entry->next;
+               if ((unsigned long)next & IRQ_WORK_PENDING)
+                       return false;
+               nflags = next_flags(next, IRQ_WORK_FLAGS);
+       } while (cmpxchg(&entry->next, next, nflags) != next);
+
+       return true;
+}
+
+
+void __weak arch_irq_work_raise(void)
+{
+       /*
+        * Lame architectures will get the timer tick callback
+        */
+}
+
+/*
+ * Queue the entry and raise the IPI if needed.
+ */
+static void __irq_work_queue(struct irq_work *entry)
+{
+       struct irq_work **head, *next;
+
+       head = &get_cpu_var(irq_work_list);
+
+       do {
+               next = *head;
+               /* Can assign non-atomic because we keep the flags set. */
+               entry->next = next_flags(next, IRQ_WORK_FLAGS);
+       } while (cmpxchg(head, next, entry) != next);
+
+       /* The list was empty, raise self-interrupt to start processing. */
+       if (!irq_work_next(entry))
+               arch_irq_work_raise();
+
+       put_cpu_var(irq_work_list);
+}
+
+/*
+ * Enqueue the irq_work @entry, returns true on success, failure when the
+ * @entry was already enqueued by someone else.
+ *
+ * Can be re-enqueued while the callback is still in progress.
+ */
+bool irq_work_queue(struct irq_work *entry)
+{
+       if (!irq_work_claim(entry)) {
+               /*
+                * Already enqueued, can't do!
+                */
+               return false;
+       }
+
+       __irq_work_queue(entry);
+       return true;
+}
+EXPORT_SYMBOL_GPL(irq_work_queue);
+
+/*
+ * Run the irq_work entries on this cpu. Requires to be ran from hardirq
+ * context with local IRQs disabled.
+ */
+void irq_work_run(void)
+{
+       struct irq_work *list, **head;
+
+       head = &__get_cpu_var(irq_work_list);
+       if (*head == NULL)
+               return;
+
+       BUG_ON(!in_irq());
+       BUG_ON(!irqs_disabled());
+
+       list = xchg(head, NULL);
+       while (list != NULL) {
+               struct irq_work *entry = list;
+
+               list = irq_work_next(list);
+
+               /*
+                * Clear the PENDING bit, after this point the @entry
+                * can be re-used.
+                */
+               entry->next = next_flags(NULL, IRQ_WORK_BUSY);
+               entry->func(entry);
+               /*
+                * Clear the BUSY bit and return to the free state if
+                * no-one else claimed it meanwhile.
+                */
+               cmpxchg(&entry->next, next_flags(NULL, IRQ_WORK_BUSY), NULL);
+       }
+}
+EXPORT_SYMBOL_GPL(irq_work_run);
+
+/*
+ * Synchronize against the irq_work @entry, ensures the entry is not
+ * currently in use.
+ */
+void irq_work_sync(struct irq_work *entry)
+{
+       WARN_ON_ONCE(irqs_disabled());
+
+       while (irq_work_is_set(entry, IRQ_WORK_BUSY))
+               cpu_relax();
+}
+EXPORT_SYMBOL_GPL(irq_work_sync);
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
new file mode 100644 (file)
index 0000000..7be868b
--- /dev/null
@@ -0,0 +1,429 @@
+/*
+ * jump label support
+ *
+ * Copyright (C) 2009 Jason Baron <jbaron@redhat.com>
+ *
+ */
+#include <linux/jump_label.h>
+#include <linux/memory.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/err.h>
+
+#ifdef HAVE_JUMP_LABEL
+
+#define JUMP_LABEL_HASH_BITS 6
+#define JUMP_LABEL_TABLE_SIZE (1 << JUMP_LABEL_HASH_BITS)
+static struct hlist_head jump_label_table[JUMP_LABEL_TABLE_SIZE];
+
+/* mutex to protect coming/going of the the jump_label table */
+static DEFINE_MUTEX(jump_label_mutex);
+
+struct jump_label_entry {
+       struct hlist_node hlist;
+       struct jump_entry *table;
+       int nr_entries;
+       /* hang modules off here */
+       struct hlist_head modules;
+       unsigned long key;
+};
+
+struct jump_label_module_entry {
+       struct hlist_node hlist;
+       struct jump_entry *table;
+       int nr_entries;
+       struct module *mod;
+};
+
+static int jump_label_cmp(const void *a, const void *b)
+{
+       const struct jump_entry *jea = a;
+       const struct jump_entry *jeb = b;
+
+       if (jea->key < jeb->key)
+               return -1;
+
+       if (jea->key > jeb->key)
+               return 1;
+
+       return 0;
+}
+
+static void
+sort_jump_label_entries(struct jump_entry *start, struct jump_entry *stop)
+{
+       unsigned long size;
+
+       size = (((unsigned long)stop - (unsigned long)start)
+                                       / sizeof(struct jump_entry));
+       sort(start, size, sizeof(struct jump_entry), jump_label_cmp, NULL);
+}
+
+static struct jump_label_entry *get_jump_label_entry(jump_label_t key)
+{
+       struct hlist_head *head;
+       struct hlist_node *node;
+       struct jump_label_entry *e;
+       u32 hash = jhash((void *)&key, sizeof(jump_label_t), 0);
+
+       head = &jump_label_table[hash & (JUMP_LABEL_TABLE_SIZE - 1)];
+       hlist_for_each_entry(e, node, head, hlist) {
+               if (key == e->key)
+                       return e;
+       }
+       return NULL;
+}
+
+static struct jump_label_entry *
+add_jump_label_entry(jump_label_t key, int nr_entries, struct jump_entry *table)
+{
+       struct hlist_head *head;
+       struct jump_label_entry *e;
+       u32 hash;
+
+       e = get_jump_label_entry(key);
+       if (e)
+               return ERR_PTR(-EEXIST);
+
+       e = kmalloc(sizeof(struct jump_label_entry), GFP_KERNEL);
+       if (!e)
+               return ERR_PTR(-ENOMEM);
+
+       hash = jhash((void *)&key, sizeof(jump_label_t), 0);
+       head = &jump_label_table[hash & (JUMP_LABEL_TABLE_SIZE - 1)];
+       e->key = key;
+       e->table = table;
+       e->nr_entries = nr_entries;
+       INIT_HLIST_HEAD(&(e->modules));
+       hlist_add_head(&e->hlist, head);
+       return e;
+}
+
+static int
+build_jump_label_hashtable(struct jump_entry *start, struct jump_entry *stop)
+{
+       struct jump_entry *iter, *iter_begin;
+       struct jump_label_entry *entry;
+       int count;
+
+       sort_jump_label_entries(start, stop);
+       iter = start;
+       while (iter < stop) {
+               entry = get_jump_label_entry(iter->key);
+               if (!entry) {
+                       iter_begin = iter;
+                       count = 0;
+                       while ((iter < stop) &&
+                               (iter->key == iter_begin->key)) {
+                               iter++;
+                               count++;
+                       }
+                       entry = add_jump_label_entry(iter_begin->key,
+                                                       count, iter_begin);
+                       if (IS_ERR(entry))
+                               return PTR_ERR(entry);
+                } else {
+                       WARN_ONCE(1, KERN_ERR "build_jump_hashtable: unexpected entry!\n");
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+/***
+ * jump_label_update - update jump label text
+ * @key -  key value associated with a a jump label
+ * @type - enum set to JUMP_LABEL_ENABLE or JUMP_LABEL_DISABLE
+ *
+ * Will enable/disable the jump for jump label @key, depending on the
+ * value of @type.
+ *
+ */
+
+void jump_label_update(unsigned long key, enum jump_label_type type)
+{
+       struct jump_entry *iter;
+       struct jump_label_entry *entry;
+       struct hlist_node *module_node;
+       struct jump_label_module_entry *e_module;
+       int count;
+
+       mutex_lock(&jump_label_mutex);
+       entry = get_jump_label_entry((jump_label_t)key);
+       if (entry) {
+               count = entry->nr_entries;
+               iter = entry->table;
+               while (count--) {
+                       if (kernel_text_address(iter->code))
+                               arch_jump_label_transform(iter, type);
+                       iter++;
+               }
+               /* eanble/disable jump labels in modules */
+               hlist_for_each_entry(e_module, module_node, &(entry->modules),
+                                                       hlist) {
+                       count = e_module->nr_entries;
+                       iter = e_module->table;
+                       while (count--) {
+                               if (kernel_text_address(iter->code))
+                                       arch_jump_label_transform(iter, type);
+                               iter++;
+                       }
+               }
+       }
+       mutex_unlock(&jump_label_mutex);
+}
+
+static int addr_conflict(struct jump_entry *entry, void *start, void *end)
+{
+       if (entry->code <= (unsigned long)end &&
+               entry->code + JUMP_LABEL_NOP_SIZE > (unsigned long)start)
+               return 1;
+
+       return 0;
+}
+
+#ifdef CONFIG_MODULES
+
+static int module_conflict(void *start, void *end)
+{
+       struct hlist_head *head;
+       struct hlist_node *node, *node_next, *module_node, *module_node_next;
+       struct jump_label_entry *e;
+       struct jump_label_module_entry *e_module;
+       struct jump_entry *iter;
+       int i, count;
+       int conflict = 0;
+
+       for (i = 0; i < JUMP_LABEL_TABLE_SIZE; i++) {
+               head = &jump_label_table[i];
+               hlist_for_each_entry_safe(e, node, node_next, head, hlist) {
+                       hlist_for_each_entry_safe(e_module, module_node,
+                                                       module_node_next,
+                                                       &(e->modules), hlist) {
+                               count = e_module->nr_entries;
+                               iter = e_module->table;
+                               while (count--) {
+                                       if (addr_conflict(iter, start, end)) {
+                                               conflict = 1;
+                                               goto out;
+                                       }
+                                       iter++;
+                               }
+                       }
+               }
+       }
+out:
+       return conflict;
+}
+
+#endif
+
+/***
+ * jump_label_text_reserved - check if addr range is reserved
+ * @start: start text addr
+ * @end: end text addr
+ *
+ * checks if the text addr located between @start and @end
+ * overlaps with any of the jump label patch addresses. Code
+ * that wants to modify kernel text should first verify that
+ * it does not overlap with any of the jump label addresses.
+ *
+ * returns 1 if there is an overlap, 0 otherwise
+ */
+int jump_label_text_reserved(void *start, void *end)
+{
+       struct jump_entry *iter;
+       struct jump_entry *iter_start = __start___jump_table;
+       struct jump_entry *iter_stop = __start___jump_table;
+       int conflict = 0;
+
+       mutex_lock(&jump_label_mutex);
+       iter = iter_start;
+       while (iter < iter_stop) {
+               if (addr_conflict(iter, start, end)) {
+                       conflict = 1;
+                       goto out;
+               }
+               iter++;
+       }
+
+       /* now check modules */
+#ifdef CONFIG_MODULES
+       conflict = module_conflict(start, end);
+#endif
+out:
+       mutex_unlock(&jump_label_mutex);
+       return conflict;
+}
+
+static __init int init_jump_label(void)
+{
+       int ret;
+       struct jump_entry *iter_start = __start___jump_table;
+       struct jump_entry *iter_stop = __stop___jump_table;
+       struct jump_entry *iter;
+
+       mutex_lock(&jump_label_mutex);
+       ret = build_jump_label_hashtable(__start___jump_table,
+                                        __stop___jump_table);
+       iter = iter_start;
+       while (iter < iter_stop) {
+               arch_jump_label_text_poke_early(iter->code);
+               iter++;
+       }
+       mutex_unlock(&jump_label_mutex);
+       return ret;
+}
+early_initcall(init_jump_label);
+
+#ifdef CONFIG_MODULES
+
+static struct jump_label_module_entry *
+add_jump_label_module_entry(struct jump_label_entry *entry,
+                           struct jump_entry *iter_begin,
+                           int count, struct module *mod)
+{
+       struct jump_label_module_entry *e;
+
+       e = kmalloc(sizeof(struct jump_label_module_entry), GFP_KERNEL);
+       if (!e)
+               return ERR_PTR(-ENOMEM);
+       e->mod = mod;
+       e->nr_entries = count;
+       e->table = iter_begin;
+       hlist_add_head(&e->hlist, &entry->modules);
+       return e;
+}
+
+static int add_jump_label_module(struct module *mod)
+{
+       struct jump_entry *iter, *iter_begin;
+       struct jump_label_entry *entry;
+       struct jump_label_module_entry *module_entry;
+       int count;
+
+       /* if the module doesn't have jump label entries, just return */
+       if (!mod->num_jump_entries)
+               return 0;
+
+       sort_jump_label_entries(mod->jump_entries,
+                               mod->jump_entries + mod->num_jump_entries);
+       iter = mod->jump_entries;
+       while (iter < mod->jump_entries + mod->num_jump_entries) {
+               entry = get_jump_label_entry(iter->key);
+               iter_begin = iter;
+               count = 0;
+               while ((iter < mod->jump_entries + mod->num_jump_entries) &&
+                       (iter->key == iter_begin->key)) {
+                               iter++;
+                               count++;
+               }
+               if (!entry) {
+                       entry = add_jump_label_entry(iter_begin->key, 0, NULL);
+                       if (IS_ERR(entry))
+                               return PTR_ERR(entry);
+               }
+               module_entry = add_jump_label_module_entry(entry, iter_begin,
+                                                          count, mod);
+               if (IS_ERR(module_entry))
+                       return PTR_ERR(module_entry);
+       }
+       return 0;
+}
+
+static void remove_jump_label_module(struct module *mod)
+{
+       struct hlist_head *head;
+       struct hlist_node *node, *node_next, *module_node, *module_node_next;
+       struct jump_label_entry *e;
+       struct jump_label_module_entry *e_module;
+       int i;
+
+       /* if the module doesn't have jump label entries, just return */
+       if (!mod->num_jump_entries)
+               return;
+
+       for (i = 0; i < JUMP_LABEL_TABLE_SIZE; i++) {
+               head = &jump_label_table[i];
+               hlist_for_each_entry_safe(e, node, node_next, head, hlist) {
+                       hlist_for_each_entry_safe(e_module, module_node,
+                                                 module_node_next,
+                                                 &(e->modules), hlist) {
+                               if (e_module->mod == mod) {
+                                       hlist_del(&e_module->hlist);
+                                       kfree(e_module);
+                               }
+                       }
+                       if (hlist_empty(&e->modules) && (e->nr_entries == 0)) {
+                               hlist_del(&e->hlist);
+                               kfree(e);
+                       }
+               }
+       }
+}
+
+static int
+jump_label_module_notify(struct notifier_block *self, unsigned long val,
+                        void *data)
+{
+       struct module *mod = data;
+       int ret = 0;
+
+       switch (val) {
+       case MODULE_STATE_COMING:
+               mutex_lock(&jump_label_mutex);
+               ret = add_jump_label_module(mod);
+               if (ret)
+                       remove_jump_label_module(mod);
+               mutex_unlock(&jump_label_mutex);
+               break;
+       case MODULE_STATE_GOING:
+               mutex_lock(&jump_label_mutex);
+               remove_jump_label_module(mod);
+               mutex_unlock(&jump_label_mutex);
+               break;
+       }
+       return ret;
+}
+
+/***
+ * apply_jump_label_nops - patch module jump labels with arch_get_jump_label_nop()
+ * @mod: module to patch
+ *
+ * Allow for run-time selection of the optimal nops. Before the module
+ * loads patch these with arch_get_jump_label_nop(), which is specified by
+ * the arch specific jump label code.
+ */
+void jump_label_apply_nops(struct module *mod)
+{
+       struct jump_entry *iter;
+
+       /* if the module doesn't have jump label entries, just return */
+       if (!mod->num_jump_entries)
+               return;
+
+       iter = mod->jump_entries;
+       while (iter < mod->jump_entries + mod->num_jump_entries) {
+               arch_jump_label_text_poke_early(iter->code);
+               iter++;
+       }
+}
+
+struct notifier_block jump_label_module_nb = {
+       .notifier_call = jump_label_module_notify,
+       .priority = 0,
+};
+
+static __init int init_jump_label_module(void)
+{
+       return register_module_notifier(&jump_label_module_nb);
+}
+early_initcall(init_jump_label_module);
+
+#endif /* CONFIG_MODULES */
+
+#endif
index 282035f3ae964e1e288f352c370be8edd11d3078..7c44133f51ec534eb0cb6a85224e9132f7eb60d9 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/memory.h>
 #include <linux/ftrace.h>
 #include <linux/cpu.h>
+#include <linux/jump_label.h>
 
 #include <asm-generic/sections.h>
 #include <asm/cacheflush.h>
@@ -73,7 +74,8 @@ static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
 /* NOTE: change this value only with kprobe_mutex held */
 static bool kprobes_all_disarmed;
 
-static DEFINE_MUTEX(kprobe_mutex);     /* Protects kprobe_table */
+/* This protects kprobe_table and optimizing_list */
+static DEFINE_MUTEX(kprobe_mutex);
 static DEFINE_PER_CPU(struct kprobe *, kprobe_instance) = NULL;
 static struct {
        spinlock_t lock ____cacheline_aligned_in_smp;
@@ -399,7 +401,7 @@ static inline int kprobe_optready(struct kprobe *p)
  * Return an optimized kprobe whose optimizing code replaces
  * instructions including addr (exclude breakpoint).
  */
-struct kprobe *__kprobes get_optimized_kprobe(unsigned long addr)
+static struct kprobe *__kprobes get_optimized_kprobe(unsigned long addr)
 {
        int i;
        struct kprobe *p = NULL;
@@ -594,6 +596,7 @@ static __kprobes void try_to_optimize_kprobe(struct kprobe *p)
 }
 
 #ifdef CONFIG_SYSCTL
+/* This should be called with kprobe_mutex locked */
 static void __kprobes optimize_all_kprobes(void)
 {
        struct hlist_head *head;
@@ -606,17 +609,16 @@ static void __kprobes optimize_all_kprobes(void)
                return;
 
        kprobes_allow_optimization = true;
-       mutex_lock(&text_mutex);
        for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
                head = &kprobe_table[i];
                hlist_for_each_entry_rcu(p, node, head, hlist)
                        if (!kprobe_disabled(p))
                                optimize_kprobe(p);
        }
-       mutex_unlock(&text_mutex);
        printk(KERN_INFO "Kprobes globally optimized\n");
 }
 
+/* This should be called with kprobe_mutex locked */
 static void __kprobes unoptimize_all_kprobes(void)
 {
        struct hlist_head *head;
@@ -831,6 +833,7 @@ void __kprobes recycle_rp_inst(struct kretprobe_instance *ri,
 
 void __kprobes kretprobe_hash_lock(struct task_struct *tsk,
                         struct hlist_head **head, unsigned long *flags)
+__acquires(hlist_lock)
 {
        unsigned long hash = hash_ptr(tsk, KPROBE_HASH_BITS);
        spinlock_t *hlist_lock;
@@ -842,6 +845,7 @@ void __kprobes kretprobe_hash_lock(struct task_struct *tsk,
 
 static void __kprobes kretprobe_table_lock(unsigned long hash,
        unsigned long *flags)
+__acquires(hlist_lock)
 {
        spinlock_t *hlist_lock = kretprobe_table_lock_ptr(hash);
        spin_lock_irqsave(hlist_lock, *flags);
@@ -849,6 +853,7 @@ static void __kprobes kretprobe_table_lock(unsigned long hash,
 
 void __kprobes kretprobe_hash_unlock(struct task_struct *tsk,
        unsigned long *flags)
+__releases(hlist_lock)
 {
        unsigned long hash = hash_ptr(tsk, KPROBE_HASH_BITS);
        spinlock_t *hlist_lock;
@@ -857,7 +862,9 @@ void __kprobes kretprobe_hash_unlock(struct task_struct *tsk,
        spin_unlock_irqrestore(hlist_lock, *flags);
 }
 
-void __kprobes kretprobe_table_unlock(unsigned long hash, unsigned long *flags)
+static void __kprobes kretprobe_table_unlock(unsigned long hash,
+       unsigned long *flags)
+__releases(hlist_lock)
 {
        spinlock_t *hlist_lock = kretprobe_table_lock_ptr(hash);
        spin_unlock_irqrestore(hlist_lock, *flags);
@@ -1141,7 +1148,8 @@ int __kprobes register_kprobe(struct kprobe *p)
        preempt_disable();
        if (!kernel_text_address((unsigned long) p->addr) ||
            in_kprobes_functions((unsigned long) p->addr) ||
-           ftrace_text_reserved(p->addr, p->addr)) {
+           ftrace_text_reserved(p->addr, p->addr) ||
+           jump_label_text_reserved(p->addr, p->addr)) {
                preempt_enable();
                return -EINVAL;
        }
@@ -1339,18 +1347,19 @@ int __kprobes register_jprobes(struct jprobe **jps, int num)
        if (num <= 0)
                return -EINVAL;
        for (i = 0; i < num; i++) {
-               unsigned long addr;
+               unsigned long addr, offset;
                jp = jps[i];
                addr = arch_deref_entry_point(jp->entry);
 
-               if (!kernel_text_address(addr))
-                       ret = -EINVAL;
-               else {
-                       /* Todo: Verify probepoint is a function entry point */
+               /* Verify probepoint is a function entry point */
+               if (kallsyms_lookup_size_offset(addr, NULL, &offset) &&
+                   offset == 0) {
                        jp->kp.pre_handler = setjmp_pre_handler;
                        jp->kp.break_handler = longjmp_break_handler;
                        ret = register_kprobe(&jp->kp);
-               }
+               } else
+                       ret = -EINVAL;
+
                if (ret < 0) {
                        if (i > 0)
                                unregister_jprobes(jps, i);
index f2852a5102327f74c39531a517e488c0d1e673e5..42ba65dff7d99e4eeadfe6175d70c2f9665ad431 100644 (file)
@@ -639,6 +639,16 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
        }
 #endif
 
+       if (unlikely(subclass >= MAX_LOCKDEP_SUBCLASSES)) {
+               debug_locks_off();
+               printk(KERN_ERR
+                       "BUG: looking up invalid subclass: %u\n", subclass);
+               printk(KERN_ERR
+                       "turning off the locking correctness validator.\n");
+               dump_stack();
+               return NULL;
+       }
+
        /*
         * Static locks do not have their class-keys yet - for them the key
         * is the lock object itself:
@@ -774,7 +784,9 @@ out_unlock_set:
        raw_local_irq_restore(flags);
 
        if (!subclass || force)
-               lock->class_cache = class;
+               lock->class_cache[0] = class;
+       else if (subclass < NR_LOCKDEP_CACHING_CLASSES)
+               lock->class_cache[subclass] = class;
 
        if (DEBUG_LOCKS_WARN_ON(class->subclass != subclass))
                return NULL;
@@ -2679,7 +2691,11 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
 void lockdep_init_map(struct lockdep_map *lock, const char *name,
                      struct lock_class_key *key, int subclass)
 {
-       lock->class_cache = NULL;
+       int i;
+
+       for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++)
+               lock->class_cache[i] = NULL;
+
 #ifdef CONFIG_LOCK_STAT
        lock->cpu = raw_smp_processor_id();
 #endif
@@ -2739,21 +2755,13 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
        if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
                return 0;
 
-       if (unlikely(subclass >= MAX_LOCKDEP_SUBCLASSES)) {
-               debug_locks_off();
-               printk("BUG: MAX_LOCKDEP_SUBCLASSES too low!\n");
-               printk("turning off the locking correctness validator.\n");
-               dump_stack();
-               return 0;
-       }
-
        if (lock->key == &__lockdep_no_validate__)
                check = 1;
 
-       if (!subclass)
-               class = lock->class_cache;
+       if (subclass < NR_LOCKDEP_CACHING_CLASSES)
+               class = lock->class_cache[subclass];
        /*
-        * Not cached yet or subclass?
+        * Not cached?
         */
        if (unlikely(!class)) {
                class = register_lock_class(lock, subclass, 0);
@@ -2918,7 +2926,7 @@ static int match_held_lock(struct held_lock *hlock, struct lockdep_map *lock)
                return 1;
 
        if (hlock->references) {
-               struct lock_class *class = lock->class_cache;
+               struct lock_class *class = lock->class_cache[0];
 
                if (!class)
                        class = look_up_lock_class(lock, 0);
@@ -3559,7 +3567,12 @@ void lockdep_reset_lock(struct lockdep_map *lock)
                if (list_empty(head))
                        continue;
                list_for_each_entry_safe(class, next, head, hash_entry) {
-                       if (unlikely(class == lock->class_cache)) {
+                       int match = 0;
+
+                       for (j = 0; j < NR_LOCKDEP_CACHING_CLASSES; j++)
+                               match |= class == lock->class_cache[j];
+
+                       if (unlikely(match)) {
                                if (debug_locks_off_graph_unlock())
                                        WARN_ON(1);
                                goto out_restore;
@@ -3775,7 +3788,7 @@ EXPORT_SYMBOL_GPL(debug_show_all_locks);
  * Careful: only use this function if you are sure that
  * the task cannot run in parallel!
  */
-void __debug_show_held_locks(struct task_struct *task)
+void debug_show_held_locks(struct task_struct *task)
 {
        if (unlikely(!debug_locks)) {
                printk("INFO: lockdep is turned off.\n");
@@ -3783,12 +3796,6 @@ void __debug_show_held_locks(struct task_struct *task)
        }
        lockdep_print_held_locks(task);
 }
-EXPORT_SYMBOL_GPL(__debug_show_held_locks);
-
-void debug_show_held_locks(struct task_struct *task)
-{
-               __debug_show_held_locks(task);
-}
 EXPORT_SYMBOL_GPL(debug_show_held_locks);
 
 void lockdep_sys_exit(void)
index ccd641991842f4990906946f895fd5062a0389c3..2df46301a7a407dcde3435542e38f6944358d7c1 100644 (file)
@@ -55,6 +55,7 @@
 #include <linux/async.h>
 #include <linux/percpu.h>
 #include <linux/kmemleak.h>
+#include <linux/jump_label.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/module.h>
@@ -2309,6 +2310,11 @@ static void find_module_sections(struct module *mod, struct load_info *info)
                                        sizeof(*mod->tracepoints),
                                        &mod->num_tracepoints);
 #endif
+#ifdef HAVE_JUMP_LABEL
+       mod->jump_entries = section_objs(info, "__jump_table",
+                                       sizeof(*mod->jump_entries),
+                                       &mod->num_jump_entries);
+#endif
 #ifdef CONFIG_EVENT_TRACING
        mod->trace_events = section_objs(info, "_ftrace_events",
                                         sizeof(*mod->trace_events),
index b98bed3d8182685ffff2b840c0ff4809b4f65cb8..517d827f498281da50210aa76a02b4693116154a 100644 (file)
 #include <linux/kernel_stat.h>
 #include <linux/perf_event.h>
 #include <linux/ftrace_event.h>
-#include <linux/hw_breakpoint.h>
 
 #include <asm/irq_regs.h>
 
-/*
- * Each CPU has a list of per CPU events:
- */
-static DEFINE_PER_CPU(struct perf_cpu_context, perf_cpu_context);
-
-int perf_max_events __read_mostly = 1;
-static int perf_reserved_percpu __read_mostly;
-static int perf_overcommit __read_mostly = 1;
-
-static atomic_t nr_events __read_mostly;
+atomic_t perf_task_events __read_mostly;
 static atomic_t nr_mmap_events __read_mostly;
 static atomic_t nr_comm_events __read_mostly;
 static atomic_t nr_task_events __read_mostly;
 
+static LIST_HEAD(pmus);
+static DEFINE_MUTEX(pmus_lock);
+static struct srcu_struct pmus_srcu;
+
 /*
  * perf event paranoia level:
  *  -1 - not paranoid at all
@@ -67,36 +61,43 @@ int sysctl_perf_event_sample_rate __read_mostly = 100000;
 
 static atomic64_t perf_event_id;
 
-/*
- * Lock for (sysadmin-configurable) event reservations:
- */
-static DEFINE_SPINLOCK(perf_resource_lock);
+void __weak perf_event_print_debug(void)       { }
 
-/*
- * Architecture provided APIs - weak aliases:
- */
-extern __weak const struct pmu *hw_perf_event_init(struct perf_event *event)
+extern __weak const char *perf_pmu_name(void)
 {
-       return NULL;
+       return "pmu";
 }
 
-void __weak hw_perf_disable(void)              { barrier(); }
-void __weak hw_perf_enable(void)               { barrier(); }
-
-void __weak perf_event_print_debug(void)       { }
-
-static DEFINE_PER_CPU(int, perf_disable_count);
+void perf_pmu_disable(struct pmu *pmu)
+{
+       int *count = this_cpu_ptr(pmu->pmu_disable_count);
+       if (!(*count)++)
+               pmu->pmu_disable(pmu);
+}
 
-void perf_disable(void)
+void perf_pmu_enable(struct pmu *pmu)
 {
-       if (!__get_cpu_var(perf_disable_count)++)
-               hw_perf_disable();
+       int *count = this_cpu_ptr(pmu->pmu_disable_count);
+       if (!--(*count))
+               pmu->pmu_enable(pmu);
 }
 
-void perf_enable(void)
+static DEFINE_PER_CPU(struct list_head, rotation_list);
+
+/*
+ * perf_pmu_rotate_start() and perf_rotate_context() are fully serialized
+ * because they're strictly cpu affine and rotate_start is called with IRQs
+ * disabled, while rotate_context is called from IRQ context.
+ */
+static void perf_pmu_rotate_start(struct pmu *pmu)
 {
-       if (!--__get_cpu_var(perf_disable_count))
-               hw_perf_enable();
+       struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+       struct list_head *head = &__get_cpu_var(rotation_list);
+
+       WARN_ON(!irqs_disabled());
+
+       if (list_empty(&cpuctx->rotation_list))
+               list_add(&cpuctx->rotation_list, head);
 }
 
 static void get_ctx(struct perf_event_context *ctx)
@@ -151,13 +152,13 @@ static u64 primary_event_id(struct perf_event *event)
  * the context could get moved to another task.
  */
 static struct perf_event_context *
-perf_lock_task_context(struct task_struct *task, unsigned long *flags)
+perf_lock_task_context(struct task_struct *task, int ctxn, unsigned long *flags)
 {
        struct perf_event_context *ctx;
 
        rcu_read_lock();
- retry:
-       ctx = rcu_dereference(task->perf_event_ctxp);
+retry:
+       ctx = rcu_dereference(task->perf_event_ctxp[ctxn]);
        if (ctx) {
                /*
                 * If this context is a clone of another, it might
@@ -170,7 +171,7 @@ perf_lock_task_context(struct task_struct *task, unsigned long *flags)
                 * can't get swapped on us any more.
                 */
                raw_spin_lock_irqsave(&ctx->lock, *flags);
-               if (ctx != rcu_dereference(task->perf_event_ctxp)) {
+               if (ctx != rcu_dereference(task->perf_event_ctxp[ctxn])) {
                        raw_spin_unlock_irqrestore(&ctx->lock, *flags);
                        goto retry;
                }
@@ -189,12 +190,13 @@ perf_lock_task_context(struct task_struct *task, unsigned long *flags)
  * can't get swapped to another task.  This also increments its
  * reference count so that the context can't get freed.
  */
-static struct perf_event_context *perf_pin_task_context(struct task_struct *task)
+static struct perf_event_context *
+perf_pin_task_context(struct task_struct *task, int ctxn)
 {
        struct perf_event_context *ctx;
        unsigned long flags;
 
-       ctx = perf_lock_task_context(task, &flags);
+       ctx = perf_lock_task_context(task, ctxn, &flags);
        if (ctx) {
                ++ctx->pin_count;
                raw_spin_unlock_irqrestore(&ctx->lock, flags);
@@ -302,6 +304,8 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
        }
 
        list_add_rcu(&event->event_entry, &ctx->event_list);
+       if (!ctx->nr_events)
+               perf_pmu_rotate_start(ctx->pmu);
        ctx->nr_events++;
        if (event->attr.inherit_stat)
                ctx->nr_stat++;
@@ -311,7 +315,12 @@ static void perf_group_attach(struct perf_event *event)
 {
        struct perf_event *group_leader = event->group_leader;
 
-       WARN_ON_ONCE(event->attach_state & PERF_ATTACH_GROUP);
+       /*
+        * We can have double attach due to group movement in perf_event_open.
+        */
+       if (event->attach_state & PERF_ATTACH_GROUP)
+               return;
+
        event->attach_state |= PERF_ATTACH_GROUP;
 
        if (group_leader == event)
@@ -436,7 +445,7 @@ event_sched_out(struct perf_event *event,
                event->state = PERF_EVENT_STATE_OFF;
        }
        event->tstamp_stopped = ctx->time;
-       event->pmu->disable(event);
+       event->pmu->del(event, 0);
        event->oncpu = -1;
 
        if (!is_software_event(event))
@@ -466,6 +475,12 @@ group_sched_out(struct perf_event *group_event,
                cpuctx->exclusive = 0;
 }
 
+static inline struct perf_cpu_context *
+__get_cpu_context(struct perf_event_context *ctx)
+{
+       return this_cpu_ptr(ctx->pmu->pmu_cpu_context);
+}
+
 /*
  * Cross CPU call to remove a performance event
  *
@@ -474,9 +489,9 @@ group_sched_out(struct perf_event *group_event,
  */
 static void __perf_event_remove_from_context(void *info)
 {
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
        struct perf_event *event = info;
        struct perf_event_context *ctx = event->ctx;
+       struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
 
        /*
         * If this is a task context, we need to check whether it is
@@ -487,27 +502,11 @@ static void __perf_event_remove_from_context(void *info)
                return;
 
        raw_spin_lock(&ctx->lock);
-       /*
-        * Protect the list operation against NMI by disabling the
-        * events on a global level.
-        */
-       perf_disable();
 
        event_sched_out(event, cpuctx, ctx);
 
        list_del_event(event, ctx);
 
-       if (!ctx->task) {
-               /*
-                * Allow more per task events with respect to the
-                * reservation:
-                */
-               cpuctx->max_pertask =
-                       min(perf_max_events - ctx->nr_events,
-                           perf_max_events - perf_reserved_percpu);
-       }
-
-       perf_enable();
        raw_spin_unlock(&ctx->lock);
 }
 
@@ -572,8 +571,8 @@ retry:
 static void __perf_event_disable(void *info)
 {
        struct perf_event *event = info;
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
        struct perf_event_context *ctx = event->ctx;
+       struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
 
        /*
         * If this is a per-task event, need to check whether this
@@ -628,7 +627,7 @@ void perf_event_disable(struct perf_event *event)
                return;
        }
 
- retry:
+retry:
        task_oncpu_function_call(task, __perf_event_disable, event);
 
        raw_spin_lock_irq(&ctx->lock);
@@ -667,7 +666,7 @@ event_sched_in(struct perf_event *event,
         */
        smp_wmb();
 
-       if (event->pmu->enable(event)) {
+       if (event->pmu->add(event, PERF_EF_START)) {
                event->state = PERF_EVENT_STATE_INACTIVE;
                event->oncpu = -1;
                return -EAGAIN;
@@ -691,22 +690,17 @@ group_sched_in(struct perf_event *group_event,
               struct perf_event_context *ctx)
 {
        struct perf_event *event, *partial_group = NULL;
-       const struct pmu *pmu = group_event->pmu;
-       bool txn = false;
+       struct pmu *pmu = group_event->pmu;
+       u64 now = ctx->time;
+       bool simulate = false;
 
        if (group_event->state == PERF_EVENT_STATE_OFF)
                return 0;
 
-       /* Check if group transaction availabe */
-       if (pmu->start_txn)
-               txn = true;
-
-       if (txn)
-               pmu->start_txn(pmu);
+       pmu->start_txn(pmu);
 
        if (event_sched_in(group_event, cpuctx, ctx)) {
-               if (txn)
-                       pmu->cancel_txn(pmu);
+               pmu->cancel_txn(pmu);
                return -EAGAIN;
        }
 
@@ -720,23 +714,38 @@ group_sched_in(struct perf_event *group_event,
                }
        }
 
-       if (!txn || !pmu->commit_txn(pmu))
+       if (!pmu->commit_txn(pmu))
                return 0;
 
 group_error:
        /*
         * Groups can be scheduled in as one unit only, so undo any
         * partial group before returning:
+        * The events up to the failed event are scheduled out normally,
+        * tstamp_stopped will be updated.
+        *
+        * The failed events and the remaining siblings need to have
+        * their timings updated as if they had gone thru event_sched_in()
+        * and event_sched_out(). This is required to get consistent timings
+        * across the group. This also takes care of the case where the group
+        * could never be scheduled by ensuring tstamp_stopped is set to mark
+        * the time the event was actually stopped, such that time delta
+        * calculation in update_event_times() is correct.
         */
        list_for_each_entry(event, &group_event->sibling_list, group_entry) {
                if (event == partial_group)
-                       break;
-               event_sched_out(event, cpuctx, ctx);
+                       simulate = true;
+
+               if (simulate) {
+                       event->tstamp_running += now - event->tstamp_stopped;
+                       event->tstamp_stopped = now;
+               } else {
+                       event_sched_out(event, cpuctx, ctx);
+               }
        }
        event_sched_out(group_event, cpuctx, ctx);
 
-       if (txn)
-               pmu->cancel_txn(pmu);
+       pmu->cancel_txn(pmu);
 
        return -EAGAIN;
 }
@@ -789,10 +798,10 @@ static void add_event_to_ctx(struct perf_event *event,
  */
 static void __perf_install_in_context(void *info)
 {
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
        struct perf_event *event = info;
        struct perf_event_context *ctx = event->ctx;
        struct perf_event *leader = event->group_leader;
+       struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
        int err;
 
        /*
@@ -812,12 +821,6 @@ static void __perf_install_in_context(void *info)
        ctx->is_active = 1;
        update_context_time(ctx);
 
-       /*
-        * Protect the list operation against NMI by disabling the
-        * events on a global level. NOP for non NMI based events.
-        */
-       perf_disable();
-
        add_event_to_ctx(event, ctx);
 
        if (event->cpu != -1 && event->cpu != smp_processor_id())
@@ -855,12 +858,7 @@ static void __perf_install_in_context(void *info)
                }
        }
 
-       if (!err && !ctx->task && cpuctx->max_pertask)
-               cpuctx->max_pertask--;
-
- unlock:
-       perf_enable();
-
+unlock:
        raw_spin_unlock(&ctx->lock);
 }
 
@@ -883,6 +881,8 @@ perf_install_in_context(struct perf_event_context *ctx,
 {
        struct task_struct *task = ctx->task;
 
+       event->ctx = ctx;
+
        if (!task) {
                /*
                 * Per cpu events are installed via an smp call and
@@ -931,10 +931,12 @@ static void __perf_event_mark_enabled(struct perf_event *event,
 
        event->state = PERF_EVENT_STATE_INACTIVE;
        event->tstamp_enabled = ctx->time - event->total_time_enabled;
-       list_for_each_entry(sub, &event->sibling_list, group_entry)
-               if (sub->state >= PERF_EVENT_STATE_INACTIVE)
+       list_for_each_entry(sub, &event->sibling_list, group_entry) {
+               if (sub->state >= PERF_EVENT_STATE_INACTIVE) {
                        sub->tstamp_enabled =
                                ctx->time - sub->total_time_enabled;
+               }
+       }
 }
 
 /*
@@ -943,9 +945,9 @@ static void __perf_event_mark_enabled(struct perf_event *event,
 static void __perf_event_enable(void *info)
 {
        struct perf_event *event = info;
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
        struct perf_event_context *ctx = event->ctx;
        struct perf_event *leader = event->group_leader;
+       struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
        int err;
 
        /*
@@ -979,12 +981,10 @@ static void __perf_event_enable(void *info)
        if (!group_can_go_on(event, cpuctx, 1)) {
                err = -EEXIST;
        } else {
-               perf_disable();
                if (event == leader)
                        err = group_sched_in(event, cpuctx, ctx);
                else
                        err = event_sched_in(event, cpuctx, ctx);
-               perf_enable();
        }
 
        if (err) {
@@ -1000,7 +1000,7 @@ static void __perf_event_enable(void *info)
                }
        }
 
- unlock:
+unlock:
        raw_spin_unlock(&ctx->lock);
 }
 
@@ -1041,7 +1041,7 @@ void perf_event_enable(struct perf_event *event)
        if (event->state == PERF_EVENT_STATE_ERROR)
                event->state = PERF_EVENT_STATE_OFF;
 
- retry:
+retry:
        raw_spin_unlock_irq(&ctx->lock);
        task_oncpu_function_call(task, __perf_event_enable, event);
 
@@ -1061,7 +1061,7 @@ void perf_event_enable(struct perf_event *event)
        if (event->state == PERF_EVENT_STATE_OFF)
                __perf_event_mark_enabled(event, ctx);
 
- out:
+out:
        raw_spin_unlock_irq(&ctx->lock);
 }
 
@@ -1092,26 +1092,26 @@ static void ctx_sched_out(struct perf_event_context *ctx,
        struct perf_event *event;
 
        raw_spin_lock(&ctx->lock);
+       perf_pmu_disable(ctx->pmu);
        ctx->is_active = 0;
        if (likely(!ctx->nr_events))
                goto out;
        update_context_time(ctx);
 
-       perf_disable();
        if (!ctx->nr_active)
-               goto out_enable;
+               goto out;
 
-       if (event_type & EVENT_PINNED)
+       if (event_type & EVENT_PINNED) {
                list_for_each_entry(event, &ctx->pinned_groups, group_entry)
                        group_sched_out(event, cpuctx, ctx);
+       }
 
-       if (event_type & EVENT_FLEXIBLE)
+       if (event_type & EVENT_FLEXIBLE) {
                list_for_each_entry(event, &ctx->flexible_groups, group_entry)
                        group_sched_out(event, cpuctx, ctx);
-
- out_enable:
-       perf_enable();
- out:
+       }
+out:
+       perf_pmu_enable(ctx->pmu);
        raw_spin_unlock(&ctx->lock);
 }
 
@@ -1209,34 +1209,25 @@ static void perf_event_sync_stat(struct perf_event_context *ctx,
        }
 }
 
-/*
- * Called from scheduler to remove the events of the current task,
- * with interrupts disabled.
- *
- * We stop each event and update the event value in event->count.
- *
- * This does not protect us against NMI, but disable()
- * sets the disabled bit in the control field of event _before_
- * accessing the event control register. If a NMI hits, then it will
- * not restart the event.
- */
-void perf_event_task_sched_out(struct task_struct *task,
-                                struct task_struct *next)
+void perf_event_context_sched_out(struct task_struct *task, int ctxn,
+                                 struct task_struct *next)
 {
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
-       struct perf_event_context *ctx = task->perf_event_ctxp;
+       struct perf_event_context *ctx = task->perf_event_ctxp[ctxn];
        struct perf_event_context *next_ctx;
        struct perf_event_context *parent;
+       struct perf_cpu_context *cpuctx;
        int do_switch = 1;
 
-       perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0);
+       if (likely(!ctx))
+               return;
 
-       if (likely(!ctx || !cpuctx->task_ctx))
+       cpuctx = __get_cpu_context(ctx);
+       if (!cpuctx->task_ctx)
                return;
 
        rcu_read_lock();
        parent = rcu_dereference(ctx->parent_ctx);
-       next_ctx = next->perf_event_ctxp;
+       next_ctx = next->perf_event_ctxp[ctxn];
        if (parent && next_ctx &&
            rcu_dereference(next_ctx->parent_ctx) == parent) {
                /*
@@ -1255,8 +1246,8 @@ void perf_event_task_sched_out(struct task_struct *task,
                         * XXX do we need a memory barrier of sorts
                         * wrt to rcu_dereference() of perf_event_ctxp
                         */
-                       task->perf_event_ctxp = next_ctx;
-                       next->perf_event_ctxp = ctx;
+                       task->perf_event_ctxp[ctxn] = next_ctx;
+                       next->perf_event_ctxp[ctxn] = ctx;
                        ctx->task = next;
                        next_ctx->task = task;
                        do_switch = 0;
@@ -1274,10 +1265,35 @@ void perf_event_task_sched_out(struct task_struct *task,
        }
 }
 
+#define for_each_task_context_nr(ctxn)                                 \
+       for ((ctxn) = 0; (ctxn) < perf_nr_task_contexts; (ctxn)++)
+
+/*
+ * Called from scheduler to remove the events of the current task,
+ * with interrupts disabled.
+ *
+ * We stop each event and update the event value in event->count.
+ *
+ * This does not protect us against NMI, but disable()
+ * sets the disabled bit in the control field of event _before_
+ * accessing the event control register. If a NMI hits, then it will
+ * not restart the event.
+ */
+void __perf_event_task_sched_out(struct task_struct *task,
+                                struct task_struct *next)
+{
+       int ctxn;
+
+       perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0);
+
+       for_each_task_context_nr(ctxn)
+               perf_event_context_sched_out(task, ctxn, next);
+}
+
 static void task_ctx_sched_out(struct perf_event_context *ctx,
                               enum event_type_t event_type)
 {
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
+       struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
 
        if (!cpuctx->task_ctx)
                return;
@@ -1289,14 +1305,6 @@ static void task_ctx_sched_out(struct perf_event_context *ctx,
        cpuctx->task_ctx = NULL;
 }
 
-/*
- * Called with IRQs disabled
- */
-static void __perf_event_task_sched_out(struct perf_event_context *ctx)
-{
-       task_ctx_sched_out(ctx, EVENT_ALL);
-}
-
 /*
  * Called with IRQs disabled
  */
@@ -1350,9 +1358,10 @@ ctx_flexible_sched_in(struct perf_event_context *ctx,
                if (event->cpu != -1 && event->cpu != smp_processor_id())
                        continue;
 
-               if (group_can_go_on(event, cpuctx, can_add_hw))
+               if (group_can_go_on(event, cpuctx, can_add_hw)) {
                        if (group_sched_in(event, cpuctx, ctx))
                                can_add_hw = 0;
+               }
        }
 }
 
@@ -1368,8 +1377,6 @@ ctx_sched_in(struct perf_event_context *ctx,
 
        ctx->timestamp = perf_clock();
 
-       perf_disable();
-
        /*
         * First go through the list and put on any pinned groups
         * in order to give them the best chance of going on.
@@ -1381,8 +1388,7 @@ ctx_sched_in(struct perf_event_context *ctx,
        if (event_type & EVENT_FLEXIBLE)
                ctx_flexible_sched_in(ctx, cpuctx);
 
-       perf_enable();
- out:
+out:
        raw_spin_unlock(&ctx->lock);
 }
 
@@ -1394,43 +1400,28 @@ static void cpu_ctx_sched_in(struct perf_cpu_context *cpuctx,
        ctx_sched_in(ctx, cpuctx, event_type);
 }
 
-static void task_ctx_sched_in(struct task_struct *task,
+static void task_ctx_sched_in(struct perf_event_context *ctx,
                              enum event_type_t event_type)
 {
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
-       struct perf_event_context *ctx = task->perf_event_ctxp;
+       struct perf_cpu_context *cpuctx;
 
-       if (likely(!ctx))
-               return;
+               cpuctx = __get_cpu_context(ctx);
        if (cpuctx->task_ctx == ctx)
                return;
+
        ctx_sched_in(ctx, cpuctx, event_type);
        cpuctx->task_ctx = ctx;
 }
-/*
- * Called from scheduler to add the events of the current task
- * with interrupts disabled.
- *
- * We restore the event value and then enable it.
- *
- * This does not protect us against NMI, but enable()
- * sets the enabled bit in the control field of event _before_
- * accessing the event control register. If a NMI hits, then it will
- * keep the event running.
- */
-void perf_event_task_sched_in(struct task_struct *task)
-{
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
-       struct perf_event_context *ctx = task->perf_event_ctxp;
 
-       if (likely(!ctx))
-               return;
+void perf_event_context_sched_in(struct perf_event_context *ctx)
+{
+       struct perf_cpu_context *cpuctx;
 
+       cpuctx = __get_cpu_context(ctx);
        if (cpuctx->task_ctx == ctx)
                return;
 
-       perf_disable();
-
+       perf_pmu_disable(ctx->pmu);
        /*
         * We want to keep the following priority order:
         * cpu pinned (that don't need to move), task pinned,
@@ -1444,7 +1435,37 @@ void perf_event_task_sched_in(struct task_struct *task)
 
        cpuctx->task_ctx = ctx;
 
-       perf_enable();
+       /*
+        * Since these rotations are per-cpu, we need to ensure the
+        * cpu-context we got scheduled on is actually rotating.
+        */
+       perf_pmu_rotate_start(ctx->pmu);
+       perf_pmu_enable(ctx->pmu);
+}
+
+/*
+ * Called from scheduler to add the events of the current task
+ * with interrupts disabled.
+ *
+ * We restore the event value and then enable it.
+ *
+ * This does not protect us against NMI, but enable()
+ * sets the enabled bit in the control field of event _before_
+ * accessing the event control register. If a NMI hits, then it will
+ * keep the event running.
+ */
+void __perf_event_task_sched_in(struct task_struct *task)
+{
+       struct perf_event_context *ctx;
+       int ctxn;
+
+       for_each_task_context_nr(ctxn) {
+               ctx = task->perf_event_ctxp[ctxn];
+               if (likely(!ctx))
+                       continue;
+
+               perf_event_context_sched_in(ctx);
+       }
 }
 
 #define MAX_INTERRUPTS (~0ULL)
@@ -1524,22 +1545,6 @@ do {                                     \
        return div64_u64(dividend, divisor);
 }
 
-static void perf_event_stop(struct perf_event *event)
-{
-       if (!event->pmu->stop)
-               return event->pmu->disable(event);
-
-       return event->pmu->stop(event);
-}
-
-static int perf_event_start(struct perf_event *event)
-{
-       if (!event->pmu->start)
-               return event->pmu->enable(event);
-
-       return event->pmu->start(event);
-}
-
 static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count)
 {
        struct hw_perf_event *hwc = &event->hw;
@@ -1559,15 +1564,13 @@ static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count)
        hwc->sample_period = sample_period;
 
        if (local64_read(&hwc->period_left) > 8*sample_period) {
-               perf_disable();
-               perf_event_stop(event);
+               event->pmu->stop(event, PERF_EF_UPDATE);
                local64_set(&hwc->period_left, 0);
-               perf_event_start(event);
-               perf_enable();
+               event->pmu->start(event, PERF_EF_RELOAD);
        }
 }
 
-static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
+static void perf_ctx_adjust_freq(struct perf_event_context *ctx, u64 period)
 {
        struct perf_event *event;
        struct hw_perf_event *hwc;
@@ -1592,23 +1595,19 @@ static void perf_ctx_adjust_freq(struct perf_event_context *ctx)
                 */
                if (interrupts == MAX_INTERRUPTS) {
                        perf_log_throttle(event, 1);
-                       perf_disable();
-                       event->pmu->unthrottle(event);
-                       perf_enable();
+                       event->pmu->start(event, 0);
                }
 
                if (!event->attr.freq || !event->attr.sample_freq)
                        continue;
 
-               perf_disable();
                event->pmu->read(event);
                now = local64_read(&event->count);
                delta = now - hwc->freq_count_stamp;
                hwc->freq_count_stamp = now;
 
                if (delta > 0)
-                       perf_adjust_period(event, TICK_NSEC, delta);
-               perf_enable();
+                       perf_adjust_period(event, period, delta);
        }
        raw_spin_unlock(&ctx->lock);
 }
@@ -1626,32 +1625,38 @@ static void rotate_ctx(struct perf_event_context *ctx)
        raw_spin_unlock(&ctx->lock);
 }
 
-void perf_event_task_tick(struct task_struct *curr)
+/*
+ * perf_pmu_rotate_start() and perf_rotate_context() are fully serialized
+ * because they're strictly cpu affine and rotate_start is called with IRQs
+ * disabled, while rotate_context is called from IRQ context.
+ */
+static void perf_rotate_context(struct perf_cpu_context *cpuctx)
 {
-       struct perf_cpu_context *cpuctx;
-       struct perf_event_context *ctx;
-       int rotate = 0;
-
-       if (!atomic_read(&nr_events))
-               return;
+       u64 interval = (u64)cpuctx->jiffies_interval * TICK_NSEC;
+       struct perf_event_context *ctx = NULL;
+       int rotate = 0, remove = 1;
 
-       cpuctx = &__get_cpu_var(perf_cpu_context);
-       if (cpuctx->ctx.nr_events &&
-           cpuctx->ctx.nr_events != cpuctx->ctx.nr_active)
-               rotate = 1;
+       if (cpuctx->ctx.nr_events) {
+               remove = 0;
+               if (cpuctx->ctx.nr_events != cpuctx->ctx.nr_active)
+                       rotate = 1;
+       }
 
-       ctx = curr->perf_event_ctxp;
-       if (ctx && ctx->nr_events && ctx->nr_events != ctx->nr_active)
-               rotate = 1;
+       ctx = cpuctx->task_ctx;
+       if (ctx && ctx->nr_events) {
+               remove = 0;
+               if (ctx->nr_events != ctx->nr_active)
+                       rotate = 1;
+       }
 
-       perf_ctx_adjust_freq(&cpuctx->ctx);
+       perf_pmu_disable(cpuctx->ctx.pmu);
+       perf_ctx_adjust_freq(&cpuctx->ctx, interval);
        if (ctx)
-               perf_ctx_adjust_freq(ctx);
+               perf_ctx_adjust_freq(ctx, interval);
 
        if (!rotate)
-               return;
+               goto done;
 
-       perf_disable();
        cpu_ctx_sched_out(cpuctx, EVENT_FLEXIBLE);
        if (ctx)
                task_ctx_sched_out(ctx, EVENT_FLEXIBLE);
@@ -1662,8 +1667,27 @@ void perf_event_task_tick(struct task_struct *curr)
 
        cpu_ctx_sched_in(cpuctx, EVENT_FLEXIBLE);
        if (ctx)
-               task_ctx_sched_in(curr, EVENT_FLEXIBLE);
-       perf_enable();
+               task_ctx_sched_in(ctx, EVENT_FLEXIBLE);
+
+done:
+       if (remove)
+               list_del_init(&cpuctx->rotation_list);
+
+       perf_pmu_enable(cpuctx->ctx.pmu);
+}
+
+void perf_event_task_tick(void)
+{
+       struct list_head *head = &__get_cpu_var(rotation_list);
+       struct perf_cpu_context *cpuctx, *tmp;
+
+       WARN_ON(!irqs_disabled());
+
+       list_for_each_entry_safe(cpuctx, tmp, head, rotation_list) {
+               if (cpuctx->jiffies_interval == 1 ||
+                               !(jiffies % cpuctx->jiffies_interval))
+                       perf_rotate_context(cpuctx);
+       }
 }
 
 static int event_enable_on_exec(struct perf_event *event,
@@ -1685,20 +1709,18 @@ static int event_enable_on_exec(struct perf_event *event,
  * Enable all of a task's events that have been marked enable-on-exec.
  * This expects task == current.
  */
-static void perf_event_enable_on_exec(struct task_struct *task)
+static void perf_event_enable_on_exec(struct perf_event_context *ctx)
 {
-       struct perf_event_context *ctx;
        struct perf_event *event;
        unsigned long flags;
        int enabled = 0;
        int ret;
 
        local_irq_save(flags);
-       ctx = task->perf_event_ctxp;
        if (!ctx || !ctx->nr_events)
                goto out;
 
-       __perf_event_task_sched_out(ctx);
+       task_ctx_sched_out(ctx, EVENT_ALL);
 
        raw_spin_lock(&ctx->lock);
 
@@ -1722,8 +1744,8 @@ static void perf_event_enable_on_exec(struct task_struct *task)
 
        raw_spin_unlock(&ctx->lock);
 
-       perf_event_task_sched_in(task);
- out:
+       perf_event_context_sched_in(ctx);
+out:
        local_irq_restore(flags);
 }
 
@@ -1732,9 +1754,9 @@ static void perf_event_enable_on_exec(struct task_struct *task)
  */
 static void __perf_event_read(void *info)
 {
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
        struct perf_event *event = info;
        struct perf_event_context *ctx = event->ctx;
+       struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
 
        /*
         * If this is a task context, we need to check whether it is
@@ -1773,7 +1795,13 @@ static u64 perf_event_read(struct perf_event *event)
                unsigned long flags;
 
                raw_spin_lock_irqsave(&ctx->lock, flags);
-               update_context_time(ctx);
+               /*
+                * may read while context is not active
+                * (e.g., thread is blocked), in that case
+                * we cannot update context time
+                */
+               if (ctx->is_active)
+                       update_context_time(ctx);
                update_event_times(event);
                raw_spin_unlock_irqrestore(&ctx->lock, flags);
        }
@@ -1782,106 +1810,349 @@ static u64 perf_event_read(struct perf_event *event)
 }
 
 /*
- * Initialize the perf_event context in a task_struct:
+ * Callchain support
  */
-static void
-__perf_event_init_context(struct perf_event_context *ctx,
-                           struct task_struct *task)
+
+struct callchain_cpus_entries {
+       struct rcu_head                 rcu_head;
+       struct perf_callchain_entry     *cpu_entries[0];
+};
+
+static DEFINE_PER_CPU(int, callchain_recursion[PERF_NR_CONTEXTS]);
+static atomic_t nr_callchain_events;
+static DEFINE_MUTEX(callchain_mutex);
+struct callchain_cpus_entries *callchain_cpus_entries;
+
+
+__weak void perf_callchain_kernel(struct perf_callchain_entry *entry,
+                                 struct pt_regs *regs)
 {
-       raw_spin_lock_init(&ctx->lock);
-       mutex_init(&ctx->mutex);
-       INIT_LIST_HEAD(&ctx->pinned_groups);
-       INIT_LIST_HEAD(&ctx->flexible_groups);
-       INIT_LIST_HEAD(&ctx->event_list);
-       atomic_set(&ctx->refcount, 1);
-       ctx->task = task;
 }
 
-static struct perf_event_context *find_get_context(pid_t pid, int cpu)
+__weak void perf_callchain_user(struct perf_callchain_entry *entry,
+                               struct pt_regs *regs)
 {
-       struct perf_event_context *ctx;
-       struct perf_cpu_context *cpuctx;
-       struct task_struct *task;
-       unsigned long flags;
-       int err;
+}
 
-       if (pid == -1 && cpu != -1) {
-               /* Must be root to operate on a CPU event: */
-               if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
-                       return ERR_PTR(-EACCES);
+static void release_callchain_buffers_rcu(struct rcu_head *head)
+{
+       struct callchain_cpus_entries *entries;
+       int cpu;
 
-               if (cpu < 0 || cpu >= nr_cpumask_bits)
-                       return ERR_PTR(-EINVAL);
+       entries = container_of(head, struct callchain_cpus_entries, rcu_head);
 
-               /*
-                * We could be clever and allow to attach a event to an
-                * offline CPU and activate it when the CPU comes up, but
-                * that's for later.
-                */
-               if (!cpu_online(cpu))
-                       return ERR_PTR(-ENODEV);
+       for_each_possible_cpu(cpu)
+               kfree(entries->cpu_entries[cpu]);
 
-               cpuctx = &per_cpu(perf_cpu_context, cpu);
-               ctx = &cpuctx->ctx;
-               get_ctx(ctx);
+       kfree(entries);
+}
 
-               return ctx;
-       }
+static void release_callchain_buffers(void)
+{
+       struct callchain_cpus_entries *entries;
 
-       rcu_read_lock();
-       if (!pid)
-               task = current;
-       else
-               task = find_task_by_vpid(pid);
-       if (task)
-               get_task_struct(task);
-       rcu_read_unlock();
+       entries = callchain_cpus_entries;
+       rcu_assign_pointer(callchain_cpus_entries, NULL);
+       call_rcu(&entries->rcu_head, release_callchain_buffers_rcu);
+}
 
-       if (!task)
-               return ERR_PTR(-ESRCH);
+static int alloc_callchain_buffers(void)
+{
+       int cpu;
+       int size;
+       struct callchain_cpus_entries *entries;
 
        /*
-        * Can't attach events to a dying task.
+        * We can't use the percpu allocation API for data that can be
+        * accessed from NMI. Use a temporary manual per cpu allocation
+        * until that gets sorted out.
         */
-       err = -ESRCH;
-       if (task->flags & PF_EXITING)
-               goto errout;
+       size = sizeof(*entries) + sizeof(struct perf_callchain_entry *) *
+               num_possible_cpus();
 
-       /* Reuse ptrace permission checks for now. */
-       err = -EACCES;
-       if (!ptrace_may_access(task, PTRACE_MODE_READ))
-               goto errout;
+       entries = kzalloc(size, GFP_KERNEL);
+       if (!entries)
+               return -ENOMEM;
 
- retry:
-       ctx = perf_lock_task_context(task, &flags);
-       if (ctx) {
-               unclone_ctx(ctx);
-               raw_spin_unlock_irqrestore(&ctx->lock, flags);
+       size = sizeof(struct perf_callchain_entry) * PERF_NR_CONTEXTS;
+
+       for_each_possible_cpu(cpu) {
+               entries->cpu_entries[cpu] = kmalloc_node(size, GFP_KERNEL,
+                                                        cpu_to_node(cpu));
+               if (!entries->cpu_entries[cpu])
+                       goto fail;
        }
 
-       if (!ctx) {
-               ctx = kzalloc(sizeof(struct perf_event_context), GFP_KERNEL);
-               err = -ENOMEM;
-               if (!ctx)
+       rcu_assign_pointer(callchain_cpus_entries, entries);
+
+       return 0;
+
+fail:
+       for_each_possible_cpu(cpu)
+               kfree(entries->cpu_entries[cpu]);
+       kfree(entries);
+
+       return -ENOMEM;
+}
+
+static int get_callchain_buffers(void)
+{
+       int err = 0;
+       int count;
+
+       mutex_lock(&callchain_mutex);
+
+       count = atomic_inc_return(&nr_callchain_events);
+       if (WARN_ON_ONCE(count < 1)) {
+               err = -EINVAL;
+               goto exit;
+       }
+
+       if (count > 1) {
+               /* If the allocation failed, give up */
+               if (!callchain_cpus_entries)
+                       err = -ENOMEM;
+               goto exit;
+       }
+
+       err = alloc_callchain_buffers();
+       if (err)
+               release_callchain_buffers();
+exit:
+       mutex_unlock(&callchain_mutex);
+
+       return err;
+}
+
+static void put_callchain_buffers(void)
+{
+       if (atomic_dec_and_mutex_lock(&nr_callchain_events, &callchain_mutex)) {
+               release_callchain_buffers();
+               mutex_unlock(&callchain_mutex);
+       }
+}
+
+static int get_recursion_context(int *recursion)
+{
+       int rctx;
+
+       if (in_nmi())
+               rctx = 3;
+       else if (in_irq())
+               rctx = 2;
+       else if (in_softirq())
+               rctx = 1;
+       else
+               rctx = 0;
+
+       if (recursion[rctx])
+               return -1;
+
+       recursion[rctx]++;
+       barrier();
+
+       return rctx;
+}
+
+static inline void put_recursion_context(int *recursion, int rctx)
+{
+       barrier();
+       recursion[rctx]--;
+}
+
+static struct perf_callchain_entry *get_callchain_entry(int *rctx)
+{
+       int cpu;
+       struct callchain_cpus_entries *entries;
+
+       *rctx = get_recursion_context(__get_cpu_var(callchain_recursion));
+       if (*rctx == -1)
+               return NULL;
+
+       entries = rcu_dereference(callchain_cpus_entries);
+       if (!entries)
+               return NULL;
+
+       cpu = smp_processor_id();
+
+       return &entries->cpu_entries[cpu][*rctx];
+}
+
+static void
+put_callchain_entry(int rctx)
+{
+       put_recursion_context(__get_cpu_var(callchain_recursion), rctx);
+}
+
+static struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
+{
+       int rctx;
+       struct perf_callchain_entry *entry;
+
+
+       entry = get_callchain_entry(&rctx);
+       if (rctx == -1)
+               return NULL;
+
+       if (!entry)
+               goto exit_put;
+
+       entry->nr = 0;
+
+       if (!user_mode(regs)) {
+               perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
+               perf_callchain_kernel(entry, regs);
+               if (current->mm)
+                       regs = task_pt_regs(current);
+               else
+                       regs = NULL;
+       }
+
+       if (regs) {
+               perf_callchain_store(entry, PERF_CONTEXT_USER);
+               perf_callchain_user(entry, regs);
+       }
+
+exit_put:
+       put_callchain_entry(rctx);
+
+       return entry;
+}
+
+/*
+ * Initialize the perf_event context in a task_struct:
+ */
+static void __perf_event_init_context(struct perf_event_context *ctx)
+{
+       raw_spin_lock_init(&ctx->lock);
+       mutex_init(&ctx->mutex);
+       INIT_LIST_HEAD(&ctx->pinned_groups);
+       INIT_LIST_HEAD(&ctx->flexible_groups);
+       INIT_LIST_HEAD(&ctx->event_list);
+       atomic_set(&ctx->refcount, 1);
+}
+
+static struct perf_event_context *
+alloc_perf_context(struct pmu *pmu, struct task_struct *task)
+{
+       struct perf_event_context *ctx;
+
+       ctx = kzalloc(sizeof(struct perf_event_context), GFP_KERNEL);
+       if (!ctx)
+               return NULL;
+
+       __perf_event_init_context(ctx);
+       if (task) {
+               ctx->task = task;
+               get_task_struct(task);
+       }
+       ctx->pmu = pmu;
+
+       return ctx;
+}
+
+static struct task_struct *
+find_lively_task_by_vpid(pid_t vpid)
+{
+       struct task_struct *task;
+       int err;
+
+       rcu_read_lock();
+       if (!vpid)
+               task = current;
+       else
+               task = find_task_by_vpid(vpid);
+       if (task)
+               get_task_struct(task);
+       rcu_read_unlock();
+
+       if (!task)
+               return ERR_PTR(-ESRCH);
+
+       /*
+        * Can't attach events to a dying task.
+        */
+       err = -ESRCH;
+       if (task->flags & PF_EXITING)
+               goto errout;
+
+       /* Reuse ptrace permission checks for now. */
+       err = -EACCES;
+       if (!ptrace_may_access(task, PTRACE_MODE_READ))
+               goto errout;
+
+       return task;
+errout:
+       put_task_struct(task);
+       return ERR_PTR(err);
+
+}
+
+static struct perf_event_context *
+find_get_context(struct pmu *pmu, struct task_struct *task, int cpu)
+{
+       struct perf_event_context *ctx;
+       struct perf_cpu_context *cpuctx;
+       unsigned long flags;
+       int ctxn, err;
+
+       if (!task && cpu != -1) {
+               /* Must be root to operate on a CPU event: */
+               if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN))
+                       return ERR_PTR(-EACCES);
+
+               if (cpu < 0 || cpu >= nr_cpumask_bits)
+                       return ERR_PTR(-EINVAL);
+
+               /*
+                * We could be clever and allow to attach a event to an
+                * offline CPU and activate it when the CPU comes up, but
+                * that's for later.
+                */
+               if (!cpu_online(cpu))
+                       return ERR_PTR(-ENODEV);
+
+               cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
+               ctx = &cpuctx->ctx;
+               get_ctx(ctx);
+
+               return ctx;
+       }
+
+       err = -EINVAL;
+       ctxn = pmu->task_ctx_nr;
+       if (ctxn < 0)
+               goto errout;
+
+retry:
+       ctx = perf_lock_task_context(task, ctxn, &flags);
+       if (ctx) {
+               unclone_ctx(ctx);
+               raw_spin_unlock_irqrestore(&ctx->lock, flags);
+       }
+
+       if (!ctx) {
+               ctx = alloc_perf_context(pmu, task);
+               err = -ENOMEM;
+               if (!ctx)
                        goto errout;
-               __perf_event_init_context(ctx, task);
+
                get_ctx(ctx);
-               if (cmpxchg(&task->perf_event_ctxp, NULL, ctx)) {
+
+               if (cmpxchg(&task->perf_event_ctxp[ctxn], NULL, ctx)) {
                        /*
                         * We raced with some other task; use
                         * the context they set.
                         */
+                       put_task_struct(task);
                        kfree(ctx);
                        goto retry;
                }
-               get_task_struct(task);
        }
 
-       put_task_struct(task);
        return ctx;
 
- errout:
-       put_task_struct(task);
+errout:
        return ERR_PTR(err);
 }
 
@@ -1898,21 +2169,23 @@ static void free_event_rcu(struct rcu_head *head)
        kfree(event);
 }
 
-static void perf_pending_sync(struct perf_event *event);
 static void perf_buffer_put(struct perf_buffer *buffer);
 
 static void free_event(struct perf_event *event)
 {
-       perf_pending_sync(event);
+       irq_work_sync(&event->pending);
 
        if (!event->parent) {
-               atomic_dec(&nr_events);
+               if (event->attach_state & PERF_ATTACH_TASK)
+                       jump_label_dec(&perf_task_events);
                if (event->attr.mmap || event->attr.mmap_data)
                        atomic_dec(&nr_mmap_events);
                if (event->attr.comm)
                        atomic_dec(&nr_comm_events);
                if (event->attr.task)
                        atomic_dec(&nr_task_events);
+               if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN)
+                       put_callchain_buffers();
        }
 
        if (event->buffer) {
@@ -1923,7 +2196,9 @@ static void free_event(struct perf_event *event)
        if (event->destroy)
                event->destroy(event);
 
-       put_ctx(event->ctx);
+       if (event->ctx)
+               put_ctx(event->ctx);
+
        call_rcu(&event->rcu_head, free_event_rcu);
 }
 
@@ -2342,6 +2617,9 @@ int perf_event_task_disable(void)
 
 static int perf_event_index(struct perf_event *event)
 {
+       if (event->hw.state & PERF_HES_STOPPED)
+               return 0;
+
        if (event->state != PERF_EVENT_STATE_ACTIVE)
                return 0;
 
@@ -2845,16 +3123,7 @@ void perf_event_wakeup(struct perf_event *event)
        }
 }
 
-/*
- * Pending wakeups
- *
- * Handle the case where we need to wakeup up from NMI (or rq->lock) context.
- *
- * The NMI bit means we cannot possibly take locks. Therefore, maintain a
- * single linked list and use cmpxchg() to add entries lockless.
- */
-
-static void perf_pending_event(struct perf_pending_entry *entry)
+static void perf_pending_event(struct irq_work *entry)
 {
        struct perf_event *event = container_of(entry,
                        struct perf_event, pending);
@@ -2870,99 +3139,6 @@ static void perf_pending_event(struct perf_pending_entry *entry)
        }
 }
 
-#define PENDING_TAIL ((struct perf_pending_entry *)-1UL)
-
-static DEFINE_PER_CPU(struct perf_pending_entry *, perf_pending_head) = {
-       PENDING_TAIL,
-};
-
-static void perf_pending_queue(struct perf_pending_entry *entry,
-                              void (*func)(struct perf_pending_entry *))
-{
-       struct perf_pending_entry **head;
-
-       if (cmpxchg(&entry->next, NULL, PENDING_TAIL) != NULL)
-               return;
-
-       entry->func = func;
-
-       head = &get_cpu_var(perf_pending_head);
-
-       do {
-               entry->next = *head;
-       } while (cmpxchg(head, entry->next, entry) != entry->next);
-
-       set_perf_event_pending();
-
-       put_cpu_var(perf_pending_head);
-}
-
-static int __perf_pending_run(void)
-{
-       struct perf_pending_entry *list;
-       int nr = 0;
-
-       list = xchg(&__get_cpu_var(perf_pending_head), PENDING_TAIL);
-       while (list != PENDING_TAIL) {
-               void (*func)(struct perf_pending_entry *);
-               struct perf_pending_entry *entry = list;
-
-               list = list->next;
-
-               func = entry->func;
-               entry->next = NULL;
-               /*
-                * Ensure we observe the unqueue before we issue the wakeup,
-                * so that we won't be waiting forever.
-                * -- see perf_not_pending().
-                */
-               smp_wmb();
-
-               func(entry);
-               nr++;
-       }
-
-       return nr;
-}
-
-static inline int perf_not_pending(struct perf_event *event)
-{
-       /*
-        * If we flush on whatever cpu we run, there is a chance we don't
-        * need to wait.
-        */
-       get_cpu();
-       __perf_pending_run();
-       put_cpu();
-
-       /*
-        * Ensure we see the proper queue state before going to sleep
-        * so that we do not miss the wakeup. -- see perf_pending_handle()
-        */
-       smp_rmb();
-       return event->pending.next == NULL;
-}
-
-static void perf_pending_sync(struct perf_event *event)
-{
-       wait_event(event->waitq, perf_not_pending(event));
-}
-
-void perf_event_do_pending(void)
-{
-       __perf_pending_run();
-}
-
-/*
- * Callchain support -- arch specific
- */
-
-__weak struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
-{
-       return NULL;
-}
-
-
 /*
  * We assume there is only KVM supporting the callbacks.
  * Later on, we might change it to a list if there is
@@ -3012,8 +3188,7 @@ static void perf_output_wakeup(struct perf_output_handle *handle)
 
        if (handle->nmi) {
                handle->event->pending_wakeup = 1;
-               perf_pending_queue(&handle->event->pending,
-                                  perf_pending_event);
+               irq_work_queue(&handle->event->pending);
        } else
                perf_event_wakeup(handle->event);
 }
@@ -3069,7 +3244,7 @@ again:
        if (handle->wakeup != local_read(&buffer->wakeup))
                perf_output_wakeup(handle);
 
- out:
+out:
        preempt_enable();
 }
 
@@ -3457,14 +3632,20 @@ static void perf_event_output(struct perf_event *event, int nmi,
        struct perf_output_handle handle;
        struct perf_event_header header;
 
+       /* protect the callchain buffers */
+       rcu_read_lock();
+
        perf_prepare_sample(&header, data, event, regs);
 
        if (perf_output_begin(&handle, event, header.size, nmi, 1))
-               return;
+               goto exit;
 
        perf_output_sample(&handle, &header, data, event);
 
        perf_output_end(&handle);
+
+exit:
+       rcu_read_unlock();
 }
 
 /*
@@ -3578,16 +3759,27 @@ static void perf_event_task_ctx(struct perf_event_context *ctx,
 static void perf_event_task_event(struct perf_task_event *task_event)
 {
        struct perf_cpu_context *cpuctx;
-       struct perf_event_context *ctx = task_event->task_ctx;
+       struct perf_event_context *ctx;
+       struct pmu *pmu;
+       int ctxn;
 
        rcu_read_lock();
-       cpuctx = &get_cpu_var(perf_cpu_context);
-       perf_event_task_ctx(&cpuctx->ctx, task_event);
-       if (!ctx)
-               ctx = rcu_dereference(current->perf_event_ctxp);
-       if (ctx)
-               perf_event_task_ctx(ctx, task_event);
-       put_cpu_var(perf_cpu_context);
+       list_for_each_entry_rcu(pmu, &pmus, entry) {
+               cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
+               perf_event_task_ctx(&cpuctx->ctx, task_event);
+
+               ctx = task_event->task_ctx;
+               if (!ctx) {
+                       ctxn = pmu->task_ctx_nr;
+                       if (ctxn < 0)
+                               goto next;
+                       ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
+               }
+               if (ctx)
+                       perf_event_task_ctx(ctx, task_event);
+next:
+               put_cpu_ptr(pmu->pmu_cpu_context);
+       }
        rcu_read_unlock();
 }
 
@@ -3692,8 +3884,10 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event)
 {
        struct perf_cpu_context *cpuctx;
        struct perf_event_context *ctx;
-       unsigned int size;
        char comm[TASK_COMM_LEN];
+       unsigned int size;
+       struct pmu *pmu;
+       int ctxn;
 
        memset(comm, 0, sizeof(comm));
        strlcpy(comm, comm_event->task->comm, sizeof(comm));
@@ -3705,21 +3899,36 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event)
        comm_event->event_id.header.size = sizeof(comm_event->event_id) + size;
 
        rcu_read_lock();
-       cpuctx = &get_cpu_var(perf_cpu_context);
-       perf_event_comm_ctx(&cpuctx->ctx, comm_event);
-       ctx = rcu_dereference(current->perf_event_ctxp);
-       if (ctx)
-               perf_event_comm_ctx(ctx, comm_event);
-       put_cpu_var(perf_cpu_context);
+       list_for_each_entry_rcu(pmu, &pmus, entry) {
+               cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
+               perf_event_comm_ctx(&cpuctx->ctx, comm_event);
+
+               ctxn = pmu->task_ctx_nr;
+               if (ctxn < 0)
+                       goto next;
+
+               ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
+               if (ctx)
+                       perf_event_comm_ctx(ctx, comm_event);
+next:
+               put_cpu_ptr(pmu->pmu_cpu_context);
+       }
        rcu_read_unlock();
 }
 
 void perf_event_comm(struct task_struct *task)
 {
        struct perf_comm_event comm_event;
+       struct perf_event_context *ctx;
+       int ctxn;
 
-       if (task->perf_event_ctxp)
-               perf_event_enable_on_exec(task);
+       for_each_task_context_nr(ctxn) {
+               ctx = task->perf_event_ctxp[ctxn];
+               if (!ctx)
+                       continue;
+
+               perf_event_enable_on_exec(ctx);
+       }
 
        if (!atomic_read(&nr_comm_events))
                return;
@@ -3821,6 +4030,8 @@ static void perf_event_mmap_event(struct perf_mmap_event *mmap_event)
        char tmp[16];
        char *buf = NULL;
        const char *name;
+       struct pmu *pmu;
+       int ctxn;
 
        memset(tmp, 0, sizeof(tmp));
 
@@ -3873,12 +4084,23 @@ got_name:
        mmap_event->event_id.header.size = sizeof(mmap_event->event_id) + size;
 
        rcu_read_lock();
-       cpuctx = &get_cpu_var(perf_cpu_context);
-       perf_event_mmap_ctx(&cpuctx->ctx, mmap_event, vma->vm_flags & VM_EXEC);
-       ctx = rcu_dereference(current->perf_event_ctxp);
-       if (ctx)
-               perf_event_mmap_ctx(ctx, mmap_event, vma->vm_flags & VM_EXEC);
-       put_cpu_var(perf_cpu_context);
+       list_for_each_entry_rcu(pmu, &pmus, entry) {
+               cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
+               perf_event_mmap_ctx(&cpuctx->ctx, mmap_event,
+                                       vma->vm_flags & VM_EXEC);
+
+               ctxn = pmu->task_ctx_nr;
+               if (ctxn < 0)
+                       goto next;
+
+               ctx = rcu_dereference(current->perf_event_ctxp[ctxn]);
+               if (ctx) {
+                       perf_event_mmap_ctx(ctx, mmap_event,
+                                       vma->vm_flags & VM_EXEC);
+               }
+next:
+               put_cpu_ptr(pmu->pmu_cpu_context);
+       }
        rcu_read_unlock();
 
        kfree(buf);
@@ -3960,8 +4182,6 @@ static int __perf_event_overflow(struct perf_event *event, int nmi,
        struct hw_perf_event *hwc = &event->hw;
        int ret = 0;
 
-       throttle = (throttle && event->pmu->unthrottle != NULL);
-
        if (!throttle) {
                hwc->interrupts++;
        } else {
@@ -4004,8 +4224,7 @@ static int __perf_event_overflow(struct perf_event *event, int nmi,
                event->pending_kill = POLL_HUP;
                if (nmi) {
                        event->pending_disable = 1;
-                       perf_pending_queue(&event->pending,
-                                          perf_pending_event);
+                       irq_work_queue(&event->pending);
                } else
                        perf_event_disable(event);
        }
@@ -4029,6 +4248,17 @@ int perf_event_overflow(struct perf_event *event, int nmi,
  * Generic software event infrastructure
  */
 
+struct swevent_htable {
+       struct swevent_hlist            *swevent_hlist;
+       struct mutex                    hlist_mutex;
+       int                             hlist_refcount;
+
+       /* Recursion avoidance in each contexts */
+       int                             recursion[PERF_NR_CONTEXTS];
+};
+
+static DEFINE_PER_CPU(struct swevent_htable, swevent_htable);
+
 /*
  * We directly increment event->count and keep a second value in
  * event->hw.period_left to count intervals. This period event
@@ -4086,7 +4316,7 @@ static void perf_swevent_overflow(struct perf_event *event, u64 overflow,
        }
 }
 
-static void perf_swevent_add(struct perf_event *event, u64 nr,
+static void perf_swevent_event(struct perf_event *event, u64 nr,
                               int nmi, struct perf_sample_data *data,
                               struct pt_regs *regs)
 {
@@ -4112,6 +4342,9 @@ static void perf_swevent_add(struct perf_event *event, u64 nr,
 static int perf_exclude_event(struct perf_event *event,
                              struct pt_regs *regs)
 {
+       if (event->hw.state & PERF_HES_STOPPED)
+               return 0;
+
        if (regs) {
                if (event->attr.exclude_user && user_mode(regs))
                        return 1;
@@ -4158,11 +4391,11 @@ __find_swevent_head(struct swevent_hlist *hlist, u64 type, u32 event_id)
 
 /* For the read side: events when they trigger */
 static inline struct hlist_head *
-find_swevent_head_rcu(struct perf_cpu_context *ctx, u64 type, u32 event_id)
+find_swevent_head_rcu(struct swevent_htable *swhash, u64 type, u32 event_id)
 {
        struct swevent_hlist *hlist;
 
-       hlist = rcu_dereference(ctx->swevent_hlist);
+       hlist = rcu_dereference(swhash->swevent_hlist);
        if (!hlist)
                return NULL;
 
@@ -4171,7 +4404,7 @@ find_swevent_head_rcu(struct perf_cpu_context *ctx, u64 type, u32 event_id)
 
 /* For the event head insertion and removal in the hlist */
 static inline struct hlist_head *
-find_swevent_head(struct perf_cpu_context *ctx, struct perf_event *event)
+find_swevent_head(struct swevent_htable *swhash, struct perf_event *event)
 {
        struct swevent_hlist *hlist;
        u32 event_id = event->attr.config;
@@ -4182,7 +4415,7 @@ find_swevent_head(struct perf_cpu_context *ctx, struct perf_event *event)
         * and release. Which makes the protected version suitable here.
         * The context lock guarantees that.
         */
-       hlist = rcu_dereference_protected(ctx->swevent_hlist,
+       hlist = rcu_dereference_protected(swhash->swevent_hlist,
                                          lockdep_is_held(&event->ctx->lock));
        if (!hlist)
                return NULL;
@@ -4195,23 +4428,19 @@ static void do_perf_sw_event(enum perf_type_id type, u32 event_id,
                                    struct perf_sample_data *data,
                                    struct pt_regs *regs)
 {
-       struct perf_cpu_context *cpuctx;
+       struct swevent_htable *swhash = &__get_cpu_var(swevent_htable);
        struct perf_event *event;
        struct hlist_node *node;
        struct hlist_head *head;
 
-       cpuctx = &__get_cpu_var(perf_cpu_context);
-
        rcu_read_lock();
-
-       head = find_swevent_head_rcu(cpuctx, type, event_id);
-
+       head = find_swevent_head_rcu(swhash, type, event_id);
        if (!head)
                goto end;
 
        hlist_for_each_entry_rcu(event, node, head, hlist_entry) {
                if (perf_swevent_match(event, type, event_id, data, regs))
-                       perf_swevent_add(event, nr, nmi, data, regs);
+                       perf_swevent_event(event, nr, nmi, data, regs);
        }
 end:
        rcu_read_unlock();
@@ -4219,33 +4448,17 @@ end:
 
 int perf_swevent_get_recursion_context(void)
 {
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
-       int rctx;
-
-       if (in_nmi())
-               rctx = 3;
-       else if (in_irq())
-               rctx = 2;
-       else if (in_softirq())
-               rctx = 1;
-       else
-               rctx = 0;
-
-       if (cpuctx->recursion[rctx])
-               return -1;
+       struct swevent_htable *swhash = &__get_cpu_var(swevent_htable);
 
-       cpuctx->recursion[rctx]++;
-       barrier();
-
-       return rctx;
+       return get_recursion_context(swhash->recursion);
 }
 EXPORT_SYMBOL_GPL(perf_swevent_get_recursion_context);
 
 void inline perf_swevent_put_recursion_context(int rctx)
 {
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
-       barrier();
-       cpuctx->recursion[rctx]--;
+       struct swevent_htable *swhash = &__get_cpu_var(swevent_htable);
+
+       put_recursion_context(swhash->recursion, rctx);
 }
 
 void __perf_sw_event(u32 event_id, u64 nr, int nmi,
@@ -4271,20 +4484,20 @@ static void perf_swevent_read(struct perf_event *event)
 {
 }
 
-static int perf_swevent_enable(struct perf_event *event)
+static int perf_swevent_add(struct perf_event *event, int flags)
 {
+       struct swevent_htable *swhash = &__get_cpu_var(swevent_htable);
        struct hw_perf_event *hwc = &event->hw;
-       struct perf_cpu_context *cpuctx;
        struct hlist_head *head;
 
-       cpuctx = &__get_cpu_var(perf_cpu_context);
-
        if (hwc->sample_period) {
                hwc->last_period = hwc->sample_period;
                perf_swevent_set_period(event);
        }
 
-       head = find_swevent_head(cpuctx, event);
+       hwc->state = !(flags & PERF_EF_START);
+
+       head = find_swevent_head(swhash, event);
        if (WARN_ON_ONCE(!head))
                return -EINVAL;
 
@@ -4293,202 +4506,27 @@ static int perf_swevent_enable(struct perf_event *event)
        return 0;
 }
 
-static void perf_swevent_disable(struct perf_event *event)
+static void perf_swevent_del(struct perf_event *event, int flags)
 {
        hlist_del_rcu(&event->hlist_entry);
 }
 
-static void perf_swevent_void(struct perf_event *event)
-{
-}
-
-static int perf_swevent_int(struct perf_event *event)
-{
-       return 0;
-}
-
-static const struct pmu perf_ops_generic = {
-       .enable         = perf_swevent_enable,
-       .disable        = perf_swevent_disable,
-       .start          = perf_swevent_int,
-       .stop           = perf_swevent_void,
-       .read           = perf_swevent_read,
-       .unthrottle     = perf_swevent_void, /* hwc->interrupts already reset */
-};
-
-/*
- * hrtimer based swevent callback
- */
-
-static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
-{
-       enum hrtimer_restart ret = HRTIMER_RESTART;
-       struct perf_sample_data data;
-       struct pt_regs *regs;
-       struct perf_event *event;
-       u64 period;
-
-       event = container_of(hrtimer, struct perf_event, hw.hrtimer);
-       event->pmu->read(event);
-
-       perf_sample_data_init(&data, 0);
-       data.period = event->hw.last_period;
-       regs = get_irq_regs();
-
-       if (regs && !perf_exclude_event(event, regs)) {
-               if (!(event->attr.exclude_idle && current->pid == 0))
-                       if (perf_event_overflow(event, 0, &data, regs))
-                               ret = HRTIMER_NORESTART;
-       }
-
-       period = max_t(u64, 10000, event->hw.sample_period);
-       hrtimer_forward_now(hrtimer, ns_to_ktime(period));
-
-       return ret;
-}
-
-static void perf_swevent_start_hrtimer(struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       hwc->hrtimer.function = perf_swevent_hrtimer;
-       if (hwc->sample_period) {
-               u64 period;
-
-               if (hwc->remaining) {
-                       if (hwc->remaining < 0)
-                               period = 10000;
-                       else
-                               period = hwc->remaining;
-                       hwc->remaining = 0;
-               } else {
-                       period = max_t(u64, 10000, hwc->sample_period);
-               }
-               __hrtimer_start_range_ns(&hwc->hrtimer,
-                               ns_to_ktime(period), 0,
-                               HRTIMER_MODE_REL, 0);
-       }
-}
-
-static void perf_swevent_cancel_hrtimer(struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-
-       if (hwc->sample_period) {
-               ktime_t remaining = hrtimer_get_remaining(&hwc->hrtimer);
-               hwc->remaining = ktime_to_ns(remaining);
-
-               hrtimer_cancel(&hwc->hrtimer);
-       }
-}
-
-/*
- * Software event: cpu wall time clock
- */
-
-static void cpu_clock_perf_event_update(struct perf_event *event)
-{
-       int cpu = raw_smp_processor_id();
-       s64 prev;
-       u64 now;
-
-       now = cpu_clock(cpu);
-       prev = local64_xchg(&event->hw.prev_count, now);
-       local64_add(now - prev, &event->count);
-}
-
-static int cpu_clock_perf_event_enable(struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       int cpu = raw_smp_processor_id();
-
-       local64_set(&hwc->prev_count, cpu_clock(cpu));
-       perf_swevent_start_hrtimer(event);
-
-       return 0;
-}
-
-static void cpu_clock_perf_event_disable(struct perf_event *event)
-{
-       perf_swevent_cancel_hrtimer(event);
-       cpu_clock_perf_event_update(event);
-}
-
-static void cpu_clock_perf_event_read(struct perf_event *event)
-{
-       cpu_clock_perf_event_update(event);
-}
-
-static const struct pmu perf_ops_cpu_clock = {
-       .enable         = cpu_clock_perf_event_enable,
-       .disable        = cpu_clock_perf_event_disable,
-       .read           = cpu_clock_perf_event_read,
-};
-
-/*
- * Software event: task time clock
- */
-
-static void task_clock_perf_event_update(struct perf_event *event, u64 now)
-{
-       u64 prev;
-       s64 delta;
-
-       prev = local64_xchg(&event->hw.prev_count, now);
-       delta = now - prev;
-       local64_add(delta, &event->count);
-}
-
-static int task_clock_perf_event_enable(struct perf_event *event)
-{
-       struct hw_perf_event *hwc = &event->hw;
-       u64 now;
-
-       now = event->ctx->time;
-
-       local64_set(&hwc->prev_count, now);
-
-       perf_swevent_start_hrtimer(event);
-
-       return 0;
-}
-
-static void task_clock_perf_event_disable(struct perf_event *event)
+static void perf_swevent_start(struct perf_event *event, int flags)
 {
-       perf_swevent_cancel_hrtimer(event);
-       task_clock_perf_event_update(event, event->ctx->time);
-
+       event->hw.state = 0;
 }
 
-static void task_clock_perf_event_read(struct perf_event *event)
+static void perf_swevent_stop(struct perf_event *event, int flags)
 {
-       u64 time;
-
-       if (!in_nmi()) {
-               update_context_time(event->ctx);
-               time = event->ctx->time;
-       } else {
-               u64 now = perf_clock();
-               u64 delta = now - event->ctx->timestamp;
-               time = event->ctx->time + delta;
-       }
-
-       task_clock_perf_event_update(event, time);
+       event->hw.state = PERF_HES_STOPPED;
 }
 
-static const struct pmu perf_ops_task_clock = {
-       .enable         = task_clock_perf_event_enable,
-       .disable        = task_clock_perf_event_disable,
-       .read           = task_clock_perf_event_read,
-};
-
 /* Deref the hlist from the update side */
 static inline struct swevent_hlist *
-swevent_hlist_deref(struct perf_cpu_context *cpuctx)
+swevent_hlist_deref(struct swevent_htable *swhash)
 {
-       return rcu_dereference_protected(cpuctx->swevent_hlist,
-                                        lockdep_is_held(&cpuctx->hlist_mutex));
+       return rcu_dereference_protected(swhash->swevent_hlist,
+                                        lockdep_is_held(&swhash->hlist_mutex));
 }
 
 static void swevent_hlist_release_rcu(struct rcu_head *rcu_head)
@@ -4499,27 +4537,27 @@ static void swevent_hlist_release_rcu(struct rcu_head *rcu_head)
        kfree(hlist);
 }
 
-static void swevent_hlist_release(struct perf_cpu_context *cpuctx)
+static void swevent_hlist_release(struct swevent_htable *swhash)
 {
-       struct swevent_hlist *hlist = swevent_hlist_deref(cpuctx);
+       struct swevent_hlist *hlist = swevent_hlist_deref(swhash);
 
        if (!hlist)
                return;
 
-       rcu_assign_pointer(cpuctx->swevent_hlist, NULL);
+       rcu_assign_pointer(swhash->swevent_hlist, NULL);
        call_rcu(&hlist->rcu_head, swevent_hlist_release_rcu);
 }
 
 static void swevent_hlist_put_cpu(struct perf_event *event, int cpu)
 {
-       struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu);
+       struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
 
-       mutex_lock(&cpuctx->hlist_mutex);
+       mutex_lock(&swhash->hlist_mutex);
 
-       if (!--cpuctx->hlist_refcount)
-               swevent_hlist_release(cpuctx);
+       if (!--swhash->hlist_refcount)
+               swevent_hlist_release(swhash);
 
-       mutex_unlock(&cpuctx->hlist_mutex);
+       mutex_unlock(&swhash->hlist_mutex);
 }
 
 static void swevent_hlist_put(struct perf_event *event)
@@ -4537,12 +4575,12 @@ static void swevent_hlist_put(struct perf_event *event)
 
 static int swevent_hlist_get_cpu(struct perf_event *event, int cpu)
 {
-       struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu);
+       struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
        int err = 0;
 
-       mutex_lock(&cpuctx->hlist_mutex);
+       mutex_lock(&swhash->hlist_mutex);
 
-       if (!swevent_hlist_deref(cpuctx) && cpu_online(cpu)) {
+       if (!swevent_hlist_deref(swhash) && cpu_online(cpu)) {
                struct swevent_hlist *hlist;
 
                hlist = kzalloc(sizeof(*hlist), GFP_KERNEL);
@@ -4550,11 +4588,11 @@ static int swevent_hlist_get_cpu(struct perf_event *event, int cpu)
                        err = -ENOMEM;
                        goto exit;
                }
-               rcu_assign_pointer(cpuctx->swevent_hlist, hlist);
+               rcu_assign_pointer(swhash->swevent_hlist, hlist);
        }
-       cpuctx->hlist_refcount++;
- exit:
-       mutex_unlock(&cpuctx->hlist_mutex);
+       swhash->hlist_refcount++;
+exit:
+       mutex_unlock(&swhash->hlist_mutex);
 
        return err;
 }
@@ -4578,7 +4616,7 @@ static int swevent_hlist_get(struct perf_event *event)
        put_online_cpus();
 
        return 0;
- fail:
+fail:
        for_each_possible_cpu(cpu) {
                if (cpu == failed_cpu)
                        break;
@@ -4589,17 +4627,64 @@ static int swevent_hlist_get(struct perf_event *event)
        return err;
 }
 
-#ifdef CONFIG_EVENT_TRACING
+atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
+
+static void sw_perf_event_destroy(struct perf_event *event)
+{
+       u64 event_id = event->attr.config;
+
+       WARN_ON(event->parent);
+
+       jump_label_dec(&perf_swevent_enabled[event_id]);
+       swevent_hlist_put(event);
+}
+
+static int perf_swevent_init(struct perf_event *event)
+{
+       int event_id = event->attr.config;
+
+       if (event->attr.type != PERF_TYPE_SOFTWARE)
+               return -ENOENT;
+
+       switch (event_id) {
+       case PERF_COUNT_SW_CPU_CLOCK:
+       case PERF_COUNT_SW_TASK_CLOCK:
+               return -ENOENT;
 
-static const struct pmu perf_ops_tracepoint = {
-       .enable         = perf_trace_enable,
-       .disable        = perf_trace_disable,
-       .start          = perf_swevent_int,
-       .stop           = perf_swevent_void,
+       default:
+               break;
+       }
+
+       if (event_id > PERF_COUNT_SW_MAX)
+               return -ENOENT;
+
+       if (!event->parent) {
+               int err;
+
+               err = swevent_hlist_get(event);
+               if (err)
+                       return err;
+
+               jump_label_inc(&perf_swevent_enabled[event_id]);
+               event->destroy = sw_perf_event_destroy;
+       }
+
+       return 0;
+}
+
+static struct pmu perf_swevent = {
+       .task_ctx_nr    = perf_sw_context,
+
+       .event_init     = perf_swevent_init,
+       .add            = perf_swevent_add,
+       .del            = perf_swevent_del,
+       .start          = perf_swevent_start,
+       .stop           = perf_swevent_stop,
        .read           = perf_swevent_read,
-       .unthrottle     = perf_swevent_void,
 };
 
+#ifdef CONFIG_EVENT_TRACING
+
 static int perf_tp_filter_match(struct perf_event *event,
                                struct perf_sample_data *data)
 {
@@ -4643,7 +4728,7 @@ void perf_tp_event(u64 addr, u64 count, void *record, int entry_size,
 
        hlist_for_each_entry_rcu(event, node, head, hlist_entry) {
                if (perf_tp_event_match(event, &data, regs))
-                       perf_swevent_add(event, count, 1, &data, regs);
+                       perf_swevent_event(event, count, 1, &data, regs);
        }
 
        perf_swevent_put_recursion_context(rctx);
@@ -4655,10 +4740,13 @@ static void tp_perf_event_destroy(struct perf_event *event)
        perf_trace_destroy(event);
 }
 
-static const struct pmu *tp_perf_event_init(struct perf_event *event)
+static int perf_tp_event_init(struct perf_event *event)
 {
        int err;
 
+       if (event->attr.type != PERF_TYPE_TRACEPOINT)
+               return -ENOENT;
+
        /*
         * Raw tracepoint data is a severe data leak, only allow root to
         * have these.
@@ -4666,15 +4754,31 @@ static const struct pmu *tp_perf_event_init(struct perf_event *event)
        if ((event->attr.sample_type & PERF_SAMPLE_RAW) &&
                        perf_paranoid_tracepoint_raw() &&
                        !capable(CAP_SYS_ADMIN))
-               return ERR_PTR(-EPERM);
+               return -EPERM;
 
        err = perf_trace_init(event);
        if (err)
-               return NULL;
+               return err;
 
        event->destroy = tp_perf_event_destroy;
 
-       return &perf_ops_tracepoint;
+       return 0;
+}
+
+static struct pmu perf_tracepoint = {
+       .task_ctx_nr    = perf_sw_context,
+
+       .event_init     = perf_tp_event_init,
+       .add            = perf_trace_add,
+       .del            = perf_trace_del,
+       .start          = perf_swevent_start,
+       .stop           = perf_swevent_stop,
+       .read           = perf_swevent_read,
+};
+
+static inline void perf_tp_register(void)
+{
+       perf_pmu_register(&perf_tracepoint);
 }
 
 static int perf_event_set_filter(struct perf_event *event, void __user *arg)
@@ -4702,9 +4806,8 @@ static void perf_event_free_filter(struct perf_event *event)
 
 #else
 
-static const struct pmu *tp_perf_event_init(struct perf_event *event)
+static inline void perf_tp_register(void)
 {
-       return NULL;
 }
 
 static int perf_event_set_filter(struct perf_event *event, void __user *arg)
@@ -4719,24 +4822,6 @@ static void perf_event_free_filter(struct perf_event *event)
 #endif /* CONFIG_EVENT_TRACING */
 
 #ifdef CONFIG_HAVE_HW_BREAKPOINT
-static void bp_perf_event_destroy(struct perf_event *event)
-{
-       release_bp_slot(event);
-}
-
-static const struct pmu *bp_perf_event_init(struct perf_event *bp)
-{
-       int err;
-
-       err = register_perf_hw_breakpoint(bp);
-       if (err)
-               return ERR_PTR(err);
-
-       bp->destroy = bp_perf_event_destroy;
-
-       return &perf_ops_bp;
-}
-
 void perf_bp_event(struct perf_event *bp, void *data)
 {
        struct perf_sample_data sample;
@@ -4744,80 +4829,382 @@ void perf_bp_event(struct perf_event *bp, void *data)
 
        perf_sample_data_init(&sample, bp->attr.bp_addr);
 
-       if (!perf_exclude_event(bp, regs))
-               perf_swevent_add(bp, 1, 1, &sample, regs);
-}
-#else
-static const struct pmu *bp_perf_event_init(struct perf_event *bp)
-{
-       return NULL;
-}
-
-void perf_bp_event(struct perf_event *bp, void *regs)
-{
+       if (!bp->hw.state && !perf_exclude_event(bp, regs))
+               perf_swevent_event(bp, 1, 1, &sample, regs);
 }
 #endif
 
-atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
+/*
+ * hrtimer based swevent callback
+ */
 
-static void sw_perf_event_destroy(struct perf_event *event)
+static enum hrtimer_restart perf_swevent_hrtimer(struct hrtimer *hrtimer)
 {
-       u64 event_id = event->attr.config;
+       enum hrtimer_restart ret = HRTIMER_RESTART;
+       struct perf_sample_data data;
+       struct pt_regs *regs;
+       struct perf_event *event;
+       u64 period;
 
-       WARN_ON(event->parent);
+       event = container_of(hrtimer, struct perf_event, hw.hrtimer);
+       event->pmu->read(event);
 
-       atomic_dec(&perf_swevent_enabled[event_id]);
-       swevent_hlist_put(event);
+       perf_sample_data_init(&data, 0);
+       data.period = event->hw.last_period;
+       regs = get_irq_regs();
+
+       if (regs && !perf_exclude_event(event, regs)) {
+               if (!(event->attr.exclude_idle && current->pid == 0))
+                       if (perf_event_overflow(event, 0, &data, regs))
+                               ret = HRTIMER_NORESTART;
+       }
+
+       period = max_t(u64, 10000, event->hw.sample_period);
+       hrtimer_forward_now(hrtimer, ns_to_ktime(period));
+
+       return ret;
 }
 
-static const struct pmu *sw_perf_event_init(struct perf_event *event)
+static void perf_swevent_start_hrtimer(struct perf_event *event)
 {
-       const struct pmu *pmu = NULL;
-       u64 event_id = event->attr.config;
+       struct hw_perf_event *hwc = &event->hw;
+
+       hrtimer_init(&hwc->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       hwc->hrtimer.function = perf_swevent_hrtimer;
+       if (hwc->sample_period) {
+               s64 period = local64_read(&hwc->period_left);
+
+               if (period) {
+                       if (period < 0)
+                               period = 10000;
+
+                       local64_set(&hwc->period_left, 0);
+               } else {
+                       period = max_t(u64, 10000, hwc->sample_period);
+               }
+               __hrtimer_start_range_ns(&hwc->hrtimer,
+                               ns_to_ktime(period), 0,
+                               HRTIMER_MODE_REL_PINNED, 0);
+       }
+}
+
+static void perf_swevent_cancel_hrtimer(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->sample_period) {
+               ktime_t remaining = hrtimer_get_remaining(&hwc->hrtimer);
+               local64_set(&hwc->period_left, ktime_to_ns(remaining));
+
+               hrtimer_cancel(&hwc->hrtimer);
+       }
+}
+
+/*
+ * Software event: cpu wall time clock
+ */
+
+static void cpu_clock_event_update(struct perf_event *event)
+{
+       s64 prev;
+       u64 now;
+
+       now = local_clock();
+       prev = local64_xchg(&event->hw.prev_count, now);
+       local64_add(now - prev, &event->count);
+}
+
+static void cpu_clock_event_start(struct perf_event *event, int flags)
+{
+       local64_set(&event->hw.prev_count, local_clock());
+       perf_swevent_start_hrtimer(event);
+}
+
+static void cpu_clock_event_stop(struct perf_event *event, int flags)
+{
+       perf_swevent_cancel_hrtimer(event);
+       cpu_clock_event_update(event);
+}
+
+static int cpu_clock_event_add(struct perf_event *event, int flags)
+{
+       if (flags & PERF_EF_START)
+               cpu_clock_event_start(event, flags);
+
+       return 0;
+}
+
+static void cpu_clock_event_del(struct perf_event *event, int flags)
+{
+       cpu_clock_event_stop(event, flags);
+}
+
+static void cpu_clock_event_read(struct perf_event *event)
+{
+       cpu_clock_event_update(event);
+}
+
+static int cpu_clock_event_init(struct perf_event *event)
+{
+       if (event->attr.type != PERF_TYPE_SOFTWARE)
+               return -ENOENT;
+
+       if (event->attr.config != PERF_COUNT_SW_CPU_CLOCK)
+               return -ENOENT;
+
+       return 0;
+}
+
+static struct pmu perf_cpu_clock = {
+       .task_ctx_nr    = perf_sw_context,
+
+       .event_init     = cpu_clock_event_init,
+       .add            = cpu_clock_event_add,
+       .del            = cpu_clock_event_del,
+       .start          = cpu_clock_event_start,
+       .stop           = cpu_clock_event_stop,
+       .read           = cpu_clock_event_read,
+};
+
+/*
+ * Software event: task time clock
+ */
+
+static void task_clock_event_update(struct perf_event *event, u64 now)
+{
+       u64 prev;
+       s64 delta;
+
+       prev = local64_xchg(&event->hw.prev_count, now);
+       delta = now - prev;
+       local64_add(delta, &event->count);
+}
+
+static void task_clock_event_start(struct perf_event *event, int flags)
+{
+       local64_set(&event->hw.prev_count, event->ctx->time);
+       perf_swevent_start_hrtimer(event);
+}
+
+static void task_clock_event_stop(struct perf_event *event, int flags)
+{
+       perf_swevent_cancel_hrtimer(event);
+       task_clock_event_update(event, event->ctx->time);
+}
+
+static int task_clock_event_add(struct perf_event *event, int flags)
+{
+       if (flags & PERF_EF_START)
+               task_clock_event_start(event, flags);
+
+       return 0;
+}
+
+static void task_clock_event_del(struct perf_event *event, int flags)
+{
+       task_clock_event_stop(event, PERF_EF_UPDATE);
+}
+
+static void task_clock_event_read(struct perf_event *event)
+{
+       u64 time;
+
+       if (!in_nmi()) {
+               update_context_time(event->ctx);
+               time = event->ctx->time;
+       } else {
+               u64 now = perf_clock();
+               u64 delta = now - event->ctx->timestamp;
+               time = event->ctx->time + delta;
+       }
+
+       task_clock_event_update(event, time);
+}
+
+static int task_clock_event_init(struct perf_event *event)
+{
+       if (event->attr.type != PERF_TYPE_SOFTWARE)
+               return -ENOENT;
+
+       if (event->attr.config != PERF_COUNT_SW_TASK_CLOCK)
+               return -ENOENT;
+
+       return 0;
+}
+
+static struct pmu perf_task_clock = {
+       .task_ctx_nr    = perf_sw_context,
+
+       .event_init     = task_clock_event_init,
+       .add            = task_clock_event_add,
+       .del            = task_clock_event_del,
+       .start          = task_clock_event_start,
+       .stop           = task_clock_event_stop,
+       .read           = task_clock_event_read,
+};
+
+static void perf_pmu_nop_void(struct pmu *pmu)
+{
+}
+
+static int perf_pmu_nop_int(struct pmu *pmu)
+{
+       return 0;
+}
+
+static void perf_pmu_start_txn(struct pmu *pmu)
+{
+       perf_pmu_disable(pmu);
+}
+
+static int perf_pmu_commit_txn(struct pmu *pmu)
+{
+       perf_pmu_enable(pmu);
+       return 0;
+}
+
+static void perf_pmu_cancel_txn(struct pmu *pmu)
+{
+       perf_pmu_enable(pmu);
+}
+
+/*
+ * Ensures all contexts with the same task_ctx_nr have the same
+ * pmu_cpu_context too.
+ */
+static void *find_pmu_context(int ctxn)
+{
+       struct pmu *pmu;
+
+       if (ctxn < 0)
+               return NULL;
+
+       list_for_each_entry(pmu, &pmus, entry) {
+               if (pmu->task_ctx_nr == ctxn)
+                       return pmu->pmu_cpu_context;
+       }
 
+       return NULL;
+}
+
+static void free_pmu_context(void * __percpu cpu_context)
+{
+       struct pmu *pmu;
+
+       mutex_lock(&pmus_lock);
        /*
-        * Software events (currently) can't in general distinguish
-        * between user, kernel and hypervisor events.
-        * However, context switches and cpu migrations are considered
-        * to be kernel events, and page faults are never hypervisor
-        * events.
+        * Like a real lame refcount.
         */
-       switch (event_id) {
-       case PERF_COUNT_SW_CPU_CLOCK:
-               pmu = &perf_ops_cpu_clock;
+       list_for_each_entry(pmu, &pmus, entry) {
+               if (pmu->pmu_cpu_context == cpu_context)
+                       goto out;
+       }
 
-               break;
-       case PERF_COUNT_SW_TASK_CLOCK:
-               /*
-                * If the user instantiates this as a per-cpu event,
-                * use the cpu_clock event instead.
-                */
-               if (event->ctx->task)
-                       pmu = &perf_ops_task_clock;
-               else
-                       pmu = &perf_ops_cpu_clock;
+       free_percpu(cpu_context);
+out:
+       mutex_unlock(&pmus_lock);
+}
 
-               break;
-       case PERF_COUNT_SW_PAGE_FAULTS:
-       case PERF_COUNT_SW_PAGE_FAULTS_MIN:
-       case PERF_COUNT_SW_PAGE_FAULTS_MAJ:
-       case PERF_COUNT_SW_CONTEXT_SWITCHES:
-       case PERF_COUNT_SW_CPU_MIGRATIONS:
-       case PERF_COUNT_SW_ALIGNMENT_FAULTS:
-       case PERF_COUNT_SW_EMULATION_FAULTS:
-               if (!event->parent) {
-                       int err;
-
-                       err = swevent_hlist_get(event);
-                       if (err)
-                               return ERR_PTR(err);
+int perf_pmu_register(struct pmu *pmu)
+{
+       int cpu, ret;
+
+       mutex_lock(&pmus_lock);
+       ret = -ENOMEM;
+       pmu->pmu_disable_count = alloc_percpu(int);
+       if (!pmu->pmu_disable_count)
+               goto unlock;
+
+       pmu->pmu_cpu_context = find_pmu_context(pmu->task_ctx_nr);
+       if (pmu->pmu_cpu_context)
+               goto got_cpu_context;
+
+       pmu->pmu_cpu_context = alloc_percpu(struct perf_cpu_context);
+       if (!pmu->pmu_cpu_context)
+               goto free_pdc;
+
+       for_each_possible_cpu(cpu) {
+               struct perf_cpu_context *cpuctx;
 
-                       atomic_inc(&perf_swevent_enabled[event_id]);
-                       event->destroy = sw_perf_event_destroy;
+               cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu);
+               __perf_event_init_context(&cpuctx->ctx);
+               cpuctx->ctx.type = cpu_context;
+               cpuctx->ctx.pmu = pmu;
+               cpuctx->jiffies_interval = 1;
+               INIT_LIST_HEAD(&cpuctx->rotation_list);
+       }
+
+got_cpu_context:
+       if (!pmu->start_txn) {
+               if (pmu->pmu_enable) {
+                       /*
+                        * If we have pmu_enable/pmu_disable calls, install
+                        * transaction stubs that use that to try and batch
+                        * hardware accesses.
+                        */
+                       pmu->start_txn  = perf_pmu_start_txn;
+                       pmu->commit_txn = perf_pmu_commit_txn;
+                       pmu->cancel_txn = perf_pmu_cancel_txn;
+               } else {
+                       pmu->start_txn  = perf_pmu_nop_void;
+                       pmu->commit_txn = perf_pmu_nop_int;
+                       pmu->cancel_txn = perf_pmu_nop_void;
+               }
+       }
+
+       if (!pmu->pmu_enable) {
+               pmu->pmu_enable  = perf_pmu_nop_void;
+               pmu->pmu_disable = perf_pmu_nop_void;
+       }
+
+       list_add_rcu(&pmu->entry, &pmus);
+       ret = 0;
+unlock:
+       mutex_unlock(&pmus_lock);
+
+       return ret;
+
+free_pdc:
+       free_percpu(pmu->pmu_disable_count);
+       goto unlock;
+}
+
+void perf_pmu_unregister(struct pmu *pmu)
+{
+       mutex_lock(&pmus_lock);
+       list_del_rcu(&pmu->entry);
+       mutex_unlock(&pmus_lock);
+
+       /*
+        * We dereference the pmu list under both SRCU and regular RCU, so
+        * synchronize against both of those.
+        */
+       synchronize_srcu(&pmus_srcu);
+       synchronize_rcu();
+
+       free_percpu(pmu->pmu_disable_count);
+       free_pmu_context(pmu->pmu_cpu_context);
+}
+
+struct pmu *perf_init_event(struct perf_event *event)
+{
+       struct pmu *pmu = NULL;
+       int idx;
+
+       idx = srcu_read_lock(&pmus_srcu);
+       list_for_each_entry_rcu(pmu, &pmus, entry) {
+               int ret = pmu->event_init(event);
+               if (!ret)
+                       goto unlock;
+
+               if (ret != -ENOENT) {
+                       pmu = ERR_PTR(ret);
+                       goto unlock;
                }
-               pmu = &perf_ops_generic;
-               break;
        }
+       pmu = ERR_PTR(-ENOENT);
+unlock:
+       srcu_read_unlock(&pmus_srcu, idx);
 
        return pmu;
 }
@@ -4826,20 +5213,18 @@ static const struct pmu *sw_perf_event_init(struct perf_event *event)
  * Allocate and initialize a event structure
  */
 static struct perf_event *
-perf_event_alloc(struct perf_event_attr *attr,
-                  int cpu,
-                  struct perf_event_context *ctx,
-                  struct perf_event *group_leader,
-                  struct perf_event *parent_event,
-                  perf_overflow_handler_t overflow_handler,
-                  gfp_t gfpflags)
-{
-       const struct pmu *pmu;
+perf_event_alloc(struct perf_event_attr *attr, int cpu,
+                struct task_struct *task,
+                struct perf_event *group_leader,
+                struct perf_event *parent_event,
+                perf_overflow_handler_t overflow_handler)
+{
+       struct pmu *pmu;
        struct perf_event *event;
        struct hw_perf_event *hwc;
        long err;
 
-       event = kzalloc(sizeof(*event), gfpflags);
+       event = kzalloc(sizeof(*event), GFP_KERNEL);
        if (!event)
                return ERR_PTR(-ENOMEM);
 
@@ -4857,6 +5242,7 @@ perf_event_alloc(struct perf_event_attr *attr,
        INIT_LIST_HEAD(&event->event_entry);
        INIT_LIST_HEAD(&event->sibling_list);
        init_waitqueue_head(&event->waitq);
+       init_irq_work(&event->pending, perf_pending_event);
 
        mutex_init(&event->mmap_mutex);
 
@@ -4864,7 +5250,6 @@ perf_event_alloc(struct perf_event_attr *attr,
        event->attr             = *attr;
        event->group_leader     = group_leader;
        event->pmu              = NULL;
-       event->ctx              = ctx;
        event->oncpu            = -1;
 
        event->parent           = parent_event;
@@ -4874,6 +5259,17 @@ perf_event_alloc(struct perf_event_attr *attr,
 
        event->state            = PERF_EVENT_STATE_INACTIVE;
 
+       if (task) {
+               event->attach_state = PERF_ATTACH_TASK;
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+               /*
+                * hw_breakpoint is a bit difficult here..
+                */
+               if (attr->type == PERF_TYPE_BREAKPOINT)
+                       event->hw.bp_target = task;
+#endif
+       }
+
        if (!overflow_handler && parent_event)
                overflow_handler = parent_event->overflow_handler;
        
@@ -4898,29 +5294,8 @@ perf_event_alloc(struct perf_event_attr *attr,
        if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP))
                goto done;
 
-       switch (attr->type) {
-       case PERF_TYPE_RAW:
-       case PERF_TYPE_HARDWARE:
-       case PERF_TYPE_HW_CACHE:
-               pmu = hw_perf_event_init(event);
-               break;
-
-       case PERF_TYPE_SOFTWARE:
-               pmu = sw_perf_event_init(event);
-               break;
-
-       case PERF_TYPE_TRACEPOINT:
-               pmu = tp_perf_event_init(event);
-               break;
-
-       case PERF_TYPE_BREAKPOINT:
-               pmu = bp_perf_event_init(event);
-               break;
-
+       pmu = perf_init_event(event);
 
-       default:
-               break;
-       }
 done:
        err = 0;
        if (!pmu)
@@ -4938,13 +5313,21 @@ done:
        event->pmu = pmu;
 
        if (!event->parent) {
-               atomic_inc(&nr_events);
+               if (event->attach_state & PERF_ATTACH_TASK)
+                       jump_label_inc(&perf_task_events);
                if (event->attr.mmap || event->attr.mmap_data)
                        atomic_inc(&nr_mmap_events);
                if (event->attr.comm)
                        atomic_inc(&nr_comm_events);
                if (event->attr.task)
                        atomic_inc(&nr_task_events);
+               if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {
+                       err = get_callchain_buffers();
+                       if (err) {
+                               free_event(event);
+                               return ERR_PTR(err);
+                       }
+               }
        }
 
        return event;
@@ -5092,12 +5475,16 @@ SYSCALL_DEFINE5(perf_event_open,
                struct perf_event_attr __user *, attr_uptr,
                pid_t, pid, int, cpu, int, group_fd, unsigned long, flags)
 {
-       struct perf_event *event, *group_leader = NULL, *output_event = NULL;
+       struct perf_event *group_leader = NULL, *output_event = NULL;
+       struct perf_event *event, *sibling;
        struct perf_event_attr attr;
        struct perf_event_context *ctx;
        struct file *event_file = NULL;
        struct file *group_file = NULL;
+       struct task_struct *task = NULL;
+       struct pmu *pmu;
        int event_fd;
+       int move_group = 0;
        int fput_needed = 0;
        int err;
 
@@ -5123,20 +5510,11 @@ SYSCALL_DEFINE5(perf_event_open,
        if (event_fd < 0)
                return event_fd;
 
-       /*
-        * Get the target context (task or percpu):
-        */
-       ctx = find_get_context(pid, cpu);
-       if (IS_ERR(ctx)) {
-               err = PTR_ERR(ctx);
-               goto err_fd;
-       }
-
        if (group_fd != -1) {
                group_leader = perf_fget_light(group_fd, &fput_needed);
                if (IS_ERR(group_leader)) {
                        err = PTR_ERR(group_leader);
-                       goto err_put_context;
+                       goto err_fd;
                }
                group_file = group_leader->filp;
                if (flags & PERF_FLAG_FD_OUTPUT)
@@ -5145,6 +5523,58 @@ SYSCALL_DEFINE5(perf_event_open,
                        group_leader = NULL;
        }
 
+       if (pid != -1) {
+               task = find_lively_task_by_vpid(pid);
+               if (IS_ERR(task)) {
+                       err = PTR_ERR(task);
+                       goto err_group_fd;
+               }
+       }
+
+       event = perf_event_alloc(&attr, cpu, task, group_leader, NULL, NULL);
+       if (IS_ERR(event)) {
+               err = PTR_ERR(event);
+               goto err_task;
+       }
+
+       /*
+        * Special case software events and allow them to be part of
+        * any hardware group.
+        */
+       pmu = event->pmu;
+
+       if (group_leader &&
+           (is_software_event(event) != is_software_event(group_leader))) {
+               if (is_software_event(event)) {
+                       /*
+                        * If event and group_leader are not both a software
+                        * event, and event is, then group leader is not.
+                        *
+                        * Allow the addition of software events to !software
+                        * groups, this is safe because software events never
+                        * fail to schedule.
+                        */
+                       pmu = group_leader->pmu;
+               } else if (is_software_event(group_leader) &&
+                          (group_leader->group_flags & PERF_GROUP_SOFTWARE)) {
+                       /*
+                        * In case the group is a pure software group, and we
+                        * try to add a hardware event, move the whole group to
+                        * the hardware context.
+                        */
+                       move_group = 1;
+               }
+       }
+
+       /*
+        * Get the target context (task or percpu):
+        */
+       ctx = find_get_context(pmu, task, cpu);
+       if (IS_ERR(ctx)) {
+               err = PTR_ERR(ctx);
+               goto err_alloc;
+       }
+
        /*
         * Look up the group leader (we will attach this event to it):
         */
@@ -5156,42 +5586,66 @@ SYSCALL_DEFINE5(perf_event_open,
                 * becoming part of another group-sibling):
                 */
                if (group_leader->group_leader != group_leader)
-                       goto err_put_context;
+                       goto err_context;
                /*
                 * Do not allow to attach to a group in a different
                 * task or CPU context:
                 */
-               if (group_leader->ctx != ctx)
-                       goto err_put_context;
+               if (move_group) {
+                       if (group_leader->ctx->type != ctx->type)
+                               goto err_context;
+               } else {
+                       if (group_leader->ctx != ctx)
+                               goto err_context;
+               }
+
                /*
                 * Only a group leader can be exclusive or pinned
                 */
                if (attr.exclusive || attr.pinned)
-                       goto err_put_context;
-       }
-
-       event = perf_event_alloc(&attr, cpu, ctx, group_leader,
-                                    NULL, NULL, GFP_KERNEL);
-       if (IS_ERR(event)) {
-               err = PTR_ERR(event);
-               goto err_put_context;
+                       goto err_context;
        }
 
        if (output_event) {
                err = perf_event_set_output(event, output_event);
                if (err)
-                       goto err_free_put_context;
+                       goto err_context;
        }
 
        event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR);
        if (IS_ERR(event_file)) {
                err = PTR_ERR(event_file);
-               goto err_free_put_context;
+               goto err_context;
+       }
+
+       if (move_group) {
+               struct perf_event_context *gctx = group_leader->ctx;
+
+               mutex_lock(&gctx->mutex);
+               perf_event_remove_from_context(group_leader);
+               list_for_each_entry(sibling, &group_leader->sibling_list,
+                                   group_entry) {
+                       perf_event_remove_from_context(sibling);
+                       put_ctx(gctx);
+               }
+               mutex_unlock(&gctx->mutex);
+               put_ctx(gctx);
        }
 
        event->filp = event_file;
        WARN_ON_ONCE(ctx->parent_ctx);
        mutex_lock(&ctx->mutex);
+
+       if (move_group) {
+               perf_install_in_context(ctx, group_leader, cpu);
+               get_ctx(ctx);
+               list_for_each_entry(sibling, &group_leader->sibling_list,
+                                   group_entry) {
+                       perf_install_in_context(ctx, sibling, cpu);
+                       get_ctx(ctx);
+               }
+       }
+
        perf_install_in_context(ctx, event, cpu);
        ++ctx->generation;
        mutex_unlock(&ctx->mutex);
@@ -5212,11 +5666,15 @@ SYSCALL_DEFINE5(perf_event_open,
        fd_install(event_fd, event_file);
        return event_fd;
 
-err_free_put_context:
+err_context:
+       put_ctx(ctx);
+err_alloc:
        free_event(event);
-err_put_context:
+err_task:
+       if (task)
+               put_task_struct(task);
+err_group_fd:
        fput_light(group_file, fput_needed);
-       put_ctx(ctx);
 err_fd:
        put_unused_fd(event_fd);
        return err;
@@ -5227,154 +5685,54 @@ err_fd:
  *
  * @attr: attributes of the counter to create
  * @cpu: cpu in which the counter is bound
- * @pid: task to profile
+ * @task: task to profile (NULL for percpu)
  */
 struct perf_event *
 perf_event_create_kernel_counter(struct perf_event_attr *attr, int cpu,
-                                pid_t pid,
+                                struct task_struct *task,
                                 perf_overflow_handler_t overflow_handler)
 {
-       struct perf_event *event;
        struct perf_event_context *ctx;
-       int err;
-
-       /*
-        * Get the target context (task or percpu):
-        */
-
-       ctx = find_get_context(pid, cpu);
-       if (IS_ERR(ctx)) {
-               err = PTR_ERR(ctx);
-               goto err_exit;
-       }
-
-       event = perf_event_alloc(attr, cpu, ctx, NULL,
-                                NULL, overflow_handler, GFP_KERNEL);
-       if (IS_ERR(event)) {
-               err = PTR_ERR(event);
-               goto err_put_context;
-       }
-
-       event->filp = NULL;
-       WARN_ON_ONCE(ctx->parent_ctx);
-       mutex_lock(&ctx->mutex);
-       perf_install_in_context(ctx, event, cpu);
-       ++ctx->generation;
-       mutex_unlock(&ctx->mutex);
-
-       event->owner = current;
-       get_task_struct(current);
-       mutex_lock(&current->perf_event_mutex);
-       list_add_tail(&event->owner_entry, &current->perf_event_list);
-       mutex_unlock(&current->perf_event_mutex);
-
-       return event;
-
- err_put_context:
-       put_ctx(ctx);
- err_exit:
-       return ERR_PTR(err);
-}
-EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter);
-
-/*
- * inherit a event from parent task to child task:
- */
-static struct perf_event *
-inherit_event(struct perf_event *parent_event,
-             struct task_struct *parent,
-             struct perf_event_context *parent_ctx,
-             struct task_struct *child,
-             struct perf_event *group_leader,
-             struct perf_event_context *child_ctx)
-{
-       struct perf_event *child_event;
-
-       /*
-        * Instead of creating recursive hierarchies of events,
-        * we link inherited events back to the original parent,
-        * which has a filp for sure, which we use as the reference
-        * count:
-        */
-       if (parent_event->parent)
-               parent_event = parent_event->parent;
-
-       child_event = perf_event_alloc(&parent_event->attr,
-                                          parent_event->cpu, child_ctx,
-                                          group_leader, parent_event,
-                                          NULL, GFP_KERNEL);
-       if (IS_ERR(child_event))
-               return child_event;
-       get_ctx(child_ctx);
-
-       /*
-        * Make the child state follow the state of the parent event,
-        * not its attr.disabled bit.  We hold the parent's mutex,
-        * so we won't race with perf_event_{en, dis}able_family.
-        */
-       if (parent_event->state >= PERF_EVENT_STATE_INACTIVE)
-               child_event->state = PERF_EVENT_STATE_INACTIVE;
-       else
-               child_event->state = PERF_EVENT_STATE_OFF;
-
-       if (parent_event->attr.freq) {
-               u64 sample_period = parent_event->hw.sample_period;
-               struct hw_perf_event *hwc = &child_event->hw;
-
-               hwc->sample_period = sample_period;
-               hwc->last_period   = sample_period;
-
-               local64_set(&hwc->period_left, sample_period);
-       }
-
-       child_event->overflow_handler = parent_event->overflow_handler;
-
-       /*
-        * Link it up in the child's context:
-        */
-       add_event_to_ctx(child_event, child_ctx);
-
-       /*
-        * Get a reference to the parent filp - we will fput it
-        * when the child event exits. This is safe to do because
-        * we are in the parent and we know that the filp still
-        * exists and has a nonzero count:
-        */
-       atomic_long_inc(&parent_event->filp->f_count);
-
-       /*
-        * Link this into the parent event's child list
-        */
-       WARN_ON_ONCE(parent_event->ctx->parent_ctx);
-       mutex_lock(&parent_event->child_mutex);
-       list_add_tail(&child_event->child_list, &parent_event->child_list);
-       mutex_unlock(&parent_event->child_mutex);
+       struct perf_event *event;
+       int err;
 
-       return child_event;
-}
+       /*
+        * Get the target context (task or percpu):
+        */
 
-static int inherit_group(struct perf_event *parent_event,
-             struct task_struct *parent,
-             struct perf_event_context *parent_ctx,
-             struct task_struct *child,
-             struct perf_event_context *child_ctx)
-{
-       struct perf_event *leader;
-       struct perf_event *sub;
-       struct perf_event *child_ctr;
+       event = perf_event_alloc(attr, cpu, task, NULL, NULL, overflow_handler);
+       if (IS_ERR(event)) {
+               err = PTR_ERR(event);
+               goto err;
+       }
 
-       leader = inherit_event(parent_event, parent, parent_ctx,
-                                child, NULL, child_ctx);
-       if (IS_ERR(leader))
-               return PTR_ERR(leader);
-       list_for_each_entry(sub, &parent_event->sibling_list, group_entry) {
-               child_ctr = inherit_event(sub, parent, parent_ctx,
-                                           child, leader, child_ctx);
-               if (IS_ERR(child_ctr))
-                       return PTR_ERR(child_ctr);
+       ctx = find_get_context(event->pmu, task, cpu);
+       if (IS_ERR(ctx)) {
+               err = PTR_ERR(ctx);
+               goto err_free;
        }
-       return 0;
+
+       event->filp = NULL;
+       WARN_ON_ONCE(ctx->parent_ctx);
+       mutex_lock(&ctx->mutex);
+       perf_install_in_context(ctx, event, cpu);
+       ++ctx->generation;
+       mutex_unlock(&ctx->mutex);
+
+       event->owner = current;
+       get_task_struct(current);
+       mutex_lock(&current->perf_event_mutex);
+       list_add_tail(&event->owner_entry, &current->perf_event_list);
+       mutex_unlock(&current->perf_event_mutex);
+
+       return event;
+
+err_free:
+       free_event(event);
+err:
+       return ERR_PTR(err);
 }
+EXPORT_SYMBOL_GPL(perf_event_create_kernel_counter);
 
 static void sync_child_event(struct perf_event *child_event,
                               struct task_struct *child)
@@ -5432,16 +5790,13 @@ __perf_event_exit_task(struct perf_event *child_event,
        }
 }
 
-/*
- * When a child task exits, feed back event values to parent events.
- */
-void perf_event_exit_task(struct task_struct *child)
+static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
 {
        struct perf_event *child_event, *tmp;
        struct perf_event_context *child_ctx;
        unsigned long flags;
 
-       if (likely(!child->perf_event_ctxp)) {
+       if (likely(!child->perf_event_ctxp[ctxn])) {
                perf_event_task(child, NULL, 0);
                return;
        }
@@ -5453,8 +5808,8 @@ void perf_event_exit_task(struct task_struct *child)
         * scheduled, so we are now safe from rescheduling changing
         * our context.
         */
-       child_ctx = child->perf_event_ctxp;
-       __perf_event_task_sched_out(child_ctx);
+       child_ctx = child->perf_event_ctxp[ctxn];
+       task_ctx_sched_out(child_ctx, EVENT_ALL);
 
        /*
         * Take the context lock here so that if find_get_context is
@@ -5462,7 +5817,7 @@ void perf_event_exit_task(struct task_struct *child)
         * incremented the context's refcount before we do put_ctx below.
         */
        raw_spin_lock(&child_ctx->lock);
-       child->perf_event_ctxp = NULL;
+       child->perf_event_ctxp[ctxn] = NULL;
        /*
         * If this context is a clone; unclone it so it can't get
         * swapped to another process while we're removing all
@@ -5515,6 +5870,17 @@ again:
        put_ctx(child_ctx);
 }
 
+/*
+ * When a child task exits, feed back event values to parent events.
+ */
+void perf_event_exit_task(struct task_struct *child)
+{
+       int ctxn;
+
+       for_each_task_context_nr(ctxn)
+               perf_event_exit_task_context(child, ctxn);
+}
+
 static void perf_free_event(struct perf_event *event,
                            struct perf_event_context *ctx)
 {
@@ -5536,48 +5902,166 @@ static void perf_free_event(struct perf_event *event,
 
 /*
  * free an unexposed, unused context as created by inheritance by
- * init_task below, used by fork() in case of fail.
+ * perf_event_init_task below, used by fork() in case of fail.
  */
 void perf_event_free_task(struct task_struct *task)
 {
-       struct perf_event_context *ctx = task->perf_event_ctxp;
+       struct perf_event_context *ctx;
        struct perf_event *event, *tmp;
+       int ctxn;
 
-       if (!ctx)
-               return;
+       for_each_task_context_nr(ctxn) {
+               ctx = task->perf_event_ctxp[ctxn];
+               if (!ctx)
+                       continue;
 
-       mutex_lock(&ctx->mutex);
+               mutex_lock(&ctx->mutex);
 again:
-       list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry)
-               perf_free_event(event, ctx);
+               list_for_each_entry_safe(event, tmp, &ctx->pinned_groups,
+                               group_entry)
+                       perf_free_event(event, ctx);
 
-       list_for_each_entry_safe(event, tmp, &ctx->flexible_groups,
-                                group_entry)
-               perf_free_event(event, ctx);
+               list_for_each_entry_safe(event, tmp, &ctx->flexible_groups,
+                               group_entry)
+                       perf_free_event(event, ctx);
 
-       if (!list_empty(&ctx->pinned_groups) ||
-           !list_empty(&ctx->flexible_groups))
-               goto again;
+               if (!list_empty(&ctx->pinned_groups) ||
+                               !list_empty(&ctx->flexible_groups))
+                       goto again;
 
-       mutex_unlock(&ctx->mutex);
+               mutex_unlock(&ctx->mutex);
 
-       put_ctx(ctx);
+               put_ctx(ctx);
+       }
+}
+
+void perf_event_delayed_put(struct task_struct *task)
+{
+       int ctxn;
+
+       for_each_task_context_nr(ctxn)
+               WARN_ON_ONCE(task->perf_event_ctxp[ctxn]);
+}
+
+/*
+ * inherit a event from parent task to child task:
+ */
+static struct perf_event *
+inherit_event(struct perf_event *parent_event,
+             struct task_struct *parent,
+             struct perf_event_context *parent_ctx,
+             struct task_struct *child,
+             struct perf_event *group_leader,
+             struct perf_event_context *child_ctx)
+{
+       struct perf_event *child_event;
+       unsigned long flags;
+
+       /*
+        * Instead of creating recursive hierarchies of events,
+        * we link inherited events back to the original parent,
+        * which has a filp for sure, which we use as the reference
+        * count:
+        */
+       if (parent_event->parent)
+               parent_event = parent_event->parent;
+
+       child_event = perf_event_alloc(&parent_event->attr,
+                                          parent_event->cpu,
+                                          child,
+                                          group_leader, parent_event,
+                                          NULL);
+       if (IS_ERR(child_event))
+               return child_event;
+       get_ctx(child_ctx);
+
+       /*
+        * Make the child state follow the state of the parent event,
+        * not its attr.disabled bit.  We hold the parent's mutex,
+        * so we won't race with perf_event_{en, dis}able_family.
+        */
+       if (parent_event->state >= PERF_EVENT_STATE_INACTIVE)
+               child_event->state = PERF_EVENT_STATE_INACTIVE;
+       else
+               child_event->state = PERF_EVENT_STATE_OFF;
+
+       if (parent_event->attr.freq) {
+               u64 sample_period = parent_event->hw.sample_period;
+               struct hw_perf_event *hwc = &child_event->hw;
+
+               hwc->sample_period = sample_period;
+               hwc->last_period   = sample_period;
+
+               local64_set(&hwc->period_left, sample_period);
+       }
+
+       child_event->ctx = child_ctx;
+       child_event->overflow_handler = parent_event->overflow_handler;
+
+       /*
+        * Link it up in the child's context:
+        */
+       raw_spin_lock_irqsave(&child_ctx->lock, flags);
+       add_event_to_ctx(child_event, child_ctx);
+       raw_spin_unlock_irqrestore(&child_ctx->lock, flags);
+
+       /*
+        * Get a reference to the parent filp - we will fput it
+        * when the child event exits. This is safe to do because
+        * we are in the parent and we know that the filp still
+        * exists and has a nonzero count:
+        */
+       atomic_long_inc(&parent_event->filp->f_count);
+
+       /*
+        * Link this into the parent event's child list
+        */
+       WARN_ON_ONCE(parent_event->ctx->parent_ctx);
+       mutex_lock(&parent_event->child_mutex);
+       list_add_tail(&child_event->child_list, &parent_event->child_list);
+       mutex_unlock(&parent_event->child_mutex);
+
+       return child_event;
+}
+
+static int inherit_group(struct perf_event *parent_event,
+             struct task_struct *parent,
+             struct perf_event_context *parent_ctx,
+             struct task_struct *child,
+             struct perf_event_context *child_ctx)
+{
+       struct perf_event *leader;
+       struct perf_event *sub;
+       struct perf_event *child_ctr;
+
+       leader = inherit_event(parent_event, parent, parent_ctx,
+                                child, NULL, child_ctx);
+       if (IS_ERR(leader))
+               return PTR_ERR(leader);
+       list_for_each_entry(sub, &parent_event->sibling_list, group_entry) {
+               child_ctr = inherit_event(sub, parent, parent_ctx,
+                                           child, leader, child_ctx);
+               if (IS_ERR(child_ctr))
+                       return PTR_ERR(child_ctr);
+       }
+       return 0;
 }
 
 static int
 inherit_task_group(struct perf_event *event, struct task_struct *parent,
                   struct perf_event_context *parent_ctx,
-                  struct task_struct *child,
+                  struct task_struct *child, int ctxn,
                   int *inherited_all)
 {
        int ret;
-       struct perf_event_context *child_ctx = child->perf_event_ctxp;
+       struct perf_event_context *child_ctx;
 
        if (!event->attr.inherit) {
                *inherited_all = 0;
                return 0;
        }
 
+               child_ctx = child->perf_event_ctxp[ctxn];
        if (!child_ctx) {
                /*
                 * This is executed from the parent task context, so
@@ -5586,14 +6070,11 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent,
                 * child.
                 */
 
-               child_ctx = kzalloc(sizeof(struct perf_event_context),
-                                   GFP_KERNEL);
+               child_ctx = alloc_perf_context(event->pmu, child);
                if (!child_ctx)
                        return -ENOMEM;
 
-               __perf_event_init_context(child_ctx, child);
-               child->perf_event_ctxp = child_ctx;
-               get_task_struct(child);
+               child->perf_event_ctxp[ctxn] = child_ctx;
        }
 
        ret = inherit_group(event, parent, parent_ctx,
@@ -5605,11 +6086,10 @@ inherit_task_group(struct perf_event *event, struct task_struct *parent,
        return ret;
 }
 
-
 /*
  * Initialize the perf_event context in task_struct
  */
-int perf_event_init_task(struct task_struct *child)
+int perf_event_init_context(struct task_struct *child, int ctxn)
 {
        struct perf_event_context *child_ctx, *parent_ctx;
        struct perf_event_context *cloned_ctx;
@@ -5618,19 +6098,19 @@ int perf_event_init_task(struct task_struct *child)
        int inherited_all = 1;
        int ret = 0;
 
-       child->perf_event_ctxp = NULL;
+       child->perf_event_ctxp[ctxn] = NULL;
 
        mutex_init(&child->perf_event_mutex);
        INIT_LIST_HEAD(&child->perf_event_list);
 
-       if (likely(!parent->perf_event_ctxp))
+       if (likely(!parent->perf_event_ctxp[ctxn]))
                return 0;
 
        /*
         * If the parent's context is a clone, pin it so it won't get
         * swapped under us.
         */
-       parent_ctx = perf_pin_task_context(parent);
+       parent_ctx = perf_pin_task_context(parent, ctxn);
 
        /*
         * No need to check if parent_ctx != NULL here; since we saw
@@ -5650,20 +6130,20 @@ int perf_event_init_task(struct task_struct *child)
         * the list, not manipulating it:
         */
        list_for_each_entry(event, &parent_ctx->pinned_groups, group_entry) {
-               ret = inherit_task_group(event, parent, parent_ctx, child,
-                                        &inherited_all);
+               ret = inherit_task_group(event, parent, parent_ctx,
+                                        child, ctxn, &inherited_all);
                if (ret)
                        break;
        }
 
        list_for_each_entry(event, &parent_ctx->flexible_groups, group_entry) {
-               ret = inherit_task_group(event, parent, parent_ctx, child,
-                                        &inherited_all);
+               ret = inherit_task_group(event, parent, parent_ctx,
+                                        child, ctxn, &inherited_all);
                if (ret)
                        break;
        }
 
-       child_ctx = child->perf_event_ctxp;
+       child_ctx = child->perf_event_ctxp[ctxn];
 
        if (child_ctx && inherited_all) {
                /*
@@ -5692,63 +6172,98 @@ int perf_event_init_task(struct task_struct *child)
        return ret;
 }
 
+/*
+ * Initialize the perf_event context in task_struct
+ */
+int perf_event_init_task(struct task_struct *child)
+{
+       int ctxn, ret;
+
+       for_each_task_context_nr(ctxn) {
+               ret = perf_event_init_context(child, ctxn);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
 static void __init perf_event_init_all_cpus(void)
 {
+       struct swevent_htable *swhash;
        int cpu;
-       struct perf_cpu_context *cpuctx;
 
        for_each_possible_cpu(cpu) {
-               cpuctx = &per_cpu(perf_cpu_context, cpu);
-               mutex_init(&cpuctx->hlist_mutex);
-               __perf_event_init_context(&cpuctx->ctx, NULL);
+               swhash = &per_cpu(swevent_htable, cpu);
+               mutex_init(&swhash->hlist_mutex);
+               INIT_LIST_HEAD(&per_cpu(rotation_list, cpu));
        }
 }
 
 static void __cpuinit perf_event_init_cpu(int cpu)
 {
-       struct perf_cpu_context *cpuctx;
-
-       cpuctx = &per_cpu(perf_cpu_context, cpu);
+       struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
 
-       spin_lock(&perf_resource_lock);
-       cpuctx->max_pertask = perf_max_events - perf_reserved_percpu;
-       spin_unlock(&perf_resource_lock);
-
-       mutex_lock(&cpuctx->hlist_mutex);
-       if (cpuctx->hlist_refcount > 0) {
+       mutex_lock(&swhash->hlist_mutex);
+       if (swhash->hlist_refcount > 0) {
                struct swevent_hlist *hlist;
 
-               hlist = kzalloc(sizeof(*hlist), GFP_KERNEL);
-               WARN_ON_ONCE(!hlist);
-               rcu_assign_pointer(cpuctx->swevent_hlist, hlist);
+               hlist = kzalloc_node(sizeof(*hlist), GFP_KERNEL, cpu_to_node(cpu));
+               WARN_ON(!hlist);
+               rcu_assign_pointer(swhash->swevent_hlist, hlist);
        }
-       mutex_unlock(&cpuctx->hlist_mutex);
+       mutex_unlock(&swhash->hlist_mutex);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static void __perf_event_exit_cpu(void *info)
+static void perf_pmu_rotate_stop(struct pmu *pmu)
 {
-       struct perf_cpu_context *cpuctx = &__get_cpu_var(perf_cpu_context);
-       struct perf_event_context *ctx = &cpuctx->ctx;
+       struct perf_cpu_context *cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
+
+       WARN_ON(!irqs_disabled());
+
+       list_del_init(&cpuctx->rotation_list);
+}
+
+static void __perf_event_exit_context(void *__info)
+{
+       struct perf_event_context *ctx = __info;
        struct perf_event *event, *tmp;
 
+       perf_pmu_rotate_stop(ctx->pmu);
+
        list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry)
                __perf_event_remove_from_context(event);
        list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry)
                __perf_event_remove_from_context(event);
 }
+
+static void perf_event_exit_cpu_context(int cpu)
+{
+       struct perf_event_context *ctx;
+       struct pmu *pmu;
+       int idx;
+
+       idx = srcu_read_lock(&pmus_srcu);
+       list_for_each_entry_rcu(pmu, &pmus, entry) {
+               ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx;
+
+               mutex_lock(&ctx->mutex);
+               smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);
+               mutex_unlock(&ctx->mutex);
+       }
+       srcu_read_unlock(&pmus_srcu, idx);
+}
+
 static void perf_event_exit_cpu(int cpu)
 {
-       struct perf_cpu_context *cpuctx = &per_cpu(perf_cpu_context, cpu);
-       struct perf_event_context *ctx = &cpuctx->ctx;
+       struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
 
-       mutex_lock(&cpuctx->hlist_mutex);
-       swevent_hlist_release(cpuctx);
-       mutex_unlock(&cpuctx->hlist_mutex);
+       mutex_lock(&swhash->hlist_mutex);
+       swevent_hlist_release(swhash);
+       mutex_unlock(&swhash->hlist_mutex);
 
-       mutex_lock(&ctx->mutex);
-       smp_call_function_single(cpu, __perf_event_exit_cpu, NULL, 1);
-       mutex_unlock(&ctx->mutex);
+       perf_event_exit_cpu_context(cpu);
 }
 #else
 static inline void perf_event_exit_cpu(int cpu) { }
@@ -5778,118 +6293,13 @@ perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
-/*
- * This has to have a higher priority than migration_notifier in sched.c.
- */
-static struct notifier_block __cpuinitdata perf_cpu_nb = {
-       .notifier_call          = perf_cpu_notify,
-       .priority               = 20,
-};
-
 void __init perf_event_init(void)
 {
        perf_event_init_all_cpus();
-       perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_UP_PREPARE,
-                       (void *)(long)smp_processor_id());
-       perf_cpu_notify(&perf_cpu_nb, (unsigned long)CPU_ONLINE,
-                       (void *)(long)smp_processor_id());
-       register_cpu_notifier(&perf_cpu_nb);
-}
-
-static ssize_t perf_show_reserve_percpu(struct sysdev_class *class,
-                                       struct sysdev_class_attribute *attr,
-                                       char *buf)
-{
-       return sprintf(buf, "%d\n", perf_reserved_percpu);
-}
-
-static ssize_t
-perf_set_reserve_percpu(struct sysdev_class *class,
-                       struct sysdev_class_attribute *attr,
-                       const char *buf,
-                       size_t count)
-{
-       struct perf_cpu_context *cpuctx;
-       unsigned long val;
-       int err, cpu, mpt;
-
-       err = strict_strtoul(buf, 10, &val);
-       if (err)
-               return err;
-       if (val > perf_max_events)
-               return -EINVAL;
-
-       spin_lock(&perf_resource_lock);
-       perf_reserved_percpu = val;
-       for_each_online_cpu(cpu) {
-               cpuctx = &per_cpu(perf_cpu_context, cpu);
-               raw_spin_lock_irq(&cpuctx->ctx.lock);
-               mpt = min(perf_max_events - cpuctx->ctx.nr_events,
-                         perf_max_events - perf_reserved_percpu);
-               cpuctx->max_pertask = mpt;
-               raw_spin_unlock_irq(&cpuctx->ctx.lock);
-       }
-       spin_unlock(&perf_resource_lock);
-
-       return count;
-}
-
-static ssize_t perf_show_overcommit(struct sysdev_class *class,
-                                   struct sysdev_class_attribute *attr,
-                                   char *buf)
-{
-       return sprintf(buf, "%d\n", perf_overcommit);
-}
-
-static ssize_t
-perf_set_overcommit(struct sysdev_class *class,
-                   struct sysdev_class_attribute *attr,
-                   const char *buf, size_t count)
-{
-       unsigned long val;
-       int err;
-
-       err = strict_strtoul(buf, 10, &val);
-       if (err)
-               return err;
-       if (val > 1)
-               return -EINVAL;
-
-       spin_lock(&perf_resource_lock);
-       perf_overcommit = val;
-       spin_unlock(&perf_resource_lock);
-
-       return count;
-}
-
-static SYSDEV_CLASS_ATTR(
-                               reserve_percpu,
-                               0644,
-                               perf_show_reserve_percpu,
-                               perf_set_reserve_percpu
-                       );
-
-static SYSDEV_CLASS_ATTR(
-                               overcommit,
-                               0644,
-                               perf_show_overcommit,
-                               perf_set_overcommit
-                       );
-
-static struct attribute *perfclass_attrs[] = {
-       &attr_reserve_percpu.attr,
-       &attr_overcommit.attr,
-       NULL
-};
-
-static struct attribute_group perfclass_attr_group = {
-       .attrs                  = perfclass_attrs,
-       .name                   = "perf_events",
-};
-
-static int __init perf_event_sysfs_init(void)
-{
-       return sysfs_create_group(&cpu_sysdev_class.kset.kobj,
-                                 &perfclass_attr_group);
+       init_srcu_struct(&pmus_srcu);
+       perf_pmu_register(&perf_swevent);
+       perf_pmu_register(&perf_cpu_clock);
+       perf_pmu_register(&perf_task_clock);
+       perf_tp_register();
+       perf_cpu_notifier(perf_cpu_notify);
 }
-device_initcall(perf_event_sysfs_init);
index d55c6fb8d087a24a2d462886dfe1fc53bf9deced..39b65b69584f5b0f373e360d6ecc3118751840a9 100644 (file)
@@ -401,7 +401,7 @@ struct task_struct *pid_task(struct pid *pid, enum pid_type type)
        struct task_struct *result = NULL;
        if (pid) {
                struct hlist_node *first;
-               first = rcu_dereference_check(pid->tasks[type].first,
+               first = rcu_dereference_check(hlist_first_rcu(&pid->tasks[type]),
                                              rcu_read_lock_held() ||
                                              lockdep_tasklist_lock_is_held());
                if (first)
@@ -416,6 +416,7 @@ EXPORT_SYMBOL(pid_task);
  */
 struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns)
 {
+       rcu_lockdep_assert(rcu_read_lock_held());
        return pid_task(find_pid_ns(nr, ns), PIDTYPE_PID);
 }
 
index ca6066a6952e792421c8aff49b57afec5ae2415b..29bff6117abca747d31131424f58927e1a30558d 100644 (file)
@@ -86,6 +86,7 @@ config PM_SLEEP_SMP
        depends on SMP
        depends on ARCH_SUSPEND_POSSIBLE || ARCH_HIBERNATION_POSSIBLE
        depends on PM_SLEEP
+       select HOTPLUG
        select HOTPLUG_CPU
        default y
 
@@ -137,6 +138,8 @@ config SUSPEND_FREEZER
 config HIBERNATION
        bool "Hibernation (aka 'suspend to disk')"
        depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
+       select LZO_COMPRESS
+       select LZO_DECOMPRESS
        select SUSPEND_NVS if HAS_IOMEM
        ---help---
          Enable the suspend to disk (STD) functionality, which is usually
@@ -242,3 +245,17 @@ config PM_OPS
        bool
        depends on PM_SLEEP || PM_RUNTIME
        default y
+
+config PM_OPP
+       bool "Operating Performance Point (OPP) Layer library"
+       depends on PM
+       ---help---
+         SOCs have a standard set of tuples consisting of frequency and
+         voltage pairs that the device will support per voltage domain. This
+         is called Operating Performance Point or OPP. The actual definitions
+         of OPP varies over silicon within the same family of devices.
+
+         OPP layer organizes the data internally using device pointers
+         representing individual voltage domains and provides SOC
+         implementations a ready to use framework to manage OPPs.
+         For more information, read <file:Documentation/power/opp.txt>
index 8dc31e02ae129e8f042804b67c38ab02f997d94c..657272e91d0a0af648a892fd64ca2111a100dfb4 100644 (file)
@@ -29,6 +29,7 @@
 #include "power.h"
 
 
+static int nocompress = 0;
 static int noresume = 0;
 static char resume_file[256] = CONFIG_PM_STD_PARTITION;
 dev_t swsusp_resume_device;
@@ -638,6 +639,8 @@ int hibernate(void)
 
                if (hibernation_mode == HIBERNATION_PLATFORM)
                        flags |= SF_PLATFORM_MODE;
+               if (nocompress)
+                       flags |= SF_NOCOMPRESS_MODE;
                pr_debug("PM: writing image.\n");
                error = swsusp_write(flags);
                swsusp_free();
@@ -705,7 +708,7 @@ static int software_resume(void)
                goto Unlock;
        }
 
-       pr_debug("PM: Checking image partition %s\n", resume_file);
+       pr_debug("PM: Checking hibernation image partition %s\n", resume_file);
 
        /* Check if the device is there */
        swsusp_resume_device = name_to_dev_t(resume_file);
@@ -730,10 +733,10 @@ static int software_resume(void)
        }
 
  Check_image:
-       pr_debug("PM: Resume from partition %d:%d\n",
+       pr_debug("PM: Hibernation image partition %d:%d present\n",
                MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
 
-       pr_debug("PM: Checking hibernation image.\n");
+       pr_debug("PM: Looking for hibernation image.\n");
        error = swsusp_check();
        if (error)
                goto Unlock;
@@ -765,14 +768,14 @@ static int software_resume(void)
                goto Done;
        }
 
-       pr_debug("PM: Reading hibernation image.\n");
+       pr_debug("PM: Loading hibernation image.\n");
 
        error = swsusp_read(&flags);
        swsusp_close(FMODE_READ);
        if (!error)
                hibernation_restore(flags & SF_PLATFORM_MODE);
 
-       printk(KERN_ERR "PM: Restore failed, recovering.\n");
+       printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n");
        swsusp_free();
        thaw_processes();
  Done:
@@ -785,7 +788,7 @@ static int software_resume(void)
        /* For success case, the suspend path will release the lock */
  Unlock:
        mutex_unlock(&pm_mutex);
-       pr_debug("PM: Resume from disk failed.\n");
+       pr_debug("PM: Hibernation image not present or could not be loaded.\n");
        return error;
 close_finish:
        swsusp_close(FMODE_READ);
@@ -1004,6 +1007,15 @@ static int __init resume_offset_setup(char *str)
        return 1;
 }
 
+static int __init hibernate_setup(char *str)
+{
+       if (!strncmp(str, "noresume", 8))
+               noresume = 1;
+       else if (!strncmp(str, "nocompress", 10))
+               nocompress = 1;
+       return 1;
+}
+
 static int __init noresume_setup(char *str)
 {
        noresume = 1;
@@ -1013,3 +1025,4 @@ static int __init noresume_setup(char *str)
 __setup("noresume", noresume_setup);
 __setup("resume_offset=", resume_offset_setup);
 __setup("resume=", resume_setup);
+__setup("hibernate=", hibernate_setup);
index 62b0bc6e4983cfdec1a2b4feb0f34d2235781ad6..7b5db6a8561e9a945b75f08d82acfb401bc8cd4e 100644 (file)
@@ -237,18 +237,18 @@ static ssize_t wakeup_count_show(struct kobject *kobj,
                                struct kobj_attribute *attr,
                                char *buf)
 {
-       unsigned long val;
+       unsigned int val;
 
-       return pm_get_wakeup_count(&val) ? sprintf(buf, "%lu\n", val) : -EINTR;
+       return pm_get_wakeup_count(&val) ? sprintf(buf, "%u\n", val) : -EINTR;
 }
 
 static ssize_t wakeup_count_store(struct kobject *kobj,
                                struct kobj_attribute *attr,
                                const char *buf, size_t n)
 {
-       unsigned long val;
+       unsigned int val;
 
-       if (sscanf(buf, "%lu", &val) == 1) {
+       if (sscanf(buf, "%u", &val) == 1) {
                if (pm_save_wakeup_count(val))
                        return n;
        }
@@ -281,12 +281,30 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
 }
 
 power_attr(pm_trace);
+
+static ssize_t pm_trace_dev_match_show(struct kobject *kobj,
+                                      struct kobj_attribute *attr,
+                                      char *buf)
+{
+       return show_trace_dev_match(buf, PAGE_SIZE);
+}
+
+static ssize_t
+pm_trace_dev_match_store(struct kobject *kobj, struct kobj_attribute *attr,
+                        const char *buf, size_t n)
+{
+       return -EINVAL;
+}
+
+power_attr(pm_trace_dev_match);
+
 #endif /* CONFIG_PM_TRACE */
 
 static struct attribute * g[] = {
        &state_attr.attr,
 #ifdef CONFIG_PM_TRACE
        &pm_trace_attr.attr,
+       &pm_trace_dev_match_attr.attr,
 #endif
 #ifdef CONFIG_PM_SLEEP
        &pm_async_attr.attr,
@@ -308,7 +326,7 @@ EXPORT_SYMBOL_GPL(pm_wq);
 
 static int __init pm_start_workqueue(void)
 {
-       pm_wq = create_freezeable_workqueue("pm");
+       pm_wq = alloc_workqueue("pm", WQ_FREEZEABLE, 0);
 
        return pm_wq ? 0 : -ENOMEM;
 }
@@ -321,6 +339,7 @@ static int __init pm_init(void)
        int error = pm_start_workqueue();
        if (error)
                return error;
+       hibernate_image_size_init();
        power_kobj = kobject_create_and_add("power", NULL);
        if (!power_kobj)
                return -ENOMEM;
index 006270fe382d7f756e02082e4f5309258b1ca5e3..03634be55f62aabb407b8797d6a5a74ca6feef96 100644 (file)
@@ -14,6 +14,9 @@ struct swsusp_info {
 } __attribute__((aligned(PAGE_SIZE)));
 
 #ifdef CONFIG_HIBERNATION
+/* kernel/power/snapshot.c */
+extern void __init hibernate_image_size_init(void);
+
 #ifdef CONFIG_ARCH_HIBERNATION_HEADER
 /* Maximum size of architecture specific data in a hibernation header */
 #define MAX_ARCH_HEADER_SIZE   (sizeof(struct new_utsname) + 4)
@@ -49,7 +52,11 @@ static inline char *check_image_kernel(struct swsusp_info *info)
 extern int hibernation_snapshot(int platform_mode);
 extern int hibernation_restore(int platform_mode);
 extern int hibernation_platform_enter(void);
-#endif
+
+#else /* !CONFIG_HIBERNATION */
+
+static inline void hibernate_image_size_init(void) {}
+#endif /* !CONFIG_HIBERNATION */
 
 extern int pfn_is_nosave(unsigned long);
 
@@ -134,6 +141,7 @@ extern int swsusp_swap_in_use(void);
  * the image header.
  */
 #define SF_PLATFORM_MODE       1
+#define SF_NOCOMPRESS_MODE     2
 
 /* kernel/power/hibernate.c */
 extern int swsusp_check(void);
index 028a99598f4986b6dfcfaf946af51952f071c346..e50b4c1b2a0f7f8943acb041b5d8ab202c40d5cd 100644 (file)
@@ -40,6 +40,7 @@ static int try_to_freeze_tasks(bool sig_only)
        struct timeval start, end;
        u64 elapsed_csecs64;
        unsigned int elapsed_csecs;
+       bool wakeup = false;
 
        do_gettimeofday(&start);
 
@@ -78,6 +79,11 @@ static int try_to_freeze_tasks(bool sig_only)
                if (!todo || time_after(jiffies, end_time))
                        break;
 
+               if (!pm_check_wakeup_events()) {
+                       wakeup = true;
+                       break;
+               }
+
                /*
                 * We need to retry, but first give the freezing tasks some
                 * time to enter the regrigerator.
@@ -97,8 +103,9 @@ static int try_to_freeze_tasks(bool sig_only)
                 * but it cleans up leftover PF_FREEZE requests.
                 */
                printk("\n");
-               printk(KERN_ERR "Freezing of tasks failed after %d.%02d seconds "
+               printk(KERN_ERR "Freezing of tasks %s after %d.%02d seconds "
                       "(%d tasks refusing to freeze, wq_busy=%d):\n",
+                      wakeup ? "aborted" : "failed",
                       elapsed_csecs / 100, elapsed_csecs % 100,
                       todo - wq_busy, wq_busy);
 
@@ -107,7 +114,7 @@ static int try_to_freeze_tasks(bool sig_only)
                read_lock(&tasklist_lock);
                do_each_thread(g, p) {
                        task_lock(p);
-                       if (freezing(p) && !freezer_should_skip(p))
+                       if (!wakeup && freezing(p) && !freezer_should_skip(p))
                                sched_show_task(p);
                        cancel_freezing(p);
                        task_unlock(p);
index d3f795f01bbce83741fb717e1ee1a05e1377c561..ac7eb109f19635d11930a9cef03ed4cd352cc235 100644 (file)
@@ -46,7 +46,12 @@ static void swsusp_unset_page_forbidden(struct page *);
  * 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;
+unsigned long image_size;
+
+void __init hibernate_image_size_init(void)
+{
+       image_size = ((totalram_pages * 2) / 5) * PAGE_SIZE;
+}
 
 /* List of PBEs needed for restoring the pages that were allocated before
  * the suspend and included in the suspend image, but have also been
@@ -1318,12 +1323,14 @@ int hibernate_preallocate_memory(void)
 
        /* Compute the maximum number of saveable pages to leave in memory. */
        max_size = (count - (size + PAGES_FOR_IO)) / 2 - 2 * SPARE_PAGES;
+       /* Compute the desired number of image pages specified by image_size. */
        size = DIV_ROUND_UP(image_size, PAGE_SIZE);
        if (size > max_size)
                size = max_size;
        /*
-        * If the maximum is not less than the current number of saveable pages
-        * in memory, allocate page frames for the image and we're done.
+        * If the desired number of image pages is at least as large as the
+        * current number of saveable pages in memory, allocate page frames for
+        * the image and we're done.
         */
        if (size >= saveable) {
                pages = preallocate_image_highmem(save_highmem);
index e6a5bdf61a375c309c1f9ea356e9123d79699037..916eaa79039968ff8412128858e9b8aeda951ac6 100644 (file)
 #include <linux/swapops.h>
 #include <linux/pm.h>
 #include <linux/slab.h>
+#include <linux/lzo.h>
+#include <linux/vmalloc.h>
 
 #include "power.h"
 
-#define SWSUSP_SIG     "S1SUSPEND"
+#define HIBERNATE_SIG  "LINHIB0001"
 
 /*
  *     The swap map is a data structure used for keeping track of each page
@@ -193,7 +195,7 @@ static int mark_swapfiles(struct swap_map_handle *handle, unsigned int flags)
        if (!memcmp("SWAP-SPACE",swsusp_header->sig, 10) ||
            !memcmp("SWAPSPACE2",swsusp_header->sig, 10)) {
                memcpy(swsusp_header->orig_sig,swsusp_header->sig, 10);
-               memcpy(swsusp_header->sig,SWSUSP_SIG, 10);
+               memcpy(swsusp_header->sig, HIBERNATE_SIG, 10);
                swsusp_header->image = handle->first_sector;
                swsusp_header->flags = flags;
                error = hib_bio_write_page(swsusp_resume_block,
@@ -357,6 +359,18 @@ static int swap_writer_finish(struct swap_map_handle *handle,
        return error;
 }
 
+/* We need to remember how much compressed data we need to read. */
+#define LZO_HEADER     sizeof(size_t)
+
+/* Number of pages/bytes we'll compress at one time. */
+#define LZO_UNC_PAGES  32
+#define LZO_UNC_SIZE   (LZO_UNC_PAGES * PAGE_SIZE)
+
+/* Number of pages/bytes we need for compressed data (worst case). */
+#define LZO_CMP_PAGES  DIV_ROUND_UP(lzo1x_worst_compress(LZO_UNC_SIZE) + \
+                                    LZO_HEADER, PAGE_SIZE)
+#define LZO_CMP_SIZE   (LZO_CMP_PAGES * PAGE_SIZE)
+
 /**
  *     save_image - save the suspend image data
  */
@@ -404,6 +418,137 @@ static int save_image(struct swap_map_handle *handle,
        return ret;
 }
 
+
+/**
+ * save_image_lzo - Save the suspend image data compressed with LZO.
+ * @handle: Swap mam handle to use for saving the image.
+ * @snapshot: Image to read data from.
+ * @nr_to_write: Number of pages to save.
+ */
+static int save_image_lzo(struct swap_map_handle *handle,
+                          struct snapshot_handle *snapshot,
+                          unsigned int nr_to_write)
+{
+       unsigned int m;
+       int ret = 0;
+       int nr_pages;
+       int err2;
+       struct bio *bio;
+       struct timeval start;
+       struct timeval stop;
+       size_t off, unc_len, cmp_len;
+       unsigned char *unc, *cmp, *wrk, *page;
+
+       page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+       if (!page) {
+               printk(KERN_ERR "PM: Failed to allocate LZO page\n");
+               return -ENOMEM;
+       }
+
+       wrk = vmalloc(LZO1X_1_MEM_COMPRESS);
+       if (!wrk) {
+               printk(KERN_ERR "PM: Failed to allocate LZO workspace\n");
+               free_page((unsigned long)page);
+               return -ENOMEM;
+       }
+
+       unc = vmalloc(LZO_UNC_SIZE);
+       if (!unc) {
+               printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
+               vfree(wrk);
+               free_page((unsigned long)page);
+               return -ENOMEM;
+       }
+
+       cmp = vmalloc(LZO_CMP_SIZE);
+       if (!cmp) {
+               printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
+               vfree(unc);
+               vfree(wrk);
+               free_page((unsigned long)page);
+               return -ENOMEM;
+       }
+
+       printk(KERN_INFO
+               "PM: Compressing and saving image data (%u pages) ...     ",
+               nr_to_write);
+       m = nr_to_write / 100;
+       if (!m)
+               m = 1;
+       nr_pages = 0;
+       bio = NULL;
+       do_gettimeofday(&start);
+       for (;;) {
+               for (off = 0; off < LZO_UNC_SIZE; off += PAGE_SIZE) {
+                       ret = snapshot_read_next(snapshot);
+                       if (ret < 0)
+                               goto out_finish;
+
+                       if (!ret)
+                               break;
+
+                       memcpy(unc + off, data_of(*snapshot), PAGE_SIZE);
+
+                       if (!(nr_pages % m))
+                               printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m);
+                       nr_pages++;
+               }
+
+               if (!off)
+                       break;
+
+               unc_len = off;
+               ret = lzo1x_1_compress(unc, unc_len,
+                                      cmp + LZO_HEADER, &cmp_len, wrk);
+               if (ret < 0) {
+                       printk(KERN_ERR "PM: LZO compression failed\n");
+                       break;
+               }
+
+               if (unlikely(!cmp_len ||
+                            cmp_len > lzo1x_worst_compress(unc_len))) {
+                       printk(KERN_ERR "PM: Invalid LZO compressed length\n");
+                       ret = -1;
+                       break;
+               }
+
+               *(size_t *)cmp = cmp_len;
+
+               /*
+                * Given we are writing one page at a time to disk, we copy
+                * that much from the buffer, although the last bit will likely
+                * be smaller than full page. This is OK - we saved the length
+                * of the compressed data, so any garbage at the end will be
+                * discarded when we read it.
+                */
+               for (off = 0; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) {
+                       memcpy(page, cmp + off, PAGE_SIZE);
+
+                       ret = swap_write_page(handle, page, &bio);
+                       if (ret)
+                               goto out_finish;
+               }
+       }
+
+out_finish:
+       err2 = hib_wait_on_bio_chain(&bio);
+       do_gettimeofday(&stop);
+       if (!ret)
+               ret = err2;
+       if (!ret)
+               printk(KERN_CONT "\b\b\b\bdone\n");
+       else
+               printk(KERN_CONT "\n");
+       swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+
+       vfree(cmp);
+       vfree(unc);
+       vfree(wrk);
+       free_page((unsigned long)page);
+
+       return ret;
+}
+
 /**
  *     enough_swap - Make sure we have enough swap to save the image.
  *
@@ -411,12 +556,16 @@ static int save_image(struct swap_map_handle *handle,
  *     space avaiable from the resume partition.
  */
 
-static int enough_swap(unsigned int nr_pages)
+static int enough_swap(unsigned int nr_pages, unsigned int flags)
 {
        unsigned int free_swap = count_swap_pages(root_swap, 1);
+       unsigned int required;
 
        pr_debug("PM: Free swap pages: %u\n", free_swap);
-       return free_swap > nr_pages + PAGES_FOR_IO;
+
+       required = PAGES_FOR_IO + ((flags & SF_NOCOMPRESS_MODE) ?
+               nr_pages : (nr_pages * LZO_CMP_PAGES) / LZO_UNC_PAGES + 1);
+       return free_swap > required;
 }
 
 /**
@@ -443,7 +592,7 @@ int swsusp_write(unsigned int flags)
                printk(KERN_ERR "PM: Cannot get swap writer\n");
                return error;
        }
-       if (!enough_swap(pages)) {
+       if (!enough_swap(pages, flags)) {
                printk(KERN_ERR "PM: Not enough free swap\n");
                error = -ENOSPC;
                goto out_finish;
@@ -458,8 +607,11 @@ int swsusp_write(unsigned int flags)
        }
        header = (struct swsusp_info *)data_of(snapshot);
        error = swap_write_page(&handle, header, NULL);
-       if (!error)
-               error = save_image(&handle, &snapshot, pages - 1);
+       if (!error) {
+               error = (flags & SF_NOCOMPRESS_MODE) ?
+                       save_image(&handle, &snapshot, pages - 1) :
+                       save_image_lzo(&handle, &snapshot, pages - 1);
+       }
 out_finish:
        error = swap_writer_finish(&handle, flags, error);
        return error;
@@ -589,6 +741,127 @@ static int load_image(struct swap_map_handle *handle,
        return error;
 }
 
+/**
+ * load_image_lzo - Load compressed image data and decompress them with LZO.
+ * @handle: Swap map handle to use for loading data.
+ * @snapshot: Image to copy uncompressed data into.
+ * @nr_to_read: Number of pages to load.
+ */
+static int load_image_lzo(struct swap_map_handle *handle,
+                          struct snapshot_handle *snapshot,
+                          unsigned int nr_to_read)
+{
+       unsigned int m;
+       int error = 0;
+       struct timeval start;
+       struct timeval stop;
+       unsigned nr_pages;
+       size_t off, unc_len, cmp_len;
+       unsigned char *unc, *cmp, *page;
+
+       page = (void *)__get_free_page(__GFP_WAIT | __GFP_HIGH);
+       if (!page) {
+               printk(KERN_ERR "PM: Failed to allocate LZO page\n");
+               return -ENOMEM;
+       }
+
+       unc = vmalloc(LZO_UNC_SIZE);
+       if (!unc) {
+               printk(KERN_ERR "PM: Failed to allocate LZO uncompressed\n");
+               free_page((unsigned long)page);
+               return -ENOMEM;
+       }
+
+       cmp = vmalloc(LZO_CMP_SIZE);
+       if (!cmp) {
+               printk(KERN_ERR "PM: Failed to allocate LZO compressed\n");
+               vfree(unc);
+               free_page((unsigned long)page);
+               return -ENOMEM;
+       }
+
+       printk(KERN_INFO
+               "PM: Loading and decompressing image data (%u pages) ...     ",
+               nr_to_read);
+       m = nr_to_read / 100;
+       if (!m)
+               m = 1;
+       nr_pages = 0;
+       do_gettimeofday(&start);
+
+       error = snapshot_write_next(snapshot);
+       if (error <= 0)
+               goto out_finish;
+
+       for (;;) {
+               error = swap_read_page(handle, page, NULL); /* sync */
+               if (error)
+                       break;
+
+               cmp_len = *(size_t *)page;
+               if (unlikely(!cmp_len ||
+                            cmp_len > lzo1x_worst_compress(LZO_UNC_SIZE))) {
+                       printk(KERN_ERR "PM: Invalid LZO compressed length\n");
+                       error = -1;
+                       break;
+               }
+
+               memcpy(cmp, page, PAGE_SIZE);
+               for (off = PAGE_SIZE; off < LZO_HEADER + cmp_len; off += PAGE_SIZE) {
+                       error = swap_read_page(handle, page, NULL); /* sync */
+                       if (error)
+                               goto out_finish;
+
+                       memcpy(cmp + off, page, PAGE_SIZE);
+               }
+
+               unc_len = LZO_UNC_SIZE;
+               error = lzo1x_decompress_safe(cmp + LZO_HEADER, cmp_len,
+                                             unc, &unc_len);
+               if (error < 0) {
+                       printk(KERN_ERR "PM: LZO decompression failed\n");
+                       break;
+               }
+
+               if (unlikely(!unc_len ||
+                            unc_len > LZO_UNC_SIZE ||
+                            unc_len & (PAGE_SIZE - 1))) {
+                       printk(KERN_ERR "PM: Invalid LZO uncompressed length\n");
+                       error = -1;
+                       break;
+               }
+
+               for (off = 0; off < unc_len; off += PAGE_SIZE) {
+                       memcpy(data_of(*snapshot), unc + off, PAGE_SIZE);
+
+                       if (!(nr_pages % m))
+                               printk("\b\b\b\b%3d%%", nr_pages / m);
+                       nr_pages++;
+
+                       error = snapshot_write_next(snapshot);
+                       if (error <= 0)
+                               goto out_finish;
+               }
+       }
+
+out_finish:
+       do_gettimeofday(&stop);
+       if (!error) {
+               printk("\b\b\b\bdone\n");
+               snapshot_write_finalize(snapshot);
+               if (!snapshot_image_loaded(snapshot))
+                       error = -ENODATA;
+       } else
+               printk("\n");
+       swsusp_show_speed(&start, &stop, nr_to_read, "Read");
+
+       vfree(cmp);
+       vfree(unc);
+       free_page((unsigned long)page);
+
+       return error;
+}
+
 /**
  *     swsusp_read - read the hibernation image.
  *     @flags_p: flags passed by the "frozen" kernel in the image header should
@@ -612,8 +885,11 @@ int swsusp_read(unsigned int *flags_p)
                goto end;
        if (!error)
                error = swap_read_page(&handle, header, NULL);
-       if (!error)
-               error = load_image(&handle, &snapshot, header->pages - 1);
+       if (!error) {
+               error = (*flags_p & SF_NOCOMPRESS_MODE) ?
+                       load_image(&handle, &snapshot, header->pages - 1) :
+                       load_image_lzo(&handle, &snapshot, header->pages - 1);
+       }
        swap_reader_finish(&handle);
 end:
        if (!error)
@@ -640,7 +916,7 @@ int swsusp_check(void)
                if (error)
                        goto put;
 
-               if (!memcmp(SWSUSP_SIG, swsusp_header->sig, 10)) {
+               if (!memcmp(HIBERNATE_SIG, swsusp_header->sig, 10)) {
                        memcpy(swsusp_header->sig, swsusp_header->orig_sig, 10);
                        /* Reset swap signature now */
                        error = hib_bio_write_page(swsusp_resume_block,
@@ -653,13 +929,13 @@ put:
                if (error)
                        blkdev_put(hib_resume_bdev, FMODE_READ);
                else
-                       pr_debug("PM: Signature found, resuming\n");
+                       pr_debug("PM: Image signature found, resuming\n");
        } else {
                error = PTR_ERR(hib_resume_bdev);
        }
 
        if (error)
-               pr_debug("PM: Error %d checking image file\n", error);
+               pr_debug("PM: Image not found (code %d)\n", error);
 
        return error;
 }
index 8fe465ac008aebdcdbb0e9db9fcd644d5b12c231..2531017795f63e7d9c60d1db976e2b227c98ffda 100644 (file)
@@ -85,7 +85,7 @@ EXPORT_SYMBOL(oops_in_progress);
  * provides serialisation for access to the entire console
  * driver system.
  */
-static DECLARE_MUTEX(console_sem);
+static DEFINE_SEMAPHORE(console_sem);
 struct console *console_drivers;
 EXPORT_SYMBOL_GPL(console_drivers);
 
@@ -556,7 +556,7 @@ static void zap_locks(void)
        /* If a crash is occurring, make sure we can't deadlock */
        spin_lock_init(&logbuf_lock);
        /* And make sure that we print immediately */
-       init_MUTEX(&console_sem);
+       sema_init(&console_sem, 1);
 }
 
 #if defined(CONFIG_PRINTK_TIME)
index 4d169835fb362dcd6eb52a916a0d8e85e48c8fb8..a23a57a976d1a46f69cb2c32ecc38dd78e5e8b08 100644 (file)
@@ -73,12 +73,14 @@ int debug_lockdep_rcu_enabled(void)
 EXPORT_SYMBOL_GPL(debug_lockdep_rcu_enabled);
 
 /**
- * rcu_read_lock_bh_held - might we be in RCU-bh read-side critical section?
+ * rcu_read_lock_bh_held() - might we be in RCU-bh read-side critical section?
  *
  * Check for bottom half being disabled, which covers both the
  * CONFIG_PROVE_RCU and not cases.  Note that if someone uses
  * rcu_read_lock_bh(), but then later enables BH, lockdep (if enabled)
- * will show the situation.
+ * will show the situation.  This is useful for debug checks in functions
+ * that require that they be called within an RCU read-side critical
+ * section.
  *
  * Check debug_lockdep_rcu_enabled() to prevent false positives during boot.
  */
@@ -86,7 +88,7 @@ int rcu_read_lock_bh_held(void)
 {
        if (!debug_lockdep_rcu_enabled())
                return 1;
-       return in_softirq();
+       return in_softirq() || irqs_disabled();
 }
 EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held);
 
index 196ec02f8be0c1ad884b7d69599005a6fc3a4429..d806735342acb10bc3e3ae787e62ade34f1d5955 100644 (file)
@@ -59,6 +59,14 @@ int rcu_scheduler_active __read_mostly;
 EXPORT_SYMBOL_GPL(rcu_scheduler_active);
 #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
 
+/* Forward declarations for rcutiny_plugin.h. */
+static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp);
+static void __call_rcu(struct rcu_head *head,
+                      void (*func)(struct rcu_head *rcu),
+                      struct rcu_ctrlblk *rcp);
+
+#include "rcutiny_plugin.h"
+
 #ifdef CONFIG_NO_HZ
 
 static long rcu_dynticks_nesting = 1;
@@ -140,6 +148,7 @@ void rcu_check_callbacks(int cpu, int user)
                rcu_sched_qs(cpu);
        else if (!in_softirq())
                rcu_bh_qs(cpu);
+       rcu_preempt_check_callbacks();
 }
 
 /*
@@ -162,6 +171,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp)
        *rcp->donetail = NULL;
        if (rcp->curtail == rcp->donetail)
                rcp->curtail = &rcp->rcucblist;
+       rcu_preempt_remove_callbacks(rcp);
        rcp->donetail = &rcp->rcucblist;
        local_irq_restore(flags);
 
@@ -182,6 +192,7 @@ static void rcu_process_callbacks(struct softirq_action *unused)
 {
        __rcu_process_callbacks(&rcu_sched_ctrlblk);
        __rcu_process_callbacks(&rcu_bh_ctrlblk);
+       rcu_preempt_process_callbacks();
 }
 
 /*
@@ -223,15 +234,15 @@ static void __call_rcu(struct rcu_head *head,
 }
 
 /*
- * Post an RCU callback to be invoked after the end of an RCU grace
+ * Post an RCU callback to be invoked after the end of an RCU-sched grace
  * period.  But since we have but one CPU, that would be after any
  * quiescent state.
  */
-void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
+void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
 {
        __call_rcu(head, func, &rcu_sched_ctrlblk);
 }
-EXPORT_SYMBOL_GPL(call_rcu);
+EXPORT_SYMBOL_GPL(call_rcu_sched);
 
 /*
  * Post an RCU bottom-half callback to be invoked after any subsequent
@@ -243,20 +254,6 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
 }
 EXPORT_SYMBOL_GPL(call_rcu_bh);
 
-void rcu_barrier(void)
-{
-       struct rcu_synchronize rcu;
-
-       init_rcu_head_on_stack(&rcu.head);
-       init_completion(&rcu.completion);
-       /* Will wake me after RCU finished. */
-       call_rcu(&rcu.head, wakeme_after_rcu);
-       /* Wait for it. */
-       wait_for_completion(&rcu.completion);
-       destroy_rcu_head_on_stack(&rcu.head);
-}
-EXPORT_SYMBOL_GPL(rcu_barrier);
-
 void rcu_barrier_bh(void)
 {
        struct rcu_synchronize rcu;
@@ -289,5 +286,3 @@ void __init rcu_init(void)
 {
        open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
 }
-
-#include "rcutiny_plugin.h"
index d223a92bc7427ffd098f8c49d524974eb12902fe..6ceca4f745ffa1f4535c69467ea59704e2ddbe97 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Read-Copy Update mechanism for mutual exclusion (tree-based version)
+ * Read-Copy Update mechanism for mutual exclusion, the Bloatwatch edition
  * Internal non-public definitions that provide either classic
- * or preemptable semantics.
+ * or preemptible semantics.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * Copyright IBM Corporation, 2009
+ * Copyright (c) 2010 Linaro
  *
  * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
  */
 
+#ifdef CONFIG_TINY_PREEMPT_RCU
+
+#include <linux/delay.h>
+
+/* Global control variables for preemptible RCU. */
+struct rcu_preempt_ctrlblk {
+       struct rcu_ctrlblk rcb; /* curtail: ->next ptr of last CB for GP. */
+       struct rcu_head **nexttail;
+                               /* Tasks blocked in a preemptible RCU */
+                               /*  read-side critical section while an */
+                               /*  preemptible-RCU grace period is in */
+                               /*  progress must wait for a later grace */
+                               /*  period.  This pointer points to the */
+                               /*  ->next pointer of the last task that */
+                               /*  must wait for a later grace period, or */
+                               /*  to &->rcb.rcucblist if there is no */
+                               /*  such task. */
+       struct list_head blkd_tasks;
+                               /* Tasks blocked in RCU read-side critical */
+                               /*  section.  Tasks are placed at the head */
+                               /*  of this list and age towards the tail. */
+       struct list_head *gp_tasks;
+                               /* Pointer to the first task blocking the */
+                               /*  current grace period, or NULL if there */
+                               /*  is not such task. */
+       struct list_head *exp_tasks;
+                               /* Pointer to first task blocking the */
+                               /*  current expedited grace period, or NULL */
+                               /*  if there is no such task.  If there */
+                               /*  is no current expedited grace period, */
+                               /*  then there cannot be any such task. */
+       u8 gpnum;               /* Current grace period. */
+       u8 gpcpu;               /* Last grace period blocked by the CPU. */
+       u8 completed;           /* Last grace period completed. */
+                               /*  If all three are equal, RCU is idle. */
+};
+
+static struct rcu_preempt_ctrlblk rcu_preempt_ctrlblk = {
+       .rcb.donetail = &rcu_preempt_ctrlblk.rcb.rcucblist,
+       .rcb.curtail = &rcu_preempt_ctrlblk.rcb.rcucblist,
+       .nexttail = &rcu_preempt_ctrlblk.rcb.rcucblist,
+       .blkd_tasks = LIST_HEAD_INIT(rcu_preempt_ctrlblk.blkd_tasks),
+};
+
+static int rcu_preempted_readers_exp(void);
+static void rcu_report_exp_done(void);
+
+/*
+ * Return true if the CPU has not yet responded to the current grace period.
+ */
+static int rcu_cpu_blocking_cur_gp(void)
+{
+       return rcu_preempt_ctrlblk.gpcpu != rcu_preempt_ctrlblk.gpnum;
+}
+
+/*
+ * Check for a running RCU reader.  Because there is only one CPU,
+ * there can be but one running RCU reader at a time.  ;-)
+ */
+static int rcu_preempt_running_reader(void)
+{
+       return current->rcu_read_lock_nesting;
+}
+
+/*
+ * Check for preempted RCU readers blocking any grace period.
+ * If the caller needs a reliable answer, it must disable hard irqs.
+ */
+static int rcu_preempt_blocked_readers_any(void)
+{
+       return !list_empty(&rcu_preempt_ctrlblk.blkd_tasks);
+}
+
+/*
+ * Check for preempted RCU readers blocking the current grace period.
+ * If the caller needs a reliable answer, it must disable hard irqs.
+ */
+static int rcu_preempt_blocked_readers_cgp(void)
+{
+       return rcu_preempt_ctrlblk.gp_tasks != NULL;
+}
+
+/*
+ * Return true if another preemptible-RCU grace period is needed.
+ */
+static int rcu_preempt_needs_another_gp(void)
+{
+       return *rcu_preempt_ctrlblk.rcb.curtail != NULL;
+}
+
+/*
+ * Return true if a preemptible-RCU grace period is in progress.
+ * The caller must disable hardirqs.
+ */
+static int rcu_preempt_gp_in_progress(void)
+{
+       return rcu_preempt_ctrlblk.completed != rcu_preempt_ctrlblk.gpnum;
+}
+
+/*
+ * Record a preemptible-RCU quiescent state for the specified CPU.  Note
+ * that this just means that the task currently running on the CPU is
+ * in a quiescent state.  There might be any number of tasks blocked
+ * while in an RCU read-side critical section.
+ *
+ * Unlike the other rcu_*_qs() functions, callers to this function
+ * must disable irqs in order to protect the assignment to
+ * ->rcu_read_unlock_special.
+ *
+ * Because this is a single-CPU implementation, the only way a grace
+ * period can end is if the CPU is in a quiescent state.  The reason is
+ * that a blocked preemptible-RCU reader can exit its critical section
+ * only if the CPU is running it at the time.  Therefore, when the
+ * last task blocking the current grace period exits its RCU read-side
+ * critical section, neither the CPU nor blocked tasks will be stopping
+ * the current grace period.  (In contrast, SMP implementations
+ * might have CPUs running in RCU read-side critical sections that
+ * block later grace periods -- but this is not possible given only
+ * one CPU.)
+ */
+static void rcu_preempt_cpu_qs(void)
+{
+       /* Record both CPU and task as having responded to current GP. */
+       rcu_preempt_ctrlblk.gpcpu = rcu_preempt_ctrlblk.gpnum;
+       current->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_NEED_QS;
+
+       /*
+        * If there is no GP, or if blocked readers are still blocking GP,
+        * then there is nothing more to do.
+        */
+       if (!rcu_preempt_gp_in_progress() || rcu_preempt_blocked_readers_cgp())
+               return;
+
+       /* Advance callbacks. */
+       rcu_preempt_ctrlblk.completed = rcu_preempt_ctrlblk.gpnum;
+       rcu_preempt_ctrlblk.rcb.donetail = rcu_preempt_ctrlblk.rcb.curtail;
+       rcu_preempt_ctrlblk.rcb.curtail = rcu_preempt_ctrlblk.nexttail;
+
+       /* If there are no blocked readers, next GP is done instantly. */
+       if (!rcu_preempt_blocked_readers_any())
+               rcu_preempt_ctrlblk.rcb.donetail = rcu_preempt_ctrlblk.nexttail;
+
+       /* If there are done callbacks, make RCU_SOFTIRQ process them. */
+       if (*rcu_preempt_ctrlblk.rcb.donetail != NULL)
+               raise_softirq(RCU_SOFTIRQ);
+}
+
+/*
+ * Start a new RCU grace period if warranted.  Hard irqs must be disabled.
+ */
+static void rcu_preempt_start_gp(void)
+{
+       if (!rcu_preempt_gp_in_progress() && rcu_preempt_needs_another_gp()) {
+
+               /* Official start of GP. */
+               rcu_preempt_ctrlblk.gpnum++;
+
+               /* Any blocked RCU readers block new GP. */
+               if (rcu_preempt_blocked_readers_any())
+                       rcu_preempt_ctrlblk.gp_tasks =
+                               rcu_preempt_ctrlblk.blkd_tasks.next;
+
+               /* If there is no running reader, CPU is done with GP. */
+               if (!rcu_preempt_running_reader())
+                       rcu_preempt_cpu_qs();
+       }
+}
+
+/*
+ * We have entered the scheduler, and the current task might soon be
+ * context-switched away from.  If this task is in an RCU read-side
+ * critical section, we will no longer be able to rely on the CPU to
+ * record that fact, so we enqueue the task on the blkd_tasks list.
+ * If the task started after the current grace period began, as recorded
+ * by ->gpcpu, we enqueue at the beginning of the list.  Otherwise
+ * before the element referenced by ->gp_tasks (or at the tail if
+ * ->gp_tasks is NULL) and point ->gp_tasks at the newly added element.
+ * The task will dequeue itself when it exits the outermost enclosing
+ * RCU read-side critical section.  Therefore, the current grace period
+ * cannot be permitted to complete until the ->gp_tasks pointer becomes
+ * NULL.
+ *
+ * Caller must disable preemption.
+ */
+void rcu_preempt_note_context_switch(void)
+{
+       struct task_struct *t = current;
+       unsigned long flags;
+
+       local_irq_save(flags); /* must exclude scheduler_tick(). */
+       if (rcu_preempt_running_reader() &&
+           (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) {
+
+               /* Possibly blocking in an RCU read-side critical section. */
+               t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED;
+
+               /*
+                * If this CPU has already checked in, then this task
+                * will hold up the next grace period rather than the
+                * current grace period.  Queue the task accordingly.
+                * If the task is queued for the current grace period
+                * (i.e., this CPU has not yet passed through a quiescent
+                * state for the current grace period), then as long
+                * as that task remains queued, the current grace period
+                * cannot end.
+                */
+               list_add(&t->rcu_node_entry, &rcu_preempt_ctrlblk.blkd_tasks);
+               if (rcu_cpu_blocking_cur_gp())
+                       rcu_preempt_ctrlblk.gp_tasks = &t->rcu_node_entry;
+       }
+
+       /*
+        * Either we were not in an RCU read-side critical section to
+        * begin with, or we have now recorded that critical section
+        * globally.  Either way, we can now note a quiescent state
+        * for this CPU.  Again, if we were in an RCU read-side critical
+        * section, and if that critical section was blocking the current
+        * grace period, then the fact that the task has been enqueued
+        * means that current grace period continues to be blocked.
+        */
+       rcu_preempt_cpu_qs();
+       local_irq_restore(flags);
+}
+
+/*
+ * Tiny-preemptible RCU implementation for rcu_read_lock().
+ * Just increment ->rcu_read_lock_nesting, shared state will be updated
+ * if we block.
+ */
+void __rcu_read_lock(void)
+{
+       current->rcu_read_lock_nesting++;
+       barrier();  /* needed if we ever invoke rcu_read_lock in rcutiny.c */
+}
+EXPORT_SYMBOL_GPL(__rcu_read_lock);
+
+/*
+ * Handle special cases during rcu_read_unlock(), such as needing to
+ * notify RCU core processing or task having blocked during the RCU
+ * read-side critical section.
+ */
+static void rcu_read_unlock_special(struct task_struct *t)
+{
+       int empty;
+       int empty_exp;
+       unsigned long flags;
+       struct list_head *np;
+       int special;
+
+       /*
+        * NMI handlers cannot block and cannot safely manipulate state.
+        * They therefore cannot possibly be special, so just leave.
+        */
+       if (in_nmi())
+               return;
+
+       local_irq_save(flags);
+
+       /*
+        * If RCU core is waiting for this CPU to exit critical section,
+        * let it know that we have done so.
+        */
+       special = t->rcu_read_unlock_special;
+       if (special & RCU_READ_UNLOCK_NEED_QS)
+               rcu_preempt_cpu_qs();
+
+       /* Hardware IRQ handlers cannot block. */
+       if (in_irq()) {
+               local_irq_restore(flags);
+               return;
+       }
+
+       /* Clean up if blocked during RCU read-side critical section. */
+       if (special & RCU_READ_UNLOCK_BLOCKED) {
+               t->rcu_read_unlock_special &= ~RCU_READ_UNLOCK_BLOCKED;
+
+               /*
+                * Remove this task from the ->blkd_tasks list and adjust
+                * any pointers that might have been referencing it.
+                */
+               empty = !rcu_preempt_blocked_readers_cgp();
+               empty_exp = rcu_preempt_ctrlblk.exp_tasks == NULL;
+               np = t->rcu_node_entry.next;
+               if (np == &rcu_preempt_ctrlblk.blkd_tasks)
+                       np = NULL;
+               list_del(&t->rcu_node_entry);
+               if (&t->rcu_node_entry == rcu_preempt_ctrlblk.gp_tasks)
+                       rcu_preempt_ctrlblk.gp_tasks = np;
+               if (&t->rcu_node_entry == rcu_preempt_ctrlblk.exp_tasks)
+                       rcu_preempt_ctrlblk.exp_tasks = np;
+               INIT_LIST_HEAD(&t->rcu_node_entry);
+
+               /*
+                * If this was the last task on the current list, and if
+                * we aren't waiting on the CPU, report the quiescent state
+                * and start a new grace period if needed.
+                */
+               if (!empty && !rcu_preempt_blocked_readers_cgp()) {
+                       rcu_preempt_cpu_qs();
+                       rcu_preempt_start_gp();
+               }
+
+               /*
+                * If this was the last task on the expedited lists,
+                * then we need wake up the waiting task.
+                */
+               if (!empty_exp && rcu_preempt_ctrlblk.exp_tasks == NULL)
+                       rcu_report_exp_done();
+       }
+       local_irq_restore(flags);
+}
+
+/*
+ * Tiny-preemptible RCU implementation for rcu_read_unlock().
+ * Decrement ->rcu_read_lock_nesting.  If the result is zero (outermost
+ * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then
+ * invoke rcu_read_unlock_special() to clean up after a context switch
+ * in an RCU read-side critical section and other special cases.
+ */
+void __rcu_read_unlock(void)
+{
+       struct task_struct *t = current;
+
+       barrier();  /* needed if we ever invoke rcu_read_unlock in rcutiny.c */
+       --t->rcu_read_lock_nesting;
+       barrier();  /* decrement before load of ->rcu_read_unlock_special */
+       if (t->rcu_read_lock_nesting == 0 &&
+           unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
+               rcu_read_unlock_special(t);
+#ifdef CONFIG_PROVE_LOCKING
+       WARN_ON_ONCE(t->rcu_read_lock_nesting < 0);
+#endif /* #ifdef CONFIG_PROVE_LOCKING */
+}
+EXPORT_SYMBOL_GPL(__rcu_read_unlock);
+
+/*
+ * Check for a quiescent state from the current CPU.  When a task blocks,
+ * the task is recorded in the rcu_preempt_ctrlblk structure, which is
+ * checked elsewhere.  This is called from the scheduling-clock interrupt.
+ *
+ * Caller must disable hard irqs.
+ */
+static void rcu_preempt_check_callbacks(void)
+{
+       struct task_struct *t = current;
+
+       if (rcu_preempt_gp_in_progress() &&
+           (!rcu_preempt_running_reader() ||
+            !rcu_cpu_blocking_cur_gp()))
+               rcu_preempt_cpu_qs();
+       if (&rcu_preempt_ctrlblk.rcb.rcucblist !=
+           rcu_preempt_ctrlblk.rcb.donetail)
+               raise_softirq(RCU_SOFTIRQ);
+       if (rcu_preempt_gp_in_progress() &&
+           rcu_cpu_blocking_cur_gp() &&
+           rcu_preempt_running_reader())
+               t->rcu_read_unlock_special |= RCU_READ_UNLOCK_NEED_QS;
+}
+
+/*
+ * TINY_PREEMPT_RCU has an extra callback-list tail pointer to
+ * update, so this is invoked from __rcu_process_callbacks() to
+ * handle that case.  Of course, it is invoked for all flavors of
+ * RCU, but RCU callbacks can appear only on one of the lists, and
+ * neither ->nexttail nor ->donetail can possibly be NULL, so there
+ * is no need for an explicit check.
+ */
+static void rcu_preempt_remove_callbacks(struct rcu_ctrlblk *rcp)
+{
+       if (rcu_preempt_ctrlblk.nexttail == rcp->donetail)
+               rcu_preempt_ctrlblk.nexttail = &rcp->rcucblist;
+}
+
+/*
+ * Process callbacks for preemptible RCU.
+ */
+static void rcu_preempt_process_callbacks(void)
+{
+       __rcu_process_callbacks(&rcu_preempt_ctrlblk.rcb);
+}
+
+/*
+ * Queue a preemptible -RCU callback for invocation after a grace period.
+ */
+void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
+{
+       unsigned long flags;
+
+       debug_rcu_head_queue(head);
+       head->func = func;
+       head->next = NULL;
+
+       local_irq_save(flags);
+       *rcu_preempt_ctrlblk.nexttail = head;
+       rcu_preempt_ctrlblk.nexttail = &head->next;
+       rcu_preempt_start_gp();  /* checks to see if GP needed. */
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(call_rcu);
+
+void rcu_barrier(void)
+{
+       struct rcu_synchronize rcu;
+
+       init_rcu_head_on_stack(&rcu.head);
+       init_completion(&rcu.completion);
+       /* Will wake me after RCU finished. */
+       call_rcu(&rcu.head, wakeme_after_rcu);
+       /* Wait for it. */
+       wait_for_completion(&rcu.completion);
+       destroy_rcu_head_on_stack(&rcu.head);
+}
+EXPORT_SYMBOL_GPL(rcu_barrier);
+
+/*
+ * synchronize_rcu - wait until a grace period has elapsed.
+ *
+ * Control will return to the caller some time after a full grace
+ * period has elapsed, in other words after all currently executing RCU
+ * read-side critical sections have completed.  RCU read-side critical
+ * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
+ * and may be nested.
+ */
+void synchronize_rcu(void)
+{
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       if (!rcu_scheduler_active)
+               return;
+#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
+
+       WARN_ON_ONCE(rcu_preempt_running_reader());
+       if (!rcu_preempt_blocked_readers_any())
+               return;
+
+       /* Once we get past the fastpath checks, same code as rcu_barrier(). */
+       rcu_barrier();
+}
+EXPORT_SYMBOL_GPL(synchronize_rcu);
+
+static DECLARE_WAIT_QUEUE_HEAD(sync_rcu_preempt_exp_wq);
+static unsigned long sync_rcu_preempt_exp_count;
+static DEFINE_MUTEX(sync_rcu_preempt_exp_mutex);
+
+/*
+ * Return non-zero if there are any tasks in RCU read-side critical
+ * sections blocking the current preemptible-RCU expedited grace period.
+ * If there is no preemptible-RCU expedited grace period currently in
+ * progress, returns zero unconditionally.
+ */
+static int rcu_preempted_readers_exp(void)
+{
+       return rcu_preempt_ctrlblk.exp_tasks != NULL;
+}
+
+/*
+ * Report the exit from RCU read-side critical section for the last task
+ * that queued itself during or before the current expedited preemptible-RCU
+ * grace period.
+ */
+static void rcu_report_exp_done(void)
+{
+       wake_up(&sync_rcu_preempt_exp_wq);
+}
+
+/*
+ * Wait for an rcu-preempt grace period, but expedite it.  The basic idea
+ * is to rely in the fact that there is but one CPU, and that it is
+ * illegal for a task to invoke synchronize_rcu_expedited() while in a
+ * preemptible-RCU read-side critical section.  Therefore, any such
+ * critical sections must correspond to blocked tasks, which must therefore
+ * be on the ->blkd_tasks list.  So just record the current head of the
+ * list in the ->exp_tasks pointer, and wait for all tasks including and
+ * after the task pointed to by ->exp_tasks to drain.
+ */
+void synchronize_rcu_expedited(void)
+{
+       unsigned long flags;
+       struct rcu_preempt_ctrlblk *rpcp = &rcu_preempt_ctrlblk;
+       unsigned long snap;
+
+       barrier(); /* ensure prior action seen before grace period. */
+
+       WARN_ON_ONCE(rcu_preempt_running_reader());
+
+       /*
+        * Acquire lock so that there is only one preemptible RCU grace
+        * period in flight.  Of course, if someone does the expedited
+        * grace period for us while we are acquiring the lock, just leave.
+        */
+       snap = sync_rcu_preempt_exp_count + 1;
+       mutex_lock(&sync_rcu_preempt_exp_mutex);
+       if (ULONG_CMP_LT(snap, sync_rcu_preempt_exp_count))
+               goto unlock_mb_ret; /* Others did our work for us. */
+
+       local_irq_save(flags);
+
+       /*
+        * All RCU readers have to already be on blkd_tasks because
+        * we cannot legally be executing in an RCU read-side critical
+        * section.
+        */
+
+       /* Snapshot current head of ->blkd_tasks list. */
+       rpcp->exp_tasks = rpcp->blkd_tasks.next;
+       if (rpcp->exp_tasks == &rpcp->blkd_tasks)
+               rpcp->exp_tasks = NULL;
+       local_irq_restore(flags);
+
+       /* Wait for tail of ->blkd_tasks list to drain. */
+       if (rcu_preempted_readers_exp())
+               wait_event(sync_rcu_preempt_exp_wq,
+                          !rcu_preempted_readers_exp());
+
+       /* Clean up and exit. */
+       barrier(); /* ensure expedited GP seen before counter increment. */
+       sync_rcu_preempt_exp_count++;
+unlock_mb_ret:
+       mutex_unlock(&sync_rcu_preempt_exp_mutex);
+       barrier(); /* ensure subsequent action seen after grace period. */
+}
+EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
+
+/*
+ * Does preemptible RCU need the CPU to stay out of dynticks mode?
+ */
+int rcu_preempt_needs_cpu(void)
+{
+       if (!rcu_preempt_running_reader())
+               rcu_preempt_cpu_qs();
+       return rcu_preempt_ctrlblk.rcb.rcucblist != NULL;
+}
+
+/*
+ * Check for a task exiting while in a preemptible -RCU read-side
+ * critical section, clean up if so.  No need to issue warnings,
+ * as debug_check_no_locks_held() already does this if lockdep
+ * is enabled.
+ */
+void exit_rcu(void)
+{
+       struct task_struct *t = current;
+
+       if (t->rcu_read_lock_nesting == 0)
+               return;
+       t->rcu_read_lock_nesting = 1;
+       rcu_read_unlock();
+}
+
+#else /* #ifdef CONFIG_TINY_PREEMPT_RCU */
+
+/*
+ * Because preemptible RCU does not exist, it never has any callbacks
+ * to check.
+ */
+static void rcu_preempt_check_callbacks(void)
+{
+}
+
+/*
+ * Because preemptible RCU does not exist, it never has any callbacks
+ * to remove.
+ */
+static void rcu_preempt_remove_callbacks(struct rcu_ctrlblk *rcp)
+{
+}
+
+/*
+ * Because preemptible RCU does not exist, it never has any callbacks
+ * to process.
+ */
+static void rcu_preempt_process_callbacks(void)
+{
+}
+
+#endif /* #else #ifdef CONFIG_TINY_PREEMPT_RCU */
+
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
 #include <linux/kernel_stat.h>
index 2e2726d790b98eff18d88d71dbeba8caf8ec7f7a..9d8e8fb2515f4e4801c214841a7f8c95b8b45ffe 100644 (file)
@@ -120,7 +120,7 @@ struct rcu_torture {
 };
 
 static LIST_HEAD(rcu_torture_freelist);
-static struct rcu_torture *rcu_torture_current;
+static struct rcu_torture __rcu *rcu_torture_current;
 static long rcu_torture_current_version;
 static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
 static DEFINE_SPINLOCK(rcu_torture_lock);
@@ -153,8 +153,10 @@ int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
 #define FULLSTOP_SHUTDOWN 1    /* System shutdown with rcutorture running. */
 #define FULLSTOP_RMMOD    2    /* Normal rmmod of rcutorture. */
 static int fullstop = FULLSTOP_RMMOD;
-DEFINE_MUTEX(fullstop_mutex);  /* Protect fullstop transitions and spawning */
-                               /*  of kthreads. */
+/*
+ * Protect fullstop transitions and spawning of kthreads.
+ */
+static DEFINE_MUTEX(fullstop_mutex);
 
 /*
  * Detect and respond to a system shutdown.
@@ -303,6 +305,10 @@ static void rcu_read_delay(struct rcu_random_state *rrsp)
                mdelay(longdelay_ms);
        if (!(rcu_random(rrsp) % (nrealreaders * 2 * shortdelay_us)))
                udelay(shortdelay_us);
+#ifdef CONFIG_PREEMPT
+       if (!preempt_count() && !(rcu_random(rrsp) % (nrealreaders * 20000)))
+               preempt_schedule();  /* No QS if preempt_disable() in effect */
+#endif
 }
 
 static void rcu_torture_read_unlock(int idx) __releases(RCU)
@@ -536,6 +542,8 @@ static void srcu_read_delay(struct rcu_random_state *rrsp)
        delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick);
        if (!delay)
                schedule_timeout_interruptible(longdelay);
+       else
+               rcu_read_delay(rrsp);
 }
 
 static void srcu_torture_read_unlock(int idx) __releases(&srcu_ctl)
@@ -731,7 +739,8 @@ rcu_torture_writer(void *arg)
                        continue;
                rp->rtort_pipe_count = 0;
                udelay(rcu_random(&rand) & 0x3ff);
-               old_rp = rcu_torture_current;
+               old_rp = rcu_dereference_check(rcu_torture_current,
+                                              current == writer_task);
                rp->rtort_mbtest = 1;
                rcu_assign_pointer(rcu_torture_current, rp);
                smp_wmb(); /* Mods to old_rp must follow rcu_assign_pointer() */
index d5bc43976c5ad202fa41be0456797d40bdde0c0d..ccdc04c479815addc8dbacea69643174a4636670 100644 (file)
@@ -143,6 +143,11 @@ module_param(blimit, int, 0);
 module_param(qhimark, int, 0);
 module_param(qlowmark, int, 0);
 
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
+int rcu_cpu_stall_suppress __read_mostly = RCU_CPU_STALL_SUPPRESS_INIT;
+module_param(rcu_cpu_stall_suppress, int, 0644);
+#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
+
 static void force_quiescent_state(struct rcu_state *rsp, int relaxed);
 static int rcu_pending(int cpu);
 
@@ -450,7 +455,7 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
 
 #ifdef CONFIG_RCU_CPU_STALL_DETECTOR
 
-int rcu_cpu_stall_panicking __read_mostly;
+int rcu_cpu_stall_suppress __read_mostly;
 
 static void record_gp_stall_check_time(struct rcu_state *rsp)
 {
@@ -482,8 +487,11 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
        rcu_print_task_stall(rnp);
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
-       /* OK, time to rat on our buddy... */
-
+       /*
+        * OK, time to rat on our buddy...
+        * See Documentation/RCU/stallwarn.txt for info on how to debug
+        * RCU CPU stall warnings.
+        */
        printk(KERN_ERR "INFO: %s detected stalls on CPUs/tasks: {",
               rsp->name);
        rcu_for_each_leaf_node(rsp, rnp) {
@@ -512,6 +520,11 @@ static void print_cpu_stall(struct rcu_state *rsp)
        unsigned long flags;
        struct rcu_node *rnp = rcu_get_root(rsp);
 
+       /*
+        * OK, time to rat on ourselves...
+        * See Documentation/RCU/stallwarn.txt for info on how to debug
+        * RCU CPU stall warnings.
+        */
        printk(KERN_ERR "INFO: %s detected stall on CPU %d (t=%lu jiffies)\n",
               rsp->name, smp_processor_id(), jiffies - rsp->gp_start);
        trigger_all_cpu_backtrace();
@@ -530,11 +543,11 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
        long delta;
        struct rcu_node *rnp;
 
-       if (rcu_cpu_stall_panicking)
+       if (rcu_cpu_stall_suppress)
                return;
-       delta = jiffies - rsp->jiffies_stall;
+       delta = jiffies - ACCESS_ONCE(rsp->jiffies_stall);
        rnp = rdp->mynode;
-       if ((rnp->qsmask & rdp->grpmask) && delta >= 0) {
+       if ((ACCESS_ONCE(rnp->qsmask) & rdp->grpmask) && delta >= 0) {
 
                /* We haven't checked in, so go dump stack. */
                print_cpu_stall(rsp);
@@ -548,10 +561,26 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
 
 static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr)
 {
-       rcu_cpu_stall_panicking = 1;
+       rcu_cpu_stall_suppress = 1;
        return NOTIFY_DONE;
 }
 
+/**
+ * rcu_cpu_stall_reset - prevent further stall warnings in current grace period
+ *
+ * Set the stall-warning timeout way off into the future, thus preventing
+ * any RCU CPU stall-warning messages from appearing in the current set of
+ * RCU grace periods.
+ *
+ * The caller must disable hard irqs.
+ */
+void rcu_cpu_stall_reset(void)
+{
+       rcu_sched_state.jiffies_stall = jiffies + ULONG_MAX / 2;
+       rcu_bh_state.jiffies_stall = jiffies + ULONG_MAX / 2;
+       rcu_preempt_stall_reset();
+}
+
 static struct notifier_block rcu_panic_block = {
        .notifier_call = rcu_panic,
 };
@@ -571,6 +600,10 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
 {
 }
 
+void rcu_cpu_stall_reset(void)
+{
+}
+
 static void __init check_cpu_stall_init(void)
 {
 }
@@ -712,7 +745,7 @@ static void
 rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
        __releases(rcu_get_root(rsp)->lock)
 {
-       struct rcu_data *rdp = rsp->rda[smp_processor_id()];
+       struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
        struct rcu_node *rnp = rcu_get_root(rsp);
 
        if (!cpu_needs_another_gp(rsp, rdp) || rsp->fqs_active) {
@@ -960,7 +993,7 @@ rcu_check_quiescent_state(struct rcu_state *rsp, struct rcu_data *rdp)
 static void rcu_send_cbs_to_orphanage(struct rcu_state *rsp)
 {
        int i;
-       struct rcu_data *rdp = rsp->rda[smp_processor_id()];
+       struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
 
        if (rdp->nxtlist == NULL)
                return;  /* irqs disabled, so comparison is stable. */
@@ -971,6 +1004,7 @@ static void rcu_send_cbs_to_orphanage(struct rcu_state *rsp)
        for (i = 0; i < RCU_NEXT_SIZE; i++)
                rdp->nxttail[i] = &rdp->nxtlist;
        rsp->orphan_qlen += rdp->qlen;
+       rdp->n_cbs_orphaned += rdp->qlen;
        rdp->qlen = 0;
        raw_spin_unlock(&rsp->onofflock);  /* irqs remain disabled. */
 }
@@ -984,7 +1018,7 @@ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp)
        struct rcu_data *rdp;
 
        raw_spin_lock_irqsave(&rsp->onofflock, flags);
-       rdp = rsp->rda[smp_processor_id()];
+       rdp = this_cpu_ptr(rsp->rda);
        if (rsp->orphan_cbs_list == NULL) {
                raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
                return;
@@ -992,6 +1026,7 @@ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp)
        *rdp->nxttail[RCU_NEXT_TAIL] = rsp->orphan_cbs_list;
        rdp->nxttail[RCU_NEXT_TAIL] = rsp->orphan_cbs_tail;
        rdp->qlen += rsp->orphan_qlen;
+       rdp->n_cbs_adopted += rsp->orphan_qlen;
        rsp->orphan_cbs_list = NULL;
        rsp->orphan_cbs_tail = &rsp->orphan_cbs_list;
        rsp->orphan_qlen = 0;
@@ -1007,7 +1042,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
        unsigned long flags;
        unsigned long mask;
        int need_report = 0;
-       struct rcu_data *rdp = rsp->rda[cpu];
+       struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
        struct rcu_node *rnp;
 
        /* Exclude any attempts to start a new grace period. */
@@ -1123,6 +1158,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
 
        /* Update count, and requeue any remaining callbacks. */
        rdp->qlen -= count;
+       rdp->n_cbs_invoked += count;
        if (list != NULL) {
                *tail = rdp->nxtlist;
                rdp->nxtlist = list;
@@ -1226,7 +1262,8 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
                cpu = rnp->grplo;
                bit = 1;
                for (; cpu <= rnp->grphi; cpu++, bit <<= 1) {
-                       if ((rnp->qsmask & bit) != 0 && f(rsp->rda[cpu]))
+                       if ((rnp->qsmask & bit) != 0 &&
+                           f(per_cpu_ptr(rsp->rda, cpu)))
                                mask |= bit;
                }
                if (mask != 0) {
@@ -1402,7 +1439,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
         * a quiescent state betweentimes.
         */
        local_irq_save(flags);
-       rdp = rsp->rda[smp_processor_id()];
+       rdp = this_cpu_ptr(rsp->rda);
        rcu_process_gp_end(rsp, rdp);
        check_for_new_grace_period(rsp, rdp);
 
@@ -1701,7 +1738,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
 {
        unsigned long flags;
        int i;
-       struct rcu_data *rdp = rsp->rda[cpu];
+       struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
        struct rcu_node *rnp = rcu_get_root(rsp);
 
        /* Set up local state, ensuring consistent view of global state. */
@@ -1729,7 +1766,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptable)
 {
        unsigned long flags;
        unsigned long mask;
-       struct rcu_data *rdp = rsp->rda[cpu];
+       struct rcu_data *rdp = per_cpu_ptr(rsp->rda, cpu);
        struct rcu_node *rnp = rcu_get_root(rsp);
 
        /* Set up local state, ensuring consistent view of global state. */
@@ -1865,7 +1902,8 @@ static void __init rcu_init_levelspread(struct rcu_state *rsp)
 /*
  * Helper function for rcu_init() that initializes one rcu_state structure.
  */
-static void __init rcu_init_one(struct rcu_state *rsp)
+static void __init rcu_init_one(struct rcu_state *rsp,
+               struct rcu_data __percpu *rda)
 {
        static char *buf[] = { "rcu_node_level_0",
                               "rcu_node_level_1",
@@ -1918,37 +1956,23 @@ static void __init rcu_init_one(struct rcu_state *rsp)
                }
        }
 
+       rsp->rda = rda;
        rnp = rsp->level[NUM_RCU_LVLS - 1];
        for_each_possible_cpu(i) {
                while (i > rnp->grphi)
                        rnp++;
-               rsp->rda[i]->mynode = rnp;
+               per_cpu_ptr(rsp->rda, i)->mynode = rnp;
                rcu_boot_init_percpu_data(i, rsp);
        }
 }
 
-/*
- * Helper macro for __rcu_init() and __rcu_init_preempt().  To be used
- * nowhere else!  Assigns leaf node pointers into each CPU's rcu_data
- * structure.
- */
-#define RCU_INIT_FLAVOR(rsp, rcu_data) \
-do { \
-       int i; \
-       \
-       for_each_possible_cpu(i) { \
-               (rsp)->rda[i] = &per_cpu(rcu_data, i); \
-       } \
-       rcu_init_one(rsp); \
-} while (0)
-
 void __init rcu_init(void)
 {
        int cpu;
 
        rcu_bootup_announce();
-       RCU_INIT_FLAVOR(&rcu_sched_state, rcu_sched_data);
-       RCU_INIT_FLAVOR(&rcu_bh_state, rcu_bh_data);
+       rcu_init_one(&rcu_sched_state, &rcu_sched_data);
+       rcu_init_one(&rcu_bh_state, &rcu_bh_data);
        __rcu_init_preempt();
        open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
 
index 14c040b18ed04a23f34448d9278d9ad55e5ab0c1..91d4170c5c13afd2e8997bd59b28e7cc2a4385e8 100644 (file)
@@ -202,6 +202,9 @@ struct rcu_data {
        long            qlen;           /* # of queued callbacks */
        long            qlen_last_fqs_check;
                                        /* qlen at last check for QS forcing */
+       unsigned long   n_cbs_invoked;  /* count of RCU cbs invoked. */
+       unsigned long   n_cbs_orphaned; /* RCU cbs sent to orphanage. */
+       unsigned long   n_cbs_adopted;  /* RCU cbs adopted from orphanage. */
        unsigned long   n_force_qs_snap;
                                        /* did other CPU force QS recently? */
        long            blimit;         /* Upper limit on a processed batch */
@@ -254,19 +257,23 @@ struct rcu_data {
 #define RCU_STALL_DELAY_DELTA         0
 #endif
 
-#define RCU_SECONDS_TILL_STALL_CHECK   (10 * HZ + RCU_STALL_DELAY_DELTA)
+#define RCU_SECONDS_TILL_STALL_CHECK   (CONFIG_RCU_CPU_STALL_TIMEOUT * HZ + \
+                                       RCU_STALL_DELAY_DELTA)
                                                /* for rsp->jiffies_stall */
-#define RCU_SECONDS_TILL_STALL_RECHECK (30 * HZ + RCU_STALL_DELAY_DELTA)
+#define RCU_SECONDS_TILL_STALL_RECHECK (3 * RCU_SECONDS_TILL_STALL_CHECK + 30)
                                                /* for rsp->jiffies_stall */
 #define RCU_STALL_RAT_DELAY            2       /* Allow other CPUs time */
                                                /*  to take at least one */
                                                /*  scheduling clock irq */
                                                /*  before ratting on them. */
 
-#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR_RUNNABLE
+#define RCU_CPU_STALL_SUPPRESS_INIT 0
+#else
+#define RCU_CPU_STALL_SUPPRESS_INIT 1
+#endif
 
-#define ULONG_CMP_GE(a, b)     (ULONG_MAX / 2 >= (a) - (b))
-#define ULONG_CMP_LT(a, b)     (ULONG_MAX / 2 < (a) - (b))
+#endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 
 /*
  * RCU global state, including node hierarchy.  This hierarchy is
@@ -283,7 +290,7 @@ struct rcu_state {
        struct rcu_node *level[NUM_RCU_LVLS];   /* Hierarchy levels. */
        u32 levelcnt[MAX_RCU_LVLS + 1];         /* # nodes in each level. */
        u8 levelspread[NUM_RCU_LVLS];           /* kids/node in each level. */
-       struct rcu_data *rda[NR_CPUS];          /* array of rdp pointers. */
+       struct rcu_data __percpu *rda;          /* pointer of percu rcu_data. */
 
        /* The following fields are guarded by the root rcu_node's lock. */
 
@@ -365,6 +372,7 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp,
 #ifdef CONFIG_RCU_CPU_STALL_DETECTOR
 static void rcu_print_detail_task_stall(struct rcu_state *rsp);
 static void rcu_print_task_stall(struct rcu_node *rnp);
+static void rcu_preempt_stall_reset(void);
 #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp);
 #ifdef CONFIG_HOTPLUG_CPU
index 0e4f420245d97369b7fdf6bb99815789ffe13233..71a4147473f95f51d2b2e88db4c14372dafe375f 100644 (file)
@@ -57,7 +57,7 @@ static void __init rcu_bootup_announce_oddness(void)
        printk(KERN_INFO
               "\tRCU-based detection of stalled CPUs is disabled.\n");
 #endif
-#ifndef CONFIG_RCU_CPU_STALL_VERBOSE
+#if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE)
        printk(KERN_INFO "\tVerbose stalled-CPUs detection is disabled.\n");
 #endif
 #if NUM_RCU_LVL_4 != 0
@@ -154,7 +154,7 @@ static void rcu_preempt_note_context_switch(int cpu)
            (t->rcu_read_unlock_special & RCU_READ_UNLOCK_BLOCKED) == 0) {
 
                /* Possibly blocking in an RCU read-side critical section. */
-               rdp = rcu_preempt_state.rda[cpu];
+               rdp = per_cpu_ptr(rcu_preempt_state.rda, cpu);
                rnp = rdp->mynode;
                raw_spin_lock_irqsave(&rnp->lock, flags);
                t->rcu_read_unlock_special |= RCU_READ_UNLOCK_BLOCKED;
@@ -201,7 +201,7 @@ static void rcu_preempt_note_context_switch(int cpu)
  */
 void __rcu_read_lock(void)
 {
-       ACCESS_ONCE(current->rcu_read_lock_nesting)++;
+       current->rcu_read_lock_nesting++;
        barrier();  /* needed if we ever invoke rcu_read_lock in rcutree.c */
 }
 EXPORT_SYMBOL_GPL(__rcu_read_lock);
@@ -344,7 +344,9 @@ void __rcu_read_unlock(void)
        struct task_struct *t = current;
 
        barrier();  /* needed if we ever invoke rcu_read_unlock in rcutree.c */
-       if (--ACCESS_ONCE(t->rcu_read_lock_nesting) == 0 &&
+       --t->rcu_read_lock_nesting;
+       barrier();  /* decrement before load of ->rcu_read_unlock_special */
+       if (t->rcu_read_lock_nesting == 0 &&
            unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
                rcu_read_unlock_special(t);
 #ifdef CONFIG_PROVE_LOCKING
@@ -417,6 +419,16 @@ static void rcu_print_task_stall(struct rcu_node *rnp)
        }
 }
 
+/*
+ * Suppress preemptible RCU's CPU stall warnings by pushing the
+ * time of the next stall-warning message comfortably far into the
+ * future.
+ */
+static void rcu_preempt_stall_reset(void)
+{
+       rcu_preempt_state.jiffies_stall = jiffies + ULONG_MAX / 2;
+}
+
 #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 
 /*
@@ -546,9 +558,11 @@ EXPORT_SYMBOL_GPL(call_rcu);
  *
  * Control will return to the caller some time after a full grace
  * period has elapsed, in other words after all currently executing RCU
- * read-side critical sections have completed.  RCU read-side critical
- * sections are delimited by rcu_read_lock() and rcu_read_unlock(),
- * and may be nested.
+ * read-side critical sections have completed.  Note, however, that
+ * upon return from synchronize_rcu(), the caller might well be executing
+ * concurrently with new RCU read-side critical sections that began while
+ * synchronize_rcu() was waiting.  RCU read-side critical sections are
+ * delimited by rcu_read_lock() and rcu_read_unlock(), and may be nested.
  */
 void synchronize_rcu(void)
 {
@@ -771,7 +785,7 @@ static void rcu_preempt_send_cbs_to_orphanage(void)
  */
 static void __init __rcu_init_preempt(void)
 {
-       RCU_INIT_FLAVOR(&rcu_preempt_state, rcu_preempt_data);
+       rcu_init_one(&rcu_preempt_state, &rcu_preempt_data);
 }
 
 /*
@@ -865,6 +879,14 @@ static void rcu_print_task_stall(struct rcu_node *rnp)
 {
 }
 
+/*
+ * Because preemptible RCU does not exist, there is no need to suppress
+ * its CPU stall warnings.
+ */
+static void rcu_preempt_stall_reset(void)
+{
+}
+
 #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */
 
 /*
@@ -918,15 +940,6 @@ static void rcu_preempt_process_callbacks(void)
 {
 }
 
-/*
- * In classic RCU, call_rcu() is just call_rcu_sched().
- */
-void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
-{
-       call_rcu_sched(head, func);
-}
-EXPORT_SYMBOL_GPL(call_rcu);
-
 /*
  * Wait for an rcu-preempt grace period, but make it happen quickly.
  * But because preemptable RCU does not exist, map to rcu-sched.
index 36c95b45738ed7f74fb78b901ddcff7fc1488498..d15430b9d122f4d619e76fb6b5069aa1f494a575 100644 (file)
@@ -64,7 +64,9 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp)
                   rdp->dynticks_fqs);
 #endif /* #ifdef CONFIG_NO_HZ */
        seq_printf(m, " of=%lu ri=%lu", rdp->offline_fqs, rdp->resched_ipi);
-       seq_printf(m, " ql=%ld b=%ld\n", rdp->qlen, rdp->blimit);
+       seq_printf(m, " ql=%ld b=%ld", rdp->qlen, rdp->blimit);
+       seq_printf(m, " ci=%lu co=%lu ca=%lu\n",
+                  rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 }
 
 #define PRINT_RCU_DATA(name, func, m) \
@@ -119,7 +121,9 @@ static void print_one_rcu_data_csv(struct seq_file *m, struct rcu_data *rdp)
                   rdp->dynticks_fqs);
 #endif /* #ifdef CONFIG_NO_HZ */
        seq_printf(m, ",%lu,%lu", rdp->offline_fqs, rdp->resched_ipi);
-       seq_printf(m, ",%ld,%ld\n", rdp->qlen, rdp->blimit);
+       seq_printf(m, ",%ld,%ld", rdp->qlen, rdp->blimit);
+       seq_printf(m, ",%lu,%lu,%lu\n",
+                  rdp->n_cbs_invoked, rdp->n_cbs_orphaned, rdp->n_cbs_adopted);
 }
 
 static int show_rcudata_csv(struct seq_file *m, void *unused)
@@ -128,7 +132,7 @@ static int show_rcudata_csv(struct seq_file *m, void *unused)
 #ifdef CONFIG_NO_HZ
        seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\",");
 #endif /* #ifdef CONFIG_NO_HZ */
-       seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\"\n");
+       seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\",\"ci\",\"co\",\"ca\"\n");
 #ifdef CONFIG_TREE_PREEMPT_RCU
        seq_puts(m, "\"rcu_preempt:\"\n");
        PRINT_RCU_DATA(rcu_preempt_data, print_one_rcu_data_csv, m);
@@ -262,7 +266,7 @@ static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp)
        struct rcu_data *rdp;
 
        for_each_possible_cpu(cpu) {
-               rdp = rsp->rda[cpu];
+               rdp = per_cpu_ptr(rsp->rda, cpu);
                if (rdp->beenonline)
                        print_one_rcu_pending(m, rdp);
        }
index dc85ceb908322cad7196339f4df8dd58c37b1cec..d42992bccdfae88569559f3e88f81bbcea8e9494 100644 (file)
@@ -426,9 +426,7 @@ struct root_domain {
         */
        cpumask_var_t rto_mask;
        atomic_t rto_count;
-#ifdef CONFIG_SMP
        struct cpupri cpupri;
-#endif
 };
 
 /*
@@ -437,7 +435,7 @@ struct root_domain {
  */
 static struct root_domain def_root_domain;
 
-#endif
+#endif /* CONFIG_SMP */
 
 /*
  * This is the main, per-CPU runqueue data structure.
@@ -488,11 +486,12 @@ struct rq {
         */
        unsigned long nr_uninterruptible;
 
-       struct task_struct *curr, *idle;
+       struct task_struct *curr, *idle, *stop;
        unsigned long next_balance;
        struct mm_struct *prev_mm;
 
        u64 clock;
+       u64 clock_task;
 
        atomic_t nr_iowait;
 
@@ -520,6 +519,10 @@ struct rq {
        u64 avg_idle;
 #endif
 
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+       u64 prev_irq_time;
+#endif
+
        /* calc_load related fields */
        unsigned long calc_load_update;
        long calc_load_active;
@@ -643,10 +646,22 @@ static inline struct task_group *task_group(struct task_struct *p)
 
 #endif /* CONFIG_CGROUP_SCHED */
 
+static u64 irq_time_cpu(int cpu);
+static void sched_irq_time_avg_update(struct rq *rq, u64 irq_time);
+
 inline void update_rq_clock(struct rq *rq)
 {
-       if (!rq->skip_clock_update)
-               rq->clock = sched_clock_cpu(cpu_of(rq));
+       if (!rq->skip_clock_update) {
+               int cpu = cpu_of(rq);
+               u64 irq_time;
+
+               rq->clock = sched_clock_cpu(cpu);
+               irq_time = irq_time_cpu(cpu);
+               if (rq->clock - irq_time > rq->clock_task)
+                       rq->clock_task = rq->clock - irq_time;
+
+               sched_irq_time_avg_update(rq, irq_time);
+       }
 }
 
 /*
@@ -723,7 +738,7 @@ sched_feat_write(struct file *filp, const char __user *ubuf,
                size_t cnt, loff_t *ppos)
 {
        char buf[64];
-       char *cmp = buf;
+       char *cmp;
        int neg = 0;
        int i;
 
@@ -734,6 +749,7 @@ sched_feat_write(struct file *filp, const char __user *ubuf,
                return -EFAULT;
 
        buf[cnt] = 0;
+       cmp = strstrip(buf);
 
        if (strncmp(buf, "NO_", 3) == 0) {
                neg = 1;
@@ -741,9 +757,7 @@ sched_feat_write(struct file *filp, const char __user *ubuf,
        }
 
        for (i = 0; sched_feat_names[i]; i++) {
-               int len = strlen(sched_feat_names[i]);
-
-               if (strncmp(cmp, sched_feat_names[i], len) == 0) {
+               if (strcmp(cmp, sched_feat_names[i]) == 0) {
                        if (neg)
                                sysctl_sched_features &= ~(1UL << i);
                        else
@@ -1840,7 +1854,7 @@ static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
 
 static const struct sched_class rt_sched_class;
 
-#define sched_class_highest (&rt_sched_class)
+#define sched_class_highest (&stop_sched_class)
 #define for_each_class(class) \
    for (class = sched_class_highest; class; class = class->next)
 
@@ -1858,12 +1872,6 @@ static void dec_nr_running(struct rq *rq)
 
 static void set_load_weight(struct task_struct *p)
 {
-       if (task_has_rt_policy(p)) {
-               p->se.load.weight = 0;
-               p->se.load.inv_weight = WMULT_CONST;
-               return;
-       }
-
        /*
         * SCHED_IDLE tasks get minimal weight:
         */
@@ -1917,13 +1925,132 @@ static void deactivate_task(struct rq *rq, struct task_struct *p, int flags)
        dec_nr_running(rq);
 }
 
+#ifdef CONFIG_IRQ_TIME_ACCOUNTING
+
+/*
+ * There are no locks covering percpu hardirq/softirq time.
+ * They are only modified in account_system_vtime, on corresponding CPU
+ * with interrupts disabled. So, writes are safe.
+ * They are read and saved off onto struct rq in update_rq_clock().
+ * This may result in other CPU reading this CPU's irq time and can
+ * race with irq/account_system_vtime on this CPU. We would either get old
+ * or new value (or semi updated value on 32 bit) with a side effect of
+ * accounting a slice of irq time to wrong task when irq is in progress
+ * while we read rq->clock. That is a worthy compromise in place of having
+ * locks on each irq in account_system_time.
+ */
+static DEFINE_PER_CPU(u64, cpu_hardirq_time);
+static DEFINE_PER_CPU(u64, cpu_softirq_time);
+
+static DEFINE_PER_CPU(u64, irq_start_time);
+static int sched_clock_irqtime;
+
+void enable_sched_clock_irqtime(void)
+{
+       sched_clock_irqtime = 1;
+}
+
+void disable_sched_clock_irqtime(void)
+{
+       sched_clock_irqtime = 0;
+}
+
+static u64 irq_time_cpu(int cpu)
+{
+       if (!sched_clock_irqtime)
+               return 0;
+
+       return per_cpu(cpu_softirq_time, cpu) + per_cpu(cpu_hardirq_time, cpu);
+}
+
+void account_system_vtime(struct task_struct *curr)
+{
+       unsigned long flags;
+       int cpu;
+       u64 now, delta;
+
+       if (!sched_clock_irqtime)
+               return;
+
+       local_irq_save(flags);
+
+       cpu = smp_processor_id();
+       now = sched_clock_cpu(cpu);
+       delta = now - per_cpu(irq_start_time, cpu);
+       per_cpu(irq_start_time, cpu) = now;
+       /*
+        * We do not account for softirq time from ksoftirqd here.
+        * We want to continue accounting softirq time to ksoftirqd thread
+        * in that case, so as not to confuse scheduler with a special task
+        * that do not consume any time, but still wants to run.
+        */
+       if (hardirq_count())
+               per_cpu(cpu_hardirq_time, cpu) += delta;
+       else if (in_serving_softirq() && !(curr->flags & PF_KSOFTIRQD))
+               per_cpu(cpu_softirq_time, cpu) += delta;
+
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(account_system_vtime);
+
+static void sched_irq_time_avg_update(struct rq *rq, u64 curr_irq_time)
+{
+       if (sched_clock_irqtime && sched_feat(NONIRQ_POWER)) {
+               u64 delta_irq = curr_irq_time - rq->prev_irq_time;
+               rq->prev_irq_time = curr_irq_time;
+               sched_rt_avg_update(rq, delta_irq);
+       }
+}
+
+#else
+
+static u64 irq_time_cpu(int cpu)
+{
+       return 0;
+}
+
+static void sched_irq_time_avg_update(struct rq *rq, u64 curr_irq_time) { }
+
+#endif
+
 #include "sched_idletask.c"
 #include "sched_fair.c"
 #include "sched_rt.c"
+#include "sched_stoptask.c"
 #ifdef CONFIG_SCHED_DEBUG
 # include "sched_debug.c"
 #endif
 
+void sched_set_stop_task(int cpu, struct task_struct *stop)
+{
+       struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
+       struct task_struct *old_stop = cpu_rq(cpu)->stop;
+
+       if (stop) {
+               /*
+                * Make it appear like a SCHED_FIFO task, its something
+                * userspace knows about and won't get confused about.
+                *
+                * Also, it will make PI more or less work without too
+                * much confusion -- but then, stop work should not
+                * rely on PI working anyway.
+                */
+               sched_setscheduler_nocheck(stop, SCHED_FIFO, &param);
+
+               stop->sched_class = &stop_sched_class;
+       }
+
+       cpu_rq(cpu)->stop = stop;
+
+       if (old_stop) {
+               /*
+                * Reset it back to a normal scheduling class so that
+                * it can die in pieces.
+                */
+               old_stop->sched_class = &rt_sched_class;
+       }
+}
+
 /*
  * __normal_prio - return the priority that is based on the static prio
  */
@@ -2003,6 +2130,9 @@ task_hot(struct task_struct *p, u64 now, struct sched_domain *sd)
        if (p->sched_class != &fair_sched_class)
                return 0;
 
+       if (unlikely(p->policy == SCHED_IDLE))
+               return 0;
+
        /*
         * Buddy candidates are cache hot:
         */
@@ -2852,14 +2982,14 @@ context_switch(struct rq *rq, struct task_struct *prev,
         */
        arch_start_context_switch(prev);
 
-       if (likely(!mm)) {
+       if (!mm) {
                next->active_mm = oldmm;
                atomic_inc(&oldmm->mm_count);
                enter_lazy_tlb(oldmm, next);
        } else
                switch_mm(oldmm, mm, next);
 
-       if (likely(!prev->mm)) {
+       if (!prev->mm) {
                prev->active_mm = NULL;
                rq->prev_mm = oldmm;
        }
@@ -3248,7 +3378,7 @@ static u64 do_task_delta_exec(struct task_struct *p, struct rq *rq)
 
        if (task_current(rq, p)) {
                update_rq_clock(rq);
-               ns = rq->clock - p->se.exec_start;
+               ns = rq->clock_task - p->se.exec_start;
                if ((s64)ns < 0)
                        ns = 0;
        }
@@ -3397,7 +3527,7 @@ void account_system_time(struct task_struct *p, int hardirq_offset,
        tmp = cputime_to_cputime64(cputime);
        if (hardirq_count() - hardirq_offset)
                cpustat->irq = cputime64_add(cpustat->irq, tmp);
-       else if (softirq_count())
+       else if (in_serving_softirq())
                cpustat->softirq = cputime64_add(cpustat->softirq, tmp);
        else
                cpustat->system = cputime64_add(cpustat->system, tmp);
@@ -3584,7 +3714,7 @@ void scheduler_tick(void)
        curr->sched_class->task_tick(rq, curr, 0);
        raw_spin_unlock(&rq->lock);
 
-       perf_event_task_tick(curr);
+       perf_event_task_tick();
 
 #ifdef CONFIG_SMP
        rq->idle_at_tick = idle_cpu(cpu);
@@ -3723,17 +3853,13 @@ pick_next_task(struct rq *rq)
                        return p;
        }
 
-       class = sched_class_highest;
-       for ( ; ; ) {
+       for_each_class(class) {
                p = class->pick_next_task(rq);
                if (p)
                        return p;
-               /*
-                * Will never be NULL as the idle class always
-                * returns a non-NULL p:
-                */
-               class = class->next;
        }
+
+       BUG(); /* the idle class will always have a runnable task */
 }
 
 /*
@@ -4358,6 +4484,7 @@ void rt_mutex_setprio(struct task_struct *p, int prio)
 
        rq = task_rq_lock(p, &flags);
 
+       trace_sched_pi_setprio(p, prio);
        oldprio = p->prio;
        prev_class = p->sched_class;
        on_rq = p->se.on_rq;
@@ -4645,7 +4772,7 @@ recheck:
        }
 
        if (user) {
-               retval = security_task_setscheduler(p, policy, param);
+               retval = security_task_setscheduler(p);
                if (retval)
                        return retval;
        }
@@ -4661,6 +4788,15 @@ recheck:
         */
        rq = __task_rq_lock(p);
 
+       /*
+        * Changing the policy of the stop threads its a very bad idea
+        */
+       if (p == rq->stop) {
+               __task_rq_unlock(rq);
+               raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+               return -EINVAL;
+       }
+
 #ifdef CONFIG_RT_GROUP_SCHED
        if (user) {
                /*
@@ -4887,13 +5023,13 @@ long sched_setaffinity(pid_t pid, const struct cpumask *in_mask)
        if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
                goto out_unlock;
 
-       retval = security_task_setscheduler(p, 0, NULL);
+       retval = security_task_setscheduler(p);
        if (retval)
                goto out_unlock;
 
        cpuset_cpus_allowed(p, cpus_allowed);
        cpumask_and(new_mask, in_mask, cpus_allowed);
- again:
+again:
        retval = set_cpus_allowed_ptr(p, new_mask);
 
        if (!retval) {
@@ -5337,7 +5473,19 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
        idle->se.exec_start = sched_clock();
 
        cpumask_copy(&idle->cpus_allowed, cpumask_of(cpu));
+       /*
+        * We're having a chicken and egg problem, even though we are
+        * holding rq->lock, the cpu isn't yet set to this cpu so the
+        * lockdep check in task_group() will fail.
+        *
+        * Similar case to sched_fork(). / Alternatively we could
+        * use task_rq_lock() here and obtain the other rq->lock.
+        *
+        * Silence PROVE_RCU
+        */
+       rcu_read_lock();
        __set_task_cpu(idle, cpu);
+       rcu_read_unlock();
 
        rq->curr = rq->idle = idle;
 #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
@@ -6514,6 +6662,7 @@ struct s_data {
        cpumask_var_t           nodemask;
        cpumask_var_t           this_sibling_map;
        cpumask_var_t           this_core_map;
+       cpumask_var_t           this_book_map;
        cpumask_var_t           send_covered;
        cpumask_var_t           tmpmask;
        struct sched_group      **sched_group_nodes;
@@ -6525,6 +6674,7 @@ enum s_alloc {
        sa_rootdomain,
        sa_tmpmask,
        sa_send_covered,
+       sa_this_book_map,
        sa_this_core_map,
        sa_this_sibling_map,
        sa_nodemask,
@@ -6560,31 +6710,48 @@ cpu_to_cpu_group(int cpu, const struct cpumask *cpu_map,
 #ifdef CONFIG_SCHED_MC
 static DEFINE_PER_CPU(struct static_sched_domain, core_domains);
 static DEFINE_PER_CPU(struct static_sched_group, sched_group_core);
-#endif /* CONFIG_SCHED_MC */
 
-#if defined(CONFIG_SCHED_MC) && defined(CONFIG_SCHED_SMT)
 static int
 cpu_to_core_group(int cpu, const struct cpumask *cpu_map,
                  struct sched_group **sg, struct cpumask *mask)
 {
        int group;
-
+#ifdef CONFIG_SCHED_SMT
        cpumask_and(mask, topology_thread_cpumask(cpu), cpu_map);
        group = cpumask_first(mask);
+#else
+       group = cpu;
+#endif
        if (sg)
                *sg = &per_cpu(sched_group_core, group).sg;
        return group;
 }
-#elif defined(CONFIG_SCHED_MC)
+#endif /* CONFIG_SCHED_MC */
+
+/*
+ * book sched-domains:
+ */
+#ifdef CONFIG_SCHED_BOOK
+static DEFINE_PER_CPU(struct static_sched_domain, book_domains);
+static DEFINE_PER_CPU(struct static_sched_group, sched_group_book);
+
 static int
-cpu_to_core_group(int cpu, const struct cpumask *cpu_map,
-                 struct sched_group **sg, struct cpumask *unused)
+cpu_to_book_group(int cpu, const struct cpumask *cpu_map,
+                 struct sched_group **sg, struct cpumask *mask)
 {
+       int group = cpu;
+#ifdef CONFIG_SCHED_MC
+       cpumask_and(mask, cpu_coregroup_mask(cpu), cpu_map);
+       group = cpumask_first(mask);
+#elif defined(CONFIG_SCHED_SMT)
+       cpumask_and(mask, topology_thread_cpumask(cpu), cpu_map);
+       group = cpumask_first(mask);
+#endif
        if (sg)
-               *sg = &per_cpu(sched_group_core, cpu).sg;
-       return cpu;
+               *sg = &per_cpu(sched_group_book, group).sg;
+       return group;
 }
-#endif
+#endif /* CONFIG_SCHED_BOOK */
 
 static DEFINE_PER_CPU(struct static_sched_domain, phys_domains);
 static DEFINE_PER_CPU(struct static_sched_group, sched_group_phys);
@@ -6594,7 +6761,10 @@ cpu_to_phys_group(int cpu, const struct cpumask *cpu_map,
                  struct sched_group **sg, struct cpumask *mask)
 {
        int group;
-#ifdef CONFIG_SCHED_MC
+#ifdef CONFIG_SCHED_BOOK
+       cpumask_and(mask, cpu_book_mask(cpu), cpu_map);
+       group = cpumask_first(mask);
+#elif defined(CONFIG_SCHED_MC)
        cpumask_and(mask, cpu_coregroup_mask(cpu), cpu_map);
        group = cpumask_first(mask);
 #elif defined(CONFIG_SCHED_SMT)
@@ -6855,6 +7025,9 @@ SD_INIT_FUNC(CPU)
 #ifdef CONFIG_SCHED_MC
  SD_INIT_FUNC(MC)
 #endif
+#ifdef CONFIG_SCHED_BOOK
+ SD_INIT_FUNC(BOOK)
+#endif
 
 static int default_relax_domain_level = -1;
 
@@ -6904,6 +7077,8 @@ static void __free_domain_allocs(struct s_data *d, enum s_alloc what,
                free_cpumask_var(d->tmpmask); /* fall through */
        case sa_send_covered:
                free_cpumask_var(d->send_covered); /* fall through */
+       case sa_this_book_map:
+               free_cpumask_var(d->this_book_map); /* fall through */
        case sa_this_core_map:
                free_cpumask_var(d->this_core_map); /* fall through */
        case sa_this_sibling_map:
@@ -6950,8 +7125,10 @@ static enum s_alloc __visit_domain_allocation_hell(struct s_data *d,
                return sa_nodemask;
        if (!alloc_cpumask_var(&d->this_core_map, GFP_KERNEL))
                return sa_this_sibling_map;
-       if (!alloc_cpumask_var(&d->send_covered, GFP_KERNEL))
+       if (!alloc_cpumask_var(&d->this_book_map, GFP_KERNEL))
                return sa_this_core_map;
+       if (!alloc_cpumask_var(&d->send_covered, GFP_KERNEL))
+               return sa_this_book_map;
        if (!alloc_cpumask_var(&d->tmpmask, GFP_KERNEL))
                return sa_send_covered;
        d->rd = alloc_rootdomain();
@@ -7009,6 +7186,23 @@ static struct sched_domain *__build_cpu_sched_domain(struct s_data *d,
        return sd;
 }
 
+static struct sched_domain *__build_book_sched_domain(struct s_data *d,
+       const struct cpumask *cpu_map, struct sched_domain_attr *attr,
+       struct sched_domain *parent, int i)
+{
+       struct sched_domain *sd = parent;
+#ifdef CONFIG_SCHED_BOOK
+       sd = &per_cpu(book_domains, i).sd;
+       SD_INIT(sd, BOOK);
+       set_domain_attribute(sd, attr);
+       cpumask_and(sched_domain_span(sd), cpu_map, cpu_book_mask(i));
+       sd->parent = parent;
+       parent->child = sd;
+       cpu_to_book_group(i, cpu_map, &sd->groups, d->tmpmask);
+#endif
+       return sd;
+}
+
 static struct sched_domain *__build_mc_sched_domain(struct s_data *d,
        const struct cpumask *cpu_map, struct sched_domain_attr *attr,
        struct sched_domain *parent, int i)
@@ -7065,6 +7259,15 @@ static void build_sched_groups(struct s_data *d, enum sched_domain_level l,
                                                &cpu_to_core_group,
                                                d->send_covered, d->tmpmask);
                break;
+#endif
+#ifdef CONFIG_SCHED_BOOK
+       case SD_LV_BOOK: /* set up book groups */
+               cpumask_and(d->this_book_map, cpu_map, cpu_book_mask(cpu));
+               if (cpu == cpumask_first(d->this_book_map))
+                       init_sched_build_groups(d->this_book_map, cpu_map,
+                                               &cpu_to_book_group,
+                                               d->send_covered, d->tmpmask);
+               break;
 #endif
        case SD_LV_CPU: /* set up physical groups */
                cpumask_and(d->nodemask, cpumask_of_node(cpu), cpu_map);
@@ -7113,12 +7316,14 @@ static int __build_sched_domains(const struct cpumask *cpu_map,
 
                sd = __build_numa_sched_domains(&d, cpu_map, attr, i);
                sd = __build_cpu_sched_domain(&d, cpu_map, attr, sd, i);
+               sd = __build_book_sched_domain(&d, cpu_map, attr, sd, i);
                sd = __build_mc_sched_domain(&d, cpu_map, attr, sd, i);
                sd = __build_smt_sched_domain(&d, cpu_map, attr, sd, i);
        }
 
        for_each_cpu(i, cpu_map) {
                build_sched_groups(&d, SD_LV_SIBLING, cpu_map, i);
+               build_sched_groups(&d, SD_LV_BOOK, cpu_map, i);
                build_sched_groups(&d, SD_LV_MC, cpu_map, i);
        }
 
@@ -7149,6 +7354,12 @@ static int __build_sched_domains(const struct cpumask *cpu_map,
                init_sched_groups_power(i, sd);
        }
 #endif
+#ifdef CONFIG_SCHED_BOOK
+       for_each_cpu(i, cpu_map) {
+               sd = &per_cpu(book_domains, i).sd;
+               init_sched_groups_power(i, sd);
+       }
+#endif
 
        for_each_cpu(i, cpu_map) {
                sd = &per_cpu(phys_domains, i).sd;
@@ -7174,6 +7385,8 @@ static int __build_sched_domains(const struct cpumask *cpu_map,
                sd = &per_cpu(cpu_domains, i).sd;
 #elif defined(CONFIG_SCHED_MC)
                sd = &per_cpu(core_domains, i).sd;
+#elif defined(CONFIG_SCHED_BOOK)
+               sd = &per_cpu(book_domains, i).sd;
 #else
                sd = &per_cpu(phys_domains, i).sd;
 #endif
@@ -8078,9 +8291,9 @@ int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
 
        return 1;
 
- err_free_rq:
+err_free_rq:
        kfree(cfs_rq);
- err:
+err:
        return 0;
 }
 
@@ -8168,9 +8381,9 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
 
        return 1;
 
- err_free_rq:
+err_free_rq:
        kfree(rt_rq);
- err:
+err:
        return 0;
 }
 
@@ -8528,7 +8741,7 @@ static int tg_set_bandwidth(struct task_group *tg,
                raw_spin_unlock(&rt_rq->rt_runtime_lock);
        }
        raw_spin_unlock_irq(&tg->rt_bandwidth.rt_runtime_lock);
- unlock:
+unlock:
        read_unlock(&tasklist_lock);
        mutex_unlock(&rt_constraints_mutex);
 
index db3f674ca49dbe93a611716b650bb8c715464da3..933f3d1b62ea0affb63767f87152545f7659dc6f 100644 (file)
@@ -25,7 +25,7 @@
 
 /*
  * Targeted preemption latency for CPU-bound tasks:
- * (default: 5ms * (1 + ilog(ncpus)), units: nanoseconds)
+ * (default: 6ms * (1 + ilog(ncpus)), units: nanoseconds)
  *
  * NOTE: this latency value is not the same as the concept of
  * 'timeslice length' - timeslices in CFS are of variable length
@@ -52,7 +52,7 @@ enum sched_tunable_scaling sysctl_sched_tunable_scaling
 
 /*
  * Minimal preemption granularity for CPU-bound tasks:
- * (default: 2 msec * (1 + ilog(ncpus)), units: nanoseconds)
+ * (default: 0.75 msec * (1 + ilog(ncpus)), units: nanoseconds)
  */
 unsigned int sysctl_sched_min_granularity = 750000ULL;
 unsigned int normalized_sysctl_sched_min_granularity = 750000ULL;
@@ -519,7 +519,7 @@ __update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr,
 static void update_curr(struct cfs_rq *cfs_rq)
 {
        struct sched_entity *curr = cfs_rq->curr;
-       u64 now = rq_of(cfs_rq)->clock;
+       u64 now = rq_of(cfs_rq)->clock_task;
        unsigned long delta_exec;
 
        if (unlikely(!curr))
@@ -602,7 +602,7 @@ update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
        /*
         * We are starting a new run period:
         */
-       se->exec_start = rq_of(cfs_rq)->clock;
+       se->exec_start = rq_of(cfs_rq)->clock_task;
 }
 
 /**************************************************
@@ -1764,6 +1764,10 @@ static void pull_task(struct rq *src_rq, struct task_struct *p,
        set_task_cpu(p, this_cpu);
        activate_task(this_rq, p, 0);
        check_preempt_curr(this_rq, p, 0);
+
+       /* re-arm NEWIDLE balancing when moving tasks */
+       src_rq->avg_idle = this_rq->avg_idle = 2*sysctl_sched_migration_cost;
+       this_rq->idle_stamp = 0;
 }
 
 /*
@@ -1798,7 +1802,7 @@ int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
         * 2) too many balance attempts have failed.
         */
 
-       tsk_cache_hot = task_hot(p, rq->clock, sd);
+       tsk_cache_hot = task_hot(p, rq->clock_task, sd);
        if (!tsk_cache_hot ||
                sd->nr_balance_failed > sd->cache_nice_tries) {
 #ifdef CONFIG_SCHEDSTATS
@@ -2030,12 +2034,14 @@ struct sd_lb_stats {
        unsigned long this_load;
        unsigned long this_load_per_task;
        unsigned long this_nr_running;
+       unsigned long this_has_capacity;
 
        /* Statistics of the busiest group */
        unsigned long max_load;
        unsigned long busiest_load_per_task;
        unsigned long busiest_nr_running;
        unsigned long busiest_group_capacity;
+       unsigned long busiest_has_capacity;
 
        int group_imb; /* Is there imbalance in this sd */
 #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
@@ -2058,6 +2064,7 @@ struct sg_lb_stats {
        unsigned long sum_weighted_load; /* Weighted load of group's tasks */
        unsigned long group_capacity;
        int group_imb; /* Is there an imbalance in the group ? */
+       int group_has_capacity; /* Is there extra capacity in the group? */
 };
 
 /**
@@ -2268,7 +2275,13 @@ unsigned long scale_rt_power(int cpu)
        u64 total, available;
 
        total = sched_avg_period() + (rq->clock - rq->age_stamp);
-       available = total - rq->rt_avg;
+
+       if (unlikely(total < rq->rt_avg)) {
+               /* Ensures that power won't end up being negative */
+               available = 0;
+       } else {
+               available = total - rq->rt_avg;
+       }
 
        if (unlikely((s64)total < SCHED_LOAD_SCALE))
                total = SCHED_LOAD_SCALE;
@@ -2378,7 +2391,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
                        int local_group, const struct cpumask *cpus,
                        int *balance, struct sg_lb_stats *sgs)
 {
-       unsigned long load, max_cpu_load, min_cpu_load;
+       unsigned long load, max_cpu_load, min_cpu_load, max_nr_running;
        int i;
        unsigned int balance_cpu = -1, first_idle_cpu = 0;
        unsigned long avg_load_per_task = 0;
@@ -2389,6 +2402,7 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
        /* Tally up the load of all CPUs in the group */
        max_cpu_load = 0;
        min_cpu_load = ~0UL;
+       max_nr_running = 0;
 
        for_each_cpu_and(i, sched_group_cpus(group), cpus) {
                struct rq *rq = cpu_rq(i);
@@ -2406,8 +2420,10 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
                        load = target_load(i, load_idx);
                } else {
                        load = source_load(i, load_idx);
-                       if (load > max_cpu_load)
+                       if (load > max_cpu_load) {
                                max_cpu_load = load;
+                               max_nr_running = rq->nr_running;
+                       }
                        if (min_cpu_load > load)
                                min_cpu_load = load;
                }
@@ -2447,13 +2463,15 @@ static inline void update_sg_lb_stats(struct sched_domain *sd,
        if (sgs->sum_nr_running)
                avg_load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running;
 
-       if ((max_cpu_load - min_cpu_load) > 2*avg_load_per_task)
+       if ((max_cpu_load - min_cpu_load) > 2*avg_load_per_task && max_nr_running > 1)
                sgs->group_imb = 1;
 
-       sgs->group_capacity =
-               DIV_ROUND_CLOSEST(group->cpu_power, SCHED_LOAD_SCALE);
+       sgs->group_capacity = DIV_ROUND_CLOSEST(group->cpu_power, SCHED_LOAD_SCALE);
        if (!sgs->group_capacity)
                sgs->group_capacity = fix_small_capacity(sd, group);
+
+       if (sgs->group_capacity > sgs->sum_nr_running)
+               sgs->group_has_capacity = 1;
 }
 
 /**
@@ -2542,9 +2560,14 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
                /*
                 * In case the child domain prefers tasks go to siblings
                 * first, lower the sg capacity to one so that we'll try
-                * and move all the excess tasks away.
+                * and move all the excess tasks away. We lower the capacity
+                * of a group only if the local group has the capacity to fit
+                * these excess tasks, i.e. nr_running < group_capacity. The
+                * extra check prevents the case where you always pull from the
+                * heaviest group when it is already under-utilized (possible
+                * with a large weight task outweighs the tasks on the system).
                 */
-               if (prefer_sibling)
+               if (prefer_sibling && !local_group && sds->this_has_capacity)
                        sgs.group_capacity = min(sgs.group_capacity, 1UL);
 
                if (local_group) {
@@ -2552,12 +2575,14 @@ static inline void update_sd_lb_stats(struct sched_domain *sd, int this_cpu,
                        sds->this = sg;
                        sds->this_nr_running = sgs.sum_nr_running;
                        sds->this_load_per_task = sgs.sum_weighted_load;
+                       sds->this_has_capacity = sgs.group_has_capacity;
                } else if (update_sd_pick_busiest(sd, sds, sg, &sgs, this_cpu)) {
                        sds->max_load = sgs.avg_load;
                        sds->busiest = sg;
                        sds->busiest_nr_running = sgs.sum_nr_running;
                        sds->busiest_group_capacity = sgs.group_capacity;
                        sds->busiest_load_per_task = sgs.sum_weighted_load;
+                       sds->busiest_has_capacity = sgs.group_has_capacity;
                        sds->group_imb = sgs.group_imb;
                }
 
@@ -2754,6 +2779,7 @@ static inline void calculate_imbalance(struct sd_lb_stats *sds, int this_cpu,
                return fix_small_imbalance(sds, this_cpu, imbalance);
 
 }
+
 /******* find_busiest_group() helpers end here *********************/
 
 /**
@@ -2805,6 +2831,11 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
         * 4) This group is more busy than the avg busieness at this
         *    sched_domain.
         * 5) The imbalance is within the specified limit.
+        *
+        * Note: when doing newidle balance, if the local group has excess
+        * capacity (i.e. nr_running < group_capacity) and the busiest group
+        * does not have any capacity, we force a load balance to pull tasks
+        * to the local group. In this case, we skip past checks 3, 4 and 5.
         */
        if (!(*balance))
                goto ret;
@@ -2816,6 +2847,11 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
        if (!sds.busiest || sds.busiest_nr_running == 0)
                goto out_balanced;
 
+       /*  SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */
+       if (idle == CPU_NEWLY_IDLE && sds.this_has_capacity &&
+                       !sds.busiest_has_capacity)
+               goto force_balance;
+
        if (sds.this_load >= sds.max_load)
                goto out_balanced;
 
@@ -2827,6 +2863,7 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
        if (100 * sds.max_load <= sd->imbalance_pct * sds.this_load)
                goto out_balanced;
 
+force_balance:
        /* Looks like there is an imbalance. Compute it */
        calculate_imbalance(&sds, this_cpu, imbalance);
        return sds.busiest;
@@ -3031,7 +3068,14 @@ redo:
 
        if (!ld_moved) {
                schedstat_inc(sd, lb_failed[idle]);
-               sd->nr_balance_failed++;
+               /*
+                * Increment the failure counter only on periodic balance.
+                * We do not want newidle balance, which can be very
+                * frequent, pollute the failure counter causing
+                * excessive cache_hot migrations and active balances.
+                */
+               if (idle != CPU_NEWLY_IDLE)
+                       sd->nr_balance_failed++;
 
                if (need_active_balance(sd, sd_idle, idle, cpu_of(busiest),
                                        this_cpu)) {
@@ -3153,10 +3197,8 @@ static void idle_balance(int this_cpu, struct rq *this_rq)
                interval = msecs_to_jiffies(sd->balance_interval);
                if (time_after(next_balance, sd->last_balance + interval))
                        next_balance = sd->last_balance + interval;
-               if (pulled_task) {
-                       this_rq->idle_stamp = 0;
+               if (pulled_task)
                        break;
-               }
        }
 
        raw_spin_lock(&this_rq->lock);
@@ -3751,8 +3793,11 @@ static void task_fork_fair(struct task_struct *p)
 
        update_rq_clock(rq);
 
-       if (unlikely(task_cpu(p) != this_cpu))
+       if (unlikely(task_cpu(p) != this_cpu)) {
+               rcu_read_lock();
                __set_task_cpu(p, this_cpu);
+               rcu_read_unlock();
+       }
 
        update_curr(cfs_rq);
 
index 83c66e8ad3ee314704456e14dfc23607d00c5f0d..185f920ec1a2e923b0d966f787c610ff26a7b6cb 100644 (file)
@@ -61,3 +61,8 @@ SCHED_FEAT(ASYM_EFF_LOAD, 1)
  * release the lock. Decreases scheduling overhead.
  */
 SCHED_FEAT(OWNER_SPIN, 1)
+
+/*
+ * Decrement CPU power based on irq activity
+ */
+SCHED_FEAT(NONIRQ_POWER, 1)
index d10c80ebb67a2821038a9c59b912bf8e323d67e3..bea7d79f7e9ca958bba514cbd8eb48ceab47bab3 100644 (file)
@@ -609,7 +609,7 @@ static void update_curr_rt(struct rq *rq)
        if (!task_has_rt_policy(curr))
                return;
 
-       delta_exec = rq->clock - curr->se.exec_start;
+       delta_exec = rq->clock_task - curr->se.exec_start;
        if (unlikely((s64)delta_exec < 0))
                delta_exec = 0;
 
@@ -618,7 +618,7 @@ static void update_curr_rt(struct rq *rq)
        curr->se.sum_exec_runtime += delta_exec;
        account_group_exec_runtime(curr, delta_exec);
 
-       curr->se.exec_start = rq->clock;
+       curr->se.exec_start = rq->clock_task;
        cpuacct_charge(curr, delta_exec);
 
        sched_rt_avg_update(rq, delta_exec);
@@ -960,18 +960,19 @@ select_task_rq_rt(struct rq *rq, struct task_struct *p, int sd_flag, int flags)
         * runqueue. Otherwise simply start this RT task
         * on its current runqueue.
         *
-        * We want to avoid overloading runqueues. Even if
-        * the RT task is of higher priority than the current RT task.
-        * RT tasks behave differently than other tasks. If
-        * one gets preempted, we try to push it off to another queue.
-        * So trying to keep a preempting RT task on the same
-        * cache hot CPU will force the running RT task to
-        * a cold CPU. So we waste all the cache for the lower
-        * RT task in hopes of saving some of a RT task
-        * that is just being woken and probably will have
-        * cold cache anyway.
+        * We want to avoid overloading runqueues. If the woken
+        * task is a higher priority, then it will stay on this CPU
+        * and the lower prio task should be moved to another CPU.
+        * Even though this will probably make the lower prio task
+        * lose its cache, we do not want to bounce a higher task
+        * around just because it gave up its CPU, perhaps for a
+        * lock?
+        *
+        * For equal prio tasks, we just let the scheduler sort it out.
         */
        if (unlikely(rt_task(rq->curr)) &&
+           (rq->curr->rt.nr_cpus_allowed < 2 ||
+            rq->curr->prio < p->prio) &&
            (p->rt.nr_cpus_allowed > 1)) {
                int cpu = find_lowest_rq(p);
 
@@ -1074,7 +1075,7 @@ static struct task_struct *_pick_next_task_rt(struct rq *rq)
        } while (rt_rq);
 
        p = rt_task_of(rt_se);
-       p->se.exec_start = rq->clock;
+       p->se.exec_start = rq->clock_task;
 
        return p;
 }
@@ -1139,7 +1140,7 @@ static struct task_struct *pick_next_highest_task_rt(struct rq *rq, int cpu)
        for_each_leaf_rt_rq(rt_rq, rq) {
                array = &rt_rq->active;
                idx = sched_find_first_bit(array->bitmap);
- next_idx:
+next_idx:
                if (idx >= MAX_RT_PRIO)
                        continue;
                if (next && next->prio < idx)
@@ -1315,7 +1316,7 @@ static int push_rt_task(struct rq *rq)
        if (!next_task)
                return 0;
 
- retry:
+retry:
        if (unlikely(next_task == rq->curr)) {
                WARN_ON(1);
                return 0;
@@ -1463,7 +1464,7 @@ static int pull_rt_task(struct rq *this_rq)
                         * but possible)
                         */
                }
- skip:
+skip:
                double_unlock_balance(this_rq, src_rq);
        }
 
@@ -1491,7 +1492,10 @@ static void task_woken_rt(struct rq *rq, struct task_struct *p)
        if (!task_running(rq, p) &&
            !test_tsk_need_resched(rq->curr) &&
            has_pushable_tasks(rq) &&
-           p->rt.nr_cpus_allowed > 1)
+           p->rt.nr_cpus_allowed > 1 &&
+           rt_task(rq->curr) &&
+           (rq->curr->rt.nr_cpus_allowed < 2 ||
+            rq->curr->prio < p->prio))
                push_rt_tasks(rq);
 }
 
@@ -1709,7 +1713,7 @@ static void set_curr_task_rt(struct rq *rq)
 {
        struct task_struct *p = rq->curr;
 
-       p->se.exec_start = rq->clock;
+       p->se.exec_start = rq->clock_task;
 
        /* The running task is never eligible for pushing */
        dequeue_pushable_task(rq, p);
diff --git a/kernel/sched_stoptask.c b/kernel/sched_stoptask.c
new file mode 100644 (file)
index 0000000..45bddc0
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * stop-task scheduling class.
+ *
+ * The stop task is the highest priority task in the system, it preempts
+ * everything and will be preempted by nothing.
+ *
+ * See kernel/stop_machine.c
+ */
+
+#ifdef CONFIG_SMP
+static int
+select_task_rq_stop(struct rq *rq, struct task_struct *p,
+                   int sd_flag, int flags)
+{
+       return task_cpu(p); /* stop tasks as never migrate */
+}
+#endif /* CONFIG_SMP */
+
+static void
+check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags)
+{
+       resched_task(rq->curr); /* we preempt everything */
+}
+
+static struct task_struct *pick_next_task_stop(struct rq *rq)
+{
+       struct task_struct *stop = rq->stop;
+
+       if (stop && stop->state == TASK_RUNNING)
+               return stop;
+
+       return NULL;
+}
+
+static void
+enqueue_task_stop(struct rq *rq, struct task_struct *p, int flags)
+{
+}
+
+static void
+dequeue_task_stop(struct rq *rq, struct task_struct *p, int flags)
+{
+}
+
+static void yield_task_stop(struct rq *rq)
+{
+       BUG(); /* the stop task should never yield, its pointless. */
+}
+
+static void put_prev_task_stop(struct rq *rq, struct task_struct *prev)
+{
+}
+
+static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued)
+{
+}
+
+static void set_curr_task_stop(struct rq *rq)
+{
+}
+
+static void switched_to_stop(struct rq *rq, struct task_struct *p,
+                            int running)
+{
+       BUG(); /* its impossible to change to this class */
+}
+
+static void prio_changed_stop(struct rq *rq, struct task_struct *p,
+                             int oldprio, int running)
+{
+       BUG(); /* how!?, what priority? */
+}
+
+static unsigned int
+get_rr_interval_stop(struct rq *rq, struct task_struct *task)
+{
+       return 0;
+}
+
+/*
+ * Simple, special scheduling class for the per-CPU stop tasks:
+ */
+static const struct sched_class stop_sched_class = {
+       .next                   = &rt_sched_class,
+
+       .enqueue_task           = enqueue_task_stop,
+       .dequeue_task           = dequeue_task_stop,
+       .yield_task             = yield_task_stop,
+
+       .check_preempt_curr     = check_preempt_curr_stop,
+
+       .pick_next_task         = pick_next_task_stop,
+       .put_prev_task          = put_prev_task_stop,
+
+#ifdef CONFIG_SMP
+       .select_task_rq         = select_task_rq_stop,
+#endif
+
+       .set_curr_task          = set_curr_task_stop,
+       .task_tick              = task_tick_stop,
+
+       .get_rr_interval        = get_rr_interval_stop,
+
+       .prio_changed           = prio_changed_stop,
+       .switched_to            = switched_to_stop,
+
+       /* no .task_new for stop tasks */
+};
index 07b4f1b1a73a9b6a309a3e7fe249c813007b5d17..e33fd71ed66a301621511eaf85b66cef72afce89 100644 (file)
@@ -76,12 +76,22 @@ void wakeup_softirqd(void)
                wake_up_process(tsk);
 }
 
+/*
+ * preempt_count and SOFTIRQ_OFFSET usage:
+ * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving
+ *   softirq processing.
+ * - preempt_count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET)
+ *   on local_bh_disable or local_bh_enable.
+ * This lets us distinguish between whether we are currently processing
+ * softirq and whether we just have bh disabled.
+ */
+
 /*
  * This one is for softirq.c-internal use,
  * where hardirqs are disabled legitimately:
  */
 #ifdef CONFIG_TRACE_IRQFLAGS
-static void __local_bh_disable(unsigned long ip)
+static void __local_bh_disable(unsigned long ip, unsigned int cnt)
 {
        unsigned long flags;
 
@@ -95,32 +105,43 @@ static void __local_bh_disable(unsigned long ip)
         * We must manually increment preempt_count here and manually
         * call the trace_preempt_off later.
         */
-       preempt_count() += SOFTIRQ_OFFSET;
+       preempt_count() += cnt;
        /*
         * Were softirqs turned off above:
         */
-       if (softirq_count() == SOFTIRQ_OFFSET)
+       if (softirq_count() == cnt)
                trace_softirqs_off(ip);
        raw_local_irq_restore(flags);
 
-       if (preempt_count() == SOFTIRQ_OFFSET)
+       if (preempt_count() == cnt)
                trace_preempt_off(CALLER_ADDR0, get_parent_ip(CALLER_ADDR1));
 }
 #else /* !CONFIG_TRACE_IRQFLAGS */
-static inline void __local_bh_disable(unsigned long ip)
+static inline void __local_bh_disable(unsigned long ip, unsigned int cnt)
 {
-       add_preempt_count(SOFTIRQ_OFFSET);
+       add_preempt_count(cnt);
        barrier();
 }
 #endif /* CONFIG_TRACE_IRQFLAGS */
 
 void local_bh_disable(void)
 {
-       __local_bh_disable((unsigned long)__builtin_return_address(0));
+       __local_bh_disable((unsigned long)__builtin_return_address(0),
+                               SOFTIRQ_DISABLE_OFFSET);
 }
 
 EXPORT_SYMBOL(local_bh_disable);
 
+static void __local_bh_enable(unsigned int cnt)
+{
+       WARN_ON_ONCE(in_irq());
+       WARN_ON_ONCE(!irqs_disabled());
+
+       if (softirq_count() == cnt)
+               trace_softirqs_on((unsigned long)__builtin_return_address(0));
+       sub_preempt_count(cnt);
+}
+
 /*
  * Special-case - softirqs can safely be enabled in
  * cond_resched_softirq(), or by __do_softirq(),
@@ -128,12 +149,7 @@ EXPORT_SYMBOL(local_bh_disable);
  */
 void _local_bh_enable(void)
 {
-       WARN_ON_ONCE(in_irq());
-       WARN_ON_ONCE(!irqs_disabled());
-
-       if (softirq_count() == SOFTIRQ_OFFSET)
-               trace_softirqs_on((unsigned long)__builtin_return_address(0));
-       sub_preempt_count(SOFTIRQ_OFFSET);
+       __local_bh_enable(SOFTIRQ_DISABLE_OFFSET);
 }
 
 EXPORT_SYMBOL(_local_bh_enable);
@@ -147,13 +163,13 @@ static inline void _local_bh_enable_ip(unsigned long ip)
        /*
         * Are softirqs going to be turned on now:
         */
-       if (softirq_count() == SOFTIRQ_OFFSET)
+       if (softirq_count() == SOFTIRQ_DISABLE_OFFSET)
                trace_softirqs_on(ip);
        /*
         * Keep preemption disabled until we are done with
         * softirq processing:
         */
-       sub_preempt_count(SOFTIRQ_OFFSET - 1);
+       sub_preempt_count(SOFTIRQ_DISABLE_OFFSET - 1);
 
        if (unlikely(!in_interrupt() && local_softirq_pending()))
                do_softirq();
@@ -198,7 +214,8 @@ asmlinkage void __do_softirq(void)
        pending = local_softirq_pending();
        account_system_vtime(current);
 
-       __local_bh_disable((unsigned long)__builtin_return_address(0));
+       __local_bh_disable((unsigned long)__builtin_return_address(0),
+                               SOFTIRQ_OFFSET);
        lockdep_softirq_enter();
 
        cpu = smp_processor_id();
@@ -212,18 +229,20 @@ restart:
 
        do {
                if (pending & 1) {
+                       unsigned int vec_nr = h - softirq_vec;
                        int prev_count = preempt_count();
-                       kstat_incr_softirqs_this_cpu(h - softirq_vec);
 
-                       trace_softirq_entry(h, softirq_vec);
+                       kstat_incr_softirqs_this_cpu(vec_nr);
+
+                       trace_softirq_entry(vec_nr);
                        h->action(h);
-                       trace_softirq_exit(h, softirq_vec);
+                       trace_softirq_exit(vec_nr);
                        if (unlikely(prev_count != preempt_count())) {
-                               printk(KERN_ERR "huh, entered softirq %td %s %p"
+                               printk(KERN_ERR "huh, entered softirq %u %s %p"
                                       "with preempt_count %08x,"
-                                      " exited with %08x?\n", h - softirq_vec,
-                                      softirq_to_name[h - softirq_vec],
-                                      h->action, prev_count, preempt_count());
+                                      " exited with %08x?\n", vec_nr,
+                                      softirq_to_name[vec_nr], h->action,
+                                      prev_count, preempt_count());
                                preempt_count() = prev_count;
                        }
 
@@ -245,7 +264,7 @@ restart:
        lockdep_softirq_exit();
 
        account_system_vtime(current);
-       _local_bh_enable();
+       __local_bh_enable(SOFTIRQ_OFFSET);
 }
 
 #ifndef __ARCH_HAS_DO_SOFTIRQ
@@ -279,10 +298,16 @@ void irq_enter(void)
 
        rcu_irq_enter();
        if (idle_cpu(cpu) && !in_interrupt()) {
-               __irq_enter();
+               /*
+                * Prevent raise_softirq from needlessly waking up ksoftirqd
+                * here, as softirq will be serviced on return from interrupt.
+                */
+               local_bh_disable();
                tick_check_idle(cpu);
-       } else
-               __irq_enter();
+               _local_bh_enable();
+       }
+
+       __irq_enter();
 }
 
 #ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED
@@ -696,6 +721,7 @@ static int run_ksoftirqd(void * __bind_cpu)
 {
        set_current_state(TASK_INTERRUPTIBLE);
 
+       current->flags |= PF_KSOFTIRQD;
        while (!kthread_should_stop()) {
                preempt_disable();
                if (!local_softirq_pending()) {
@@ -886,17 +912,14 @@ int __init __weak early_irq_init(void)
        return 0;
 }
 
+#ifdef CONFIG_GENERIC_HARDIRQS
 int __init __weak arch_probe_nr_irqs(void)
 {
-       return 0;
+       return NR_IRQS_LEGACY;
 }
 
 int __init __weak arch_early_irq_init(void)
 {
        return 0;
 }
-
-int __weak arch_init_chip_data(struct irq_desc *desc, int node)
-{
-       return 0;
-}
+#endif
index 2980da3fd50925f7902a5ba42e64934f6c4b0650..c71e075005368eceff3aab4340f94beca4aee249 100644 (file)
@@ -46,11 +46,9 @@ static int init_srcu_struct_fields(struct srcu_struct *sp)
 int __init_srcu_struct(struct srcu_struct *sp, const char *name,
                       struct lock_class_key *key)
 {
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
        /* Don't re-initialize a lock while it is held. */
        debug_check_no_locks_freed((void *)sp, sizeof(*sp));
        lockdep_init_map(&sp->dep_map, name, key, 0);
-#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
        return init_srcu_struct_fields(sp);
 }
 EXPORT_SYMBOL_GPL(__init_srcu_struct);
index 4372ccb25127ea8548719c78cb4a610edb94febf..090c28812ce101fbd055821fe12806265bd1ed9b 100644 (file)
@@ -287,11 +287,12 @@ repeat:
        goto repeat;
 }
 
+extern void sched_set_stop_task(int cpu, struct task_struct *stop);
+
 /* manage stopper for a cpu, mostly lifted from sched migration thread mgmt */
 static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb,
                                           unsigned long action, void *hcpu)
 {
-       struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
        unsigned int cpu = (unsigned long)hcpu;
        struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
        struct task_struct *p;
@@ -304,13 +305,13 @@ static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb,
                                   cpu);
                if (IS_ERR(p))
                        return NOTIFY_BAD;
-               sched_setscheduler_nocheck(p, SCHED_FIFO, &param);
                get_task_struct(p);
+               kthread_bind(p, cpu);
+               sched_set_stop_task(cpu, p);
                stopper->thread = p;
                break;
 
        case CPU_ONLINE:
-               kthread_bind(stopper->thread, cpu);
                /* strictly unnecessary, as first user will wake it */
                wake_up_process(stopper->thread);
                /* mark enabled */
@@ -325,6 +326,7 @@ static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb,
        {
                struct cpu_stop_work *work;
 
+               sched_set_stop_task(cpu, NULL);
                /* kill the stopper */
                kthread_stop(stopper->thread);
                /* drain remaining works */
index bad369ec54036afe9a2c2d87011fc99ea488755b..c782fe9924c79f052e1b81b7d12bdf53f9991a69 100644 (file)
@@ -50,6 +50,7 @@ cond_syscall(compat_sys_sendmsg);
 cond_syscall(sys_recvmsg);
 cond_syscall(sys_recvmmsg);
 cond_syscall(compat_sys_recvmsg);
+cond_syscall(compat_sys_recv);
 cond_syscall(compat_sys_recvfrom);
 cond_syscall(compat_sys_recvmmsg);
 cond_syscall(sys_socketcall);
index 4f104515a19bcb18ca73226c745786a41d41b4ae..f8b11a283171b65849c5ed3bc0e162397f76fbea 100644 (file)
@@ -115,7 +115,9 @@ static int test_kprobes(void)
        int ret;
        struct kprobe *kps[2] = {&kp, &kp2};
 
-       kp.addr = 0; /* addr should be cleard for reusing kprobe. */
+       /* addr and flags should be cleard for reusing kprobe. */
+       kp.addr = NULL;
+       kp.flags = 0;
        ret = register_kprobes(kps, 2);
        if (ret < 0) {
                printk(KERN_ERR "Kprobe smoke test failed: "
@@ -210,7 +212,9 @@ static int test_jprobes(void)
        int ret;
        struct jprobe *jps[2] = {&jp, &jp2};
 
-       jp.kp.addr = 0; /* addr should be cleard for reusing kprobe. */
+       /* addr and flags should be cleard for reusing kprobe. */
+       jp.kp.addr = NULL;
+       jp.kp.flags = 0;
        ret = register_jprobes(jps, 2);
        if (ret < 0) {
                printk(KERN_ERR "Kprobe smoke test failed: "
@@ -323,7 +327,9 @@ static int test_kretprobes(void)
        int ret;
        struct kretprobe *rps[2] = {&rp, &rp2};
 
-       rp.kp.addr = 0; /* addr should be cleard for reusing kprobe. */
+       /* addr and flags should be cleard for reusing kprobe. */
+       rp.kp.addr = NULL;
+       rp.kp.flags = 0;
        ret = register_kretprobes(rps, 2);
        if (ret < 0) {
                printk(KERN_ERR "Kprobe smoke test failed: "
index c63116863a80294c7ce1545b2089efe1d43258d0..d2321891538f53425430565fe68197b5cde93d12 100644 (file)
@@ -149,10 +149,18 @@ static void ntp_update_offset(long offset)
        time_reftime = get_seconds();
 
        offset64    = offset;
-       freq_adj    = (offset64 * secs) <<
-                       (NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + time_constant));
+       freq_adj    = ntp_update_offset_fll(offset64, secs);
 
-       freq_adj    += ntp_update_offset_fll(offset64, secs);
+       /*
+        * Clamp update interval to reduce PLL gain with low
+        * sampling rate (e.g. intermittent network connection)
+        * to avoid instability.
+        */
+       if (unlikely(secs > 1 << (SHIFT_PLL + 1 + time_constant)))
+               secs = 1 << (SHIFT_PLL + 1 + time_constant);
+
+       freq_adj    += (offset64 * secs) <<
+                       (NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + time_constant));
 
        freq_adj    = min(freq_adj + time_freq, MAXFREQ_SCALED);
 
index 97bf05baade7cb4b9db4a5b76cf26255b6a67753..68a9ae7679b717f6eb4782ce5114ad405dec5a4c 100644 (file)
@@ -37,7 +37,7 @@
 #include <linux/delay.h>
 #include <linux/tick.h>
 #include <linux/kallsyms.h>
-#include <linux/perf_event.h>
+#include <linux/irq_work.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 
@@ -1279,7 +1279,10 @@ void update_process_times(int user_tick)
        run_local_timers();
        rcu_check_callbacks(cpu, user_tick);
        printk_tick();
-       perf_event_do_pending();
+#ifdef CONFIG_IRQ_WORK
+       if (in_irq())
+               irq_work_run();
+#endif
        scheduler_tick();
        run_posix_cpu_timers(p);
 }
index 538501c6ea5058cf703eaa2608307f03f3aee89a..e04b8bcdef88dc92a3c52c9c53808528b0266b09 100644 (file)
@@ -49,6 +49,11 @@ config HAVE_SYSCALL_TRACEPOINTS
        help
          See Documentation/trace/ftrace-design.txt
 
+config HAVE_C_RECORDMCOUNT
+       bool
+       help
+         C version of recordmcount available?
+
 config TRACER_MAX_TRACE
        bool
 
@@ -121,7 +126,7 @@ if FTRACE
 config FUNCTION_TRACER
        bool "Kernel Function Tracer"
        depends on HAVE_FUNCTION_TRACER
-       select FRAME_POINTER
+       select FRAME_POINTER if (!ARM_UNWIND)
        select KALLSYMS
        select GENERIC_TRACER
        select CONTEXT_SWITCH_TRACER
index fa7ece649fe1bcad7b0db621fa8579e91860fb04..ebd80d50c474e60fd84fd4a577da69b052fe14eb 100644 (file)
@@ -884,10 +884,8 @@ enum {
        FTRACE_ENABLE_CALLS             = (1 << 0),
        FTRACE_DISABLE_CALLS            = (1 << 1),
        FTRACE_UPDATE_TRACE_FUNC        = (1 << 2),
-       FTRACE_ENABLE_MCOUNT            = (1 << 3),
-       FTRACE_DISABLE_MCOUNT           = (1 << 4),
-       FTRACE_START_FUNC_RET           = (1 << 5),
-       FTRACE_STOP_FUNC_RET            = (1 << 6),
+       FTRACE_START_FUNC_RET           = (1 << 3),
+       FTRACE_STOP_FUNC_RET            = (1 << 4),
 };
 
 static int ftrace_filtered;
@@ -1226,8 +1224,6 @@ static void ftrace_shutdown(int command)
 
 static void ftrace_startup_sysctl(void)
 {
-       int command = FTRACE_ENABLE_MCOUNT;
-
        if (unlikely(ftrace_disabled))
                return;
 
@@ -1235,23 +1231,17 @@ static void ftrace_startup_sysctl(void)
        saved_ftrace_func = NULL;
        /* ftrace_start_up is true if we want ftrace running */
        if (ftrace_start_up)
-               command |= FTRACE_ENABLE_CALLS;
-
-       ftrace_run_update_code(command);
+               ftrace_run_update_code(FTRACE_ENABLE_CALLS);
 }
 
 static void ftrace_shutdown_sysctl(void)
 {
-       int command = FTRACE_DISABLE_MCOUNT;
-
        if (unlikely(ftrace_disabled))
                return;
 
        /* ftrace_start_up is true if ftrace is running */
        if (ftrace_start_up)
-               command |= FTRACE_DISABLE_CALLS;
-
-       ftrace_run_update_code(command);
+               ftrace_run_update_code(FTRACE_DISABLE_CALLS);
 }
 
 static cycle_t         ftrace_update_time;
@@ -1368,24 +1358,29 @@ enum {
 #define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */
 
 struct ftrace_iterator {
-       struct ftrace_page      *pg;
-       int                     hidx;
-       int                     idx;
-       unsigned                flags;
-       struct trace_parser     parser;
+       loff_t                          pos;
+       loff_t                          func_pos;
+       struct ftrace_page              *pg;
+       struct dyn_ftrace               *func;
+       struct ftrace_func_probe        *probe;
+       struct trace_parser             parser;
+       int                             hidx;
+       int                             idx;
+       unsigned                        flags;
 };
 
 static void *
-t_hash_next(struct seq_file *m, void *v, loff_t *pos)
+t_hash_next(struct seq_file *m, loff_t *pos)
 {
        struct ftrace_iterator *iter = m->private;
-       struct hlist_node *hnd = v;
+       struct hlist_node *hnd = NULL;
        struct hlist_head *hhd;
 
-       WARN_ON(!(iter->flags & FTRACE_ITER_HASH));
-
        (*pos)++;
+       iter->pos = *pos;
 
+       if (iter->probe)
+               hnd = &iter->probe->node;
  retry:
        if (iter->hidx >= FTRACE_FUNC_HASHSIZE)
                return NULL;
@@ -1408,7 +1403,12 @@ t_hash_next(struct seq_file *m, void *v, loff_t *pos)
                }
        }
 
-       return hnd;
+       if (WARN_ON_ONCE(!hnd))
+               return NULL;
+
+       iter->probe = hlist_entry(hnd, struct ftrace_func_probe, node);
+
+       return iter;
 }
 
 static void *t_hash_start(struct seq_file *m, loff_t *pos)
@@ -1417,26 +1417,32 @@ static void *t_hash_start(struct seq_file *m, loff_t *pos)
        void *p = NULL;
        loff_t l;
 
-       if (!(iter->flags & FTRACE_ITER_HASH))
-               *pos = 0;
-
-       iter->flags |= FTRACE_ITER_HASH;
+       if (iter->func_pos > *pos)
+               return NULL;
 
        iter->hidx = 0;
-       for (l = 0; l <= *pos; ) {
-               p = t_hash_next(m, p, &l);
+       for (l = 0; l <= (*pos - iter->func_pos); ) {
+               p = t_hash_next(m, &l);
                if (!p)
                        break;
        }
-       return p;
+       if (!p)
+               return NULL;
+
+       /* Only set this if we have an item */
+       iter->flags |= FTRACE_ITER_HASH;
+
+       return iter;
 }
 
-static int t_hash_show(struct seq_file *m, void *v)
+static int
+t_hash_show(struct seq_file *m, struct ftrace_iterator *iter)
 {
        struct ftrace_func_probe *rec;
-       struct hlist_node *hnd = v;
 
-       rec = hlist_entry(hnd, struct ftrace_func_probe, node);
+       rec = iter->probe;
+       if (WARN_ON_ONCE(!rec))
+               return -EIO;
 
        if (rec->ops->print)
                return rec->ops->print(m, rec->ip, rec->ops, rec->data);
@@ -1457,12 +1463,13 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
        struct dyn_ftrace *rec = NULL;
 
        if (iter->flags & FTRACE_ITER_HASH)
-               return t_hash_next(m, v, pos);
+               return t_hash_next(m, pos);
 
        (*pos)++;
+       iter->pos = *pos;
 
        if (iter->flags & FTRACE_ITER_PRINTALL)
-               return NULL;
+               return t_hash_start(m, pos);
 
  retry:
        if (iter->idx >= iter->pg->index) {
@@ -1491,7 +1498,20 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
                }
        }
 
-       return rec;
+       if (!rec)
+               return t_hash_start(m, pos);
+
+       iter->func_pos = *pos;
+       iter->func = rec;
+
+       return iter;
+}
+
+static void reset_iter_read(struct ftrace_iterator *iter)
+{
+       iter->pos = 0;
+       iter->func_pos = 0;
+       iter->flags &= ~(FTRACE_ITER_PRINTALL & FTRACE_ITER_HASH);
 }
 
 static void *t_start(struct seq_file *m, loff_t *pos)
@@ -1501,6 +1521,12 @@ static void *t_start(struct seq_file *m, loff_t *pos)
        loff_t l;
 
        mutex_lock(&ftrace_lock);
+       /*
+        * If an lseek was done, then reset and start from beginning.
+        */
+       if (*pos < iter->pos)
+               reset_iter_read(iter);
+
        /*
         * For set_ftrace_filter reading, if we have the filter
         * off, we can short cut and just print out that all
@@ -1518,6 +1544,11 @@ static void *t_start(struct seq_file *m, loff_t *pos)
        if (iter->flags & FTRACE_ITER_HASH)
                return t_hash_start(m, pos);
 
+       /*
+        * Unfortunately, we need to restart at ftrace_pages_start
+        * every time we let go of the ftrace_mutex. This is because
+        * those pointers can change without the lock.
+        */
        iter->pg = ftrace_pages_start;
        iter->idx = 0;
        for (l = 0; l <= *pos; ) {
@@ -1526,10 +1557,14 @@ static void *t_start(struct seq_file *m, loff_t *pos)
                        break;
        }
 
-       if (!p && iter->flags & FTRACE_ITER_FILTER)
-               return t_hash_start(m, pos);
+       if (!p) {
+               if (iter->flags & FTRACE_ITER_FILTER)
+                       return t_hash_start(m, pos);
 
-       return p;
+               return NULL;
+       }
+
+       return iter;
 }
 
 static void t_stop(struct seq_file *m, void *p)
@@ -1540,16 +1575,18 @@ static void t_stop(struct seq_file *m, void *p)
 static int t_show(struct seq_file *m, void *v)
 {
        struct ftrace_iterator *iter = m->private;
-       struct dyn_ftrace *rec = v;
+       struct dyn_ftrace *rec;
 
        if (iter->flags & FTRACE_ITER_HASH)
-               return t_hash_show(m, v);
+               return t_hash_show(m, iter);
 
        if (iter->flags & FTRACE_ITER_PRINTALL) {
                seq_printf(m, "#### all functions enabled ####\n");
                return 0;
        }
 
+       rec = iter->func;
+
        if (!rec)
                return 0;
 
@@ -1601,8 +1638,8 @@ ftrace_failures_open(struct inode *inode, struct file *file)
 
        ret = ftrace_avail_open(inode, file);
        if (!ret) {
-               m = (struct seq_file *)file->private_data;
-               iter = (struct ftrace_iterator *)m->private;
+               m = file->private_data;
+               iter = m->private;
                iter->flags = FTRACE_ITER_FAILURES;
        }
 
@@ -2418,7 +2455,7 @@ static const struct file_operations ftrace_filter_fops = {
        .open = ftrace_filter_open,
        .read = seq_read,
        .write = ftrace_filter_write,
-       .llseek = no_llseek,
+       .llseek = ftrace_regex_lseek,
        .release = ftrace_filter_release,
 };
 
index ad25490f8b4077e14016628230c21479f2596050..ec5c71005c14c6d6a0861ec9ff93fa4bd3a218e4 100644 (file)
@@ -2615,6 +2615,19 @@ void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu)
 }
 EXPORT_SYMBOL_GPL(ring_buffer_record_enable_cpu);
 
+/*
+ * The total entries in the ring buffer is the running counter
+ * of entries entered into the ring buffer, minus the sum of
+ * the entries read from the ring buffer and the number of
+ * entries that were overwritten.
+ */
+static inline unsigned long
+rb_num_of_entries(struct ring_buffer_per_cpu *cpu_buffer)
+{
+       return local_read(&cpu_buffer->entries) -
+               (local_read(&cpu_buffer->overrun) + cpu_buffer->read);
+}
+
 /**
  * ring_buffer_entries_cpu - get the number of entries in a cpu buffer
  * @buffer: The ring buffer
@@ -2623,16 +2636,13 @@ EXPORT_SYMBOL_GPL(ring_buffer_record_enable_cpu);
 unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu)
 {
        struct ring_buffer_per_cpu *cpu_buffer;
-       unsigned long ret;
 
        if (!cpumask_test_cpu(cpu, buffer->cpumask))
                return 0;
 
        cpu_buffer = buffer->buffers[cpu];
-       ret = (local_read(&cpu_buffer->entries) - local_read(&cpu_buffer->overrun))
-               - cpu_buffer->read;
 
-       return ret;
+       return rb_num_of_entries(cpu_buffer);
 }
 EXPORT_SYMBOL_GPL(ring_buffer_entries_cpu);
 
@@ -2693,8 +2703,7 @@ unsigned long ring_buffer_entries(struct ring_buffer *buffer)
        /* if you care about this being correct, lock the buffer */
        for_each_buffer_cpu(buffer, cpu) {
                cpu_buffer = buffer->buffers[cpu];
-               entries += (local_read(&cpu_buffer->entries) -
-                           local_read(&cpu_buffer->overrun)) - cpu_buffer->read;
+               entries += rb_num_of_entries(cpu_buffer);
        }
 
        return entries;
index 9ec59f541156625b5c4b0aea9267086c928ae07a..82d9b8106cd078970ea0c7343e12ad2b6a6eed36 100644 (file)
@@ -2196,7 +2196,7 @@ int tracing_open_generic(struct inode *inode, struct file *filp)
 
 static int tracing_release(struct inode *inode, struct file *file)
 {
-       struct seq_file *m = (struct seq_file *)file->private_data;
+       struct seq_file *m = file->private_data;
        struct trace_iterator *iter;
        int cpu;
 
@@ -3996,13 +3996,9 @@ static void tracing_init_debugfs_percpu(long cpu)
 {
        struct dentry *d_percpu = tracing_dentry_percpu();
        struct dentry *d_cpu;
-       /* strlen(cpu) + MAX(log10(cpu)) + '\0' */
-       char cpu_dir[7];
+       char cpu_dir[30]; /* 30 characters should be more than enough */
 
-       if (cpu > 999 || cpu < 0)
-               return;
-
-       sprintf(cpu_dir, "cpu%ld", cpu);
+       snprintf(cpu_dir, 30, "cpu%ld", cpu);
        d_cpu = debugfs_create_dir(cpu_dir, d_percpu);
        if (!d_cpu) {
                pr_warning("Could not create debugfs '%s' entry\n", cpu_dir);
index d39b3c5454a5e684b8c720e0791894b36529f1cf..9021f8c0c0c3e379edbd8f39770bd9345794e266 100644 (file)
@@ -343,6 +343,10 @@ void trace_function(struct trace_array *tr,
                    unsigned long ip,
                    unsigned long parent_ip,
                    unsigned long flags, int pc);
+void trace_graph_function(struct trace_array *tr,
+                   unsigned long ip,
+                   unsigned long parent_ip,
+                   unsigned long flags, int pc);
 void trace_default_header(struct seq_file *m);
 void print_trace_header(struct seq_file *m, struct trace_iterator *iter);
 int trace_empty(struct trace_iterator *iter);
index 31cc4cb0dbf2afaa49d5f7428f5cce31d535211d..39c059ca670e64156e6681782ffa708c6b8d720f 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/kprobes.h>
 #include "trace.h"
 
-static char *perf_trace_buf[4];
+static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS];
 
 /*
  * Force it to be aligned to unsigned long to avoid misaligned accesses
@@ -24,7 +24,7 @@ static int    total_ref_count;
 static int perf_trace_event_init(struct ftrace_event_call *tp_event,
                                 struct perf_event *p_event)
 {
-       struct hlist_head *list;
+       struct hlist_head __percpu *list;
        int ret = -ENOMEM;
        int cpu;
 
@@ -42,11 +42,11 @@ static int perf_trace_event_init(struct ftrace_event_call *tp_event,
        tp_event->perf_events = list;
 
        if (!total_ref_count) {
-               char *buf;
+               char __percpu *buf;
                int i;
 
-               for (i = 0; i < 4; i++) {
-                       buf = (char *)alloc_percpu(perf_trace_t);
+               for (i = 0; i < PERF_NR_CONTEXTS; i++) {
+                       buf = (char __percpu *)alloc_percpu(perf_trace_t);
                        if (!buf)
                                goto fail;
 
@@ -65,7 +65,7 @@ fail:
        if (!total_ref_count) {
                int i;
 
-               for (i = 0; i < 4; i++) {
+               for (i = 0; i < PERF_NR_CONTEXTS; i++) {
                        free_percpu(perf_trace_buf[i]);
                        perf_trace_buf[i] = NULL;
                }
@@ -101,22 +101,26 @@ int perf_trace_init(struct perf_event *p_event)
        return ret;
 }
 
-int perf_trace_enable(struct perf_event *p_event)
+int perf_trace_add(struct perf_event *p_event, int flags)
 {
        struct ftrace_event_call *tp_event = p_event->tp_event;
+       struct hlist_head __percpu *pcpu_list;
        struct hlist_head *list;
 
-       list = tp_event->perf_events;
-       if (WARN_ON_ONCE(!list))
+       pcpu_list = tp_event->perf_events;
+       if (WARN_ON_ONCE(!pcpu_list))
                return -EINVAL;
 
-       list = this_cpu_ptr(list);
+       if (!(flags & PERF_EF_START))
+               p_event->hw.state = PERF_HES_STOPPED;
+
+       list = this_cpu_ptr(pcpu_list);
        hlist_add_head_rcu(&p_event->hlist_entry, list);
 
        return 0;
 }
 
-void perf_trace_disable(struct perf_event *p_event)
+void perf_trace_del(struct perf_event *p_event, int flags)
 {
        hlist_del_rcu(&p_event->hlist_entry);
 }
@@ -142,7 +146,7 @@ void perf_trace_destroy(struct perf_event *p_event)
        tp_event->perf_events = NULL;
 
        if (!--total_ref_count) {
-               for (i = 0; i < 4; i++) {
+               for (i = 0; i < PERF_NR_CONTEXTS; i++) {
                        free_percpu(perf_trace_buf[i]);
                        perf_trace_buf[i] = NULL;
                }
index 4c758f146328f18ce82a318fb60a0413006aca8f..398c0e8b332c1840e16bc0599c1230f9594d29a2 100644 (file)
@@ -600,21 +600,29 @@ out:
 
 enum {
        FORMAT_HEADER           = 1,
-       FORMAT_PRINTFMT         = 2,
+       FORMAT_FIELD_SEPERATOR  = 2,
+       FORMAT_PRINTFMT         = 3,
 };
 
 static void *f_next(struct seq_file *m, void *v, loff_t *pos)
 {
        struct ftrace_event_call *call = m->private;
        struct ftrace_event_field *field;
-       struct list_head *head;
+       struct list_head *common_head = &ftrace_common_fields;
+       struct list_head *head = trace_get_fields(call);
 
        (*pos)++;
 
        switch ((unsigned long)v) {
        case FORMAT_HEADER:
-               head = &ftrace_common_fields;
+               if (unlikely(list_empty(common_head)))
+                       return NULL;
+
+               field = list_entry(common_head->prev,
+                                  struct ftrace_event_field, link);
+               return field;
 
+       case FORMAT_FIELD_SEPERATOR:
                if (unlikely(list_empty(head)))
                        return NULL;
 
@@ -626,31 +634,10 @@ static void *f_next(struct seq_file *m, void *v, loff_t *pos)
                return NULL;
        }
 
-       head = trace_get_fields(call);
-
-       /*
-        * To separate common fields from event fields, the
-        * LSB is set on the first event field. Clear it in case.
-        */
-       v = (void *)((unsigned long)v & ~1L);
-
        field = v;
-       /*
-        * If this is a common field, and at the end of the list, then
-        * continue with main list.
-        */
-       if (field->link.prev == &ftrace_common_fields) {
-               if (unlikely(list_empty(head)))
-                       return NULL;
-               field = list_entry(head->prev, struct ftrace_event_field, link);
-               /* Set the LSB to notify f_show to print an extra newline */
-               field = (struct ftrace_event_field *)
-                       ((unsigned long)field | 1);
-               return field;
-       }
-
-       /* If we are done tell f_show to print the format */
-       if (field->link.prev == head)
+       if (field->link.prev == common_head)
+               return (void *)FORMAT_FIELD_SEPERATOR;
+       else if (field->link.prev == head)
                return (void *)FORMAT_PRINTFMT;
 
        field = list_entry(field->link.prev, struct ftrace_event_field, link);
@@ -688,22 +675,16 @@ static int f_show(struct seq_file *m, void *v)
                seq_printf(m, "format:\n");
                return 0;
 
+       case FORMAT_FIELD_SEPERATOR:
+               seq_putc(m, '\n');
+               return 0;
+
        case FORMAT_PRINTFMT:
                seq_printf(m, "\nprint fmt: %s\n",
                           call->print_fmt);
                return 0;
        }
 
-       /*
-        * To separate common fields from event fields, the
-        * LSB is set on the first event field. Clear it and
-        * print a newline if it is set.
-        */
-       if ((unsigned long)v & 1) {
-               seq_putc(m, '\n');
-               v = (void *)((unsigned long)v & ~1L);
-       }
-
        field = v;
 
        /*
index 6f233698518ede15cc9302e889de9f108aa0f1cb..76b05980225cb79df8bfad7bb35cd64bd52bcaf2 100644 (file)
 #include "trace.h"
 #include "trace_output.h"
 
+/* When set, irq functions will be ignored */
+static int ftrace_graph_skip_irqs;
+
 struct fgraph_cpu_data {
        pid_t           last_pid;
        int             depth;
+       int             depth_irq;
        int             ignore;
        unsigned long   enter_funcs[FTRACE_RETFUNC_DEPTH];
 };
 
 struct fgraph_data {
-       struct fgraph_cpu_data          *cpu_data;
+       struct fgraph_cpu_data __percpu *cpu_data;
 
        /* Place to preserve last processed entry. */
        struct ftrace_graph_ent_entry   ent;
@@ -41,6 +45,7 @@ struct fgraph_data {
 #define TRACE_GRAPH_PRINT_PROC         0x8
 #define TRACE_GRAPH_PRINT_DURATION     0x10
 #define TRACE_GRAPH_PRINT_ABS_TIME     0x20
+#define TRACE_GRAPH_PRINT_IRQS         0x40
 
 static struct tracer_opt trace_opts[] = {
        /* Display overruns? (for self-debug purpose) */
@@ -55,13 +60,15 @@ static struct tracer_opt trace_opts[] = {
        { TRACER_OPT(funcgraph-duration, TRACE_GRAPH_PRINT_DURATION) },
        /* Display absolute time of an entry */
        { TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) },
+       /* Display interrupts */
+       { TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) },
        { } /* Empty entry */
 };
 
 static struct tracer_flags tracer_flags = {
        /* Don't display overruns and proc by default */
        .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD |
-              TRACE_GRAPH_PRINT_DURATION,
+              TRACE_GRAPH_PRINT_DURATION | TRACE_GRAPH_PRINT_IRQS,
        .opts = trace_opts
 };
 
@@ -204,6 +211,14 @@ int __trace_graph_entry(struct trace_array *tr,
        return 1;
 }
 
+static inline int ftrace_graph_ignore_irqs(void)
+{
+       if (!ftrace_graph_skip_irqs)
+               return 0;
+
+       return in_irq();
+}
+
 int trace_graph_entry(struct ftrace_graph_ent *trace)
 {
        struct trace_array *tr = graph_array;
@@ -218,7 +233,8 @@ int trace_graph_entry(struct ftrace_graph_ent *trace)
                return 0;
 
        /* trace it when it is-nested-in or is a function enabled. */
-       if (!(trace->depth || ftrace_graph_addr(trace->func)))
+       if (!(trace->depth || ftrace_graph_addr(trace->func)) ||
+             ftrace_graph_ignore_irqs())
                return 0;
 
        local_irq_save(flags);
@@ -246,6 +262,34 @@ int trace_graph_thresh_entry(struct ftrace_graph_ent *trace)
                return trace_graph_entry(trace);
 }
 
+static void
+__trace_graph_function(struct trace_array *tr,
+               unsigned long ip, unsigned long flags, int pc)
+{
+       u64 time = trace_clock_local();
+       struct ftrace_graph_ent ent = {
+               .func  = ip,
+               .depth = 0,
+       };
+       struct ftrace_graph_ret ret = {
+               .func     = ip,
+               .depth    = 0,
+               .calltime = time,
+               .rettime  = time,
+       };
+
+       __trace_graph_entry(tr, &ent, flags, pc);
+       __trace_graph_return(tr, &ret, flags, pc);
+}
+
+void
+trace_graph_function(struct trace_array *tr,
+               unsigned long ip, unsigned long parent_ip,
+               unsigned long flags, int pc)
+{
+       __trace_graph_function(tr, ip, flags, pc);
+}
+
 void __trace_graph_return(struct trace_array *tr,
                                struct ftrace_graph_ret *trace,
                                unsigned long flags,
@@ -649,8 +693,9 @@ trace_print_graph_duration(unsigned long long duration, struct trace_seq *s)
 
        /* Print nsecs (we don't want to exceed 7 numbers) */
        if (len < 7) {
-               snprintf(nsecs_str, min(sizeof(nsecs_str), 8UL - len), "%03lu",
-                        nsecs_rem);
+               size_t slen = min_t(size_t, sizeof(nsecs_str), 8UL - len);
+
+               snprintf(nsecs_str, slen, "%03lu", nsecs_rem);
                ret = trace_seq_printf(s, ".%s", nsecs_str);
                if (!ret)
                        return TRACE_TYPE_PARTIAL_LINE;
@@ -855,6 +900,108 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
        return 0;
 }
 
+/*
+ * Entry check for irq code
+ *
+ * returns 1 if
+ *  - we are inside irq code
+ *  - we just extered irq code
+ *
+ * retunns 0 if
+ *  - funcgraph-interrupts option is set
+ *  - we are not inside irq code
+ */
+static int
+check_irq_entry(struct trace_iterator *iter, u32 flags,
+               unsigned long addr, int depth)
+{
+       int cpu = iter->cpu;
+       int *depth_irq;
+       struct fgraph_data *data = iter->private;
+
+       /*
+        * If we are either displaying irqs, or we got called as
+        * a graph event and private data does not exist,
+        * then we bypass the irq check.
+        */
+       if ((flags & TRACE_GRAPH_PRINT_IRQS) ||
+           (!data))
+               return 0;
+
+       depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq);
+
+       /*
+        * We are inside the irq code
+        */
+       if (*depth_irq >= 0)
+               return 1;
+
+       if ((addr < (unsigned long)__irqentry_text_start) ||
+           (addr >= (unsigned long)__irqentry_text_end))
+               return 0;
+
+       /*
+        * We are entering irq code.
+        */
+       *depth_irq = depth;
+       return 1;
+}
+
+/*
+ * Return check for irq code
+ *
+ * returns 1 if
+ *  - we are inside irq code
+ *  - we just left irq code
+ *
+ * returns 0 if
+ *  - funcgraph-interrupts option is set
+ *  - we are not inside irq code
+ */
+static int
+check_irq_return(struct trace_iterator *iter, u32 flags, int depth)
+{
+       int cpu = iter->cpu;
+       int *depth_irq;
+       struct fgraph_data *data = iter->private;
+
+       /*
+        * If we are either displaying irqs, or we got called as
+        * a graph event and private data does not exist,
+        * then we bypass the irq check.
+        */
+       if ((flags & TRACE_GRAPH_PRINT_IRQS) ||
+           (!data))
+               return 0;
+
+       depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq);
+
+       /*
+        * We are not inside the irq code.
+        */
+       if (*depth_irq == -1)
+               return 0;
+
+       /*
+        * We are inside the irq code, and this is returning entry.
+        * Let's not trace it and clear the entry depth, since
+        * we are out of irq code.
+        *
+        * This condition ensures that we 'leave the irq code' once
+        * we are out of the entry depth. Thus protecting us from
+        * the RETURN entry loss.
+        */
+       if (*depth_irq >= depth) {
+               *depth_irq = -1;
+               return 1;
+       }
+
+       /*
+        * We are inside the irq code, and this is not the entry.
+        */
+       return 1;
+}
+
 static enum print_line_t
 print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
                        struct trace_iterator *iter, u32 flags)
@@ -865,6 +1012,9 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
        static enum print_line_t ret;
        int cpu = iter->cpu;
 
+       if (check_irq_entry(iter, flags, call->func, call->depth))
+               return TRACE_TYPE_HANDLED;
+
        if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags))
                return TRACE_TYPE_PARTIAL_LINE;
 
@@ -902,6 +1052,9 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
        int ret;
        int i;
 
+       if (check_irq_return(iter, flags, trace->depth))
+               return TRACE_TYPE_HANDLED;
+
        if (data) {
                struct fgraph_cpu_data *cpu_data;
                int cpu = iter->cpu;
@@ -1054,7 +1207,7 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
 
 
 enum print_line_t
-print_graph_function_flags(struct trace_iterator *iter, u32 flags)
+__print_graph_function_flags(struct trace_iterator *iter, u32 flags)
 {
        struct ftrace_graph_ent_entry *field;
        struct fgraph_data *data = iter->private;
@@ -1117,7 +1270,18 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags)
 static enum print_line_t
 print_graph_function(struct trace_iterator *iter)
 {
-       return print_graph_function_flags(iter, tracer_flags.val);
+       return __print_graph_function_flags(iter, tracer_flags.val);
+}
+
+enum print_line_t print_graph_function_flags(struct trace_iterator *iter,
+                                            u32 flags)
+{
+       if (trace_flags & TRACE_ITER_LATENCY_FMT)
+               flags |= TRACE_GRAPH_PRINT_DURATION;
+       else
+               flags |= TRACE_GRAPH_PRINT_ABS_TIME;
+
+       return __print_graph_function_flags(iter, flags);
 }
 
 static enum print_line_t
@@ -1149,7 +1313,7 @@ static void print_lat_header(struct seq_file *s, u32 flags)
        seq_printf(s, "#%.*s|||| /                     \n", size, spaces);
 }
 
-void print_graph_headers_flags(struct seq_file *s, u32 flags)
+static void __print_graph_headers_flags(struct seq_file *s, u32 flags)
 {
        int lat = trace_flags & TRACE_ITER_LATENCY_FMT;
 
@@ -1190,6 +1354,23 @@ void print_graph_headers(struct seq_file *s)
        print_graph_headers_flags(s, tracer_flags.val);
 }
 
+void print_graph_headers_flags(struct seq_file *s, u32 flags)
+{
+       struct trace_iterator *iter = s->private;
+
+       if (trace_flags & TRACE_ITER_LATENCY_FMT) {
+               /* print nothing if the buffers are empty */
+               if (trace_empty(iter))
+                       return;
+
+               print_trace_header(s, iter);
+               flags |= TRACE_GRAPH_PRINT_DURATION;
+       } else
+               flags |= TRACE_GRAPH_PRINT_ABS_TIME;
+
+       __print_graph_headers_flags(s, flags);
+}
+
 void graph_trace_open(struct trace_iterator *iter)
 {
        /* pid and depth on the last trace processed */
@@ -1210,9 +1391,12 @@ void graph_trace_open(struct trace_iterator *iter)
                pid_t *pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid);
                int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth);
                int *ignore = &(per_cpu_ptr(data->cpu_data, cpu)->ignore);
+               int *depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq);
+
                *pid = -1;
                *depth = 0;
                *ignore = 0;
+               *depth_irq = -1;
        }
 
        iter->private = data;
@@ -1235,6 +1419,14 @@ void graph_trace_close(struct trace_iterator *iter)
        }
 }
 
+static int func_graph_set_flag(u32 old_flags, u32 bit, int set)
+{
+       if (bit == TRACE_GRAPH_PRINT_IRQS)
+               ftrace_graph_skip_irqs = !set;
+
+       return 0;
+}
+
 static struct trace_event_functions graph_functions = {
        .trace          = print_graph_function_event,
 };
@@ -1261,6 +1453,7 @@ static struct tracer graph_trace __read_mostly = {
        .print_line     = print_graph_function,
        .print_header   = print_graph_headers,
        .flags          = &tracer_flags,
+       .set_flag       = func_graph_set_flag,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest       = trace_selftest_startup_function_graph,
 #endif
index 73a6b0601f2e301c0cd5575cc96f7f0b788853d9..5cf8c602b8804c054bbed65475b4815fd29d5b82 100644 (file)
@@ -87,14 +87,22 @@ static __cacheline_aligned_in_smp   unsigned long max_sequence;
 
 #ifdef CONFIG_FUNCTION_TRACER
 /*
- * irqsoff uses its own tracer function to keep the overhead down:
+ * Prologue for the preempt and irqs off function tracers.
+ *
+ * Returns 1 if it is OK to continue, and data->disabled is
+ *            incremented.
+ *         0 if the trace is to be ignored, and data->disabled
+ *            is kept the same.
+ *
+ * Note, this function is also used outside this ifdef but
+ *  inside the #ifdef of the function graph tracer below.
+ *  This is OK, since the function graph tracer is
+ *  dependent on the function tracer.
  */
-static void
-irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip)
+static int func_prolog_dec(struct trace_array *tr,
+                          struct trace_array_cpu **data,
+                          unsigned long *flags)
 {
-       struct trace_array *tr = irqsoff_trace;
-       struct trace_array_cpu *data;
-       unsigned long flags;
        long disabled;
        int cpu;
 
@@ -106,18 +114,38 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip)
         */
        cpu = raw_smp_processor_id();
        if (likely(!per_cpu(tracing_cpu, cpu)))
-               return;
+               return 0;
 
-       local_save_flags(flags);
+       local_save_flags(*flags);
        /* slight chance to get a false positive on tracing_cpu */
-       if (!irqs_disabled_flags(flags))
-               return;
+       if (!irqs_disabled_flags(*flags))
+               return 0;
 
-       data = tr->data[cpu];
-       disabled = atomic_inc_return(&data->disabled);
+       *data = tr->data[cpu];
+       disabled = atomic_inc_return(&(*data)->disabled);
 
        if (likely(disabled == 1))
-               trace_function(tr, ip, parent_ip, flags, preempt_count());
+               return 1;
+
+       atomic_dec(&(*data)->disabled);
+
+       return 0;
+}
+
+/*
+ * irqsoff uses its own tracer function to keep the overhead down:
+ */
+static void
+irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip)
+{
+       struct trace_array *tr = irqsoff_trace;
+       struct trace_array_cpu *data;
+       unsigned long flags;
+
+       if (!func_prolog_dec(tr, &data, &flags))
+               return;
+
+       trace_function(tr, ip, parent_ip, flags, preempt_count());
 
        atomic_dec(&data->disabled);
 }
@@ -155,30 +183,16 @@ static int irqsoff_graph_entry(struct ftrace_graph_ent *trace)
        struct trace_array *tr = irqsoff_trace;
        struct trace_array_cpu *data;
        unsigned long flags;
-       long disabled;
        int ret;
-       int cpu;
        int pc;
 
-       cpu = raw_smp_processor_id();
-       if (likely(!per_cpu(tracing_cpu, cpu)))
+       if (!func_prolog_dec(tr, &data, &flags))
                return 0;
 
-       local_save_flags(flags);
-       /* slight chance to get a false positive on tracing_cpu */
-       if (!irqs_disabled_flags(flags))
-               return 0;
-
-       data = tr->data[cpu];
-       disabled = atomic_inc_return(&data->disabled);
-
-       if (likely(disabled == 1)) {
-               pc = preempt_count();
-               ret = __trace_graph_entry(tr, trace, flags, pc);
-       } else
-               ret = 0;
-
+       pc = preempt_count();
+       ret = __trace_graph_entry(tr, trace, flags, pc);
        atomic_dec(&data->disabled);
+
        return ret;
 }
 
@@ -187,27 +201,13 @@ static void irqsoff_graph_return(struct ftrace_graph_ret *trace)
        struct trace_array *tr = irqsoff_trace;
        struct trace_array_cpu *data;
        unsigned long flags;
-       long disabled;
-       int cpu;
        int pc;
 
-       cpu = raw_smp_processor_id();
-       if (likely(!per_cpu(tracing_cpu, cpu)))
+       if (!func_prolog_dec(tr, &data, &flags))
                return;
 
-       local_save_flags(flags);
-       /* slight chance to get a false positive on tracing_cpu */
-       if (!irqs_disabled_flags(flags))
-               return;
-
-       data = tr->data[cpu];
-       disabled = atomic_inc_return(&data->disabled);
-
-       if (likely(disabled == 1)) {
-               pc = preempt_count();
-               __trace_graph_return(tr, trace, flags, pc);
-       }
-
+       pc = preempt_count();
+       __trace_graph_return(tr, trace, flags, pc);
        atomic_dec(&data->disabled);
 }
 
@@ -229,75 +229,33 @@ static void irqsoff_trace_close(struct trace_iterator *iter)
 
 static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
 {
-       u32 flags = GRAPH_TRACER_FLAGS;
-
-       if (trace_flags & TRACE_ITER_LATENCY_FMT)
-               flags |= TRACE_GRAPH_PRINT_DURATION;
-       else
-               flags |= TRACE_GRAPH_PRINT_ABS_TIME;
-
        /*
         * In graph mode call the graph tracer output function,
         * otherwise go with the TRACE_FN event handler
         */
        if (is_graph())
-               return print_graph_function_flags(iter, flags);
+               return print_graph_function_flags(iter, GRAPH_TRACER_FLAGS);
 
        return TRACE_TYPE_UNHANDLED;
 }
 
 static void irqsoff_print_header(struct seq_file *s)
 {
-       if (is_graph()) {
-               struct trace_iterator *iter = s->private;
-               u32 flags = GRAPH_TRACER_FLAGS;
-
-               if (trace_flags & TRACE_ITER_LATENCY_FMT) {
-                       /* print nothing if the buffers are empty */
-                       if (trace_empty(iter))
-                               return;
-
-                       print_trace_header(s, iter);
-                       flags |= TRACE_GRAPH_PRINT_DURATION;
-               } else
-                       flags |= TRACE_GRAPH_PRINT_ABS_TIME;
-
-               print_graph_headers_flags(s, flags);
-       } else
+       if (is_graph())
+               print_graph_headers_flags(s, GRAPH_TRACER_FLAGS);
+       else
                trace_default_header(s);
 }
 
-static void
-trace_graph_function(struct trace_array *tr,
-                unsigned long ip, unsigned long flags, int pc)
-{
-       u64 time = trace_clock_local();
-       struct ftrace_graph_ent ent = {
-               .func  = ip,
-               .depth = 0,
-       };
-       struct ftrace_graph_ret ret = {
-               .func     = ip,
-               .depth    = 0,
-               .calltime = time,
-               .rettime  = time,
-       };
-
-       __trace_graph_entry(tr, &ent, flags, pc);
-       __trace_graph_return(tr, &ret, flags, pc);
-}
-
 static void
 __trace_function(struct trace_array *tr,
                 unsigned long ip, unsigned long parent_ip,
                 unsigned long flags, int pc)
 {
-       if (!is_graph())
+       if (is_graph())
+               trace_graph_function(tr, ip, parent_ip, flags, pc);
+       else
                trace_function(tr, ip, parent_ip, flags, pc);
-       else {
-               trace_graph_function(tr, parent_ip, flags, pc);
-               trace_graph_function(tr, ip, flags, pc);
-       }
 }
 
 #else
index 544301d29dee45b0dc089db788bcfe89687bfa45..b8d2852baa4abe7368e0aa50c294cc6a6137855a 100644 (file)
@@ -648,7 +648,7 @@ static int register_trace_probe(struct trace_probe *tp)
        }
        ret = register_probe_event(tp);
        if (ret) {
-               pr_warning("Faild to register probe event(%d)\n", ret);
+               pr_warning("Failed to register probe event(%d)\n", ret);
                goto end;
        }
 
index 4086eae6e81b1c1b9762edc01600d3294c6bc130..7319559ed59f0a10197a15dc9d62a99a1fa7aeb7 100644 (file)
@@ -31,48 +31,98 @@ static int                  wakeup_rt;
 static arch_spinlock_t wakeup_lock =
        (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED;
 
+static void wakeup_reset(struct trace_array *tr);
 static void __wakeup_reset(struct trace_array *tr);
+static int wakeup_graph_entry(struct ftrace_graph_ent *trace);
+static void wakeup_graph_return(struct ftrace_graph_ret *trace);
 
 static int save_lat_flag;
 
+#define TRACE_DISPLAY_GRAPH     1
+
+static struct tracer_opt trace_opts[] = {
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+       /* display latency trace as call graph */
+       { TRACER_OPT(display-graph, TRACE_DISPLAY_GRAPH) },
+#endif
+       { } /* Empty entry */
+};
+
+static struct tracer_flags tracer_flags = {
+       .val  = 0,
+       .opts = trace_opts,
+};
+
+#define is_graph() (tracer_flags.val & TRACE_DISPLAY_GRAPH)
+
 #ifdef CONFIG_FUNCTION_TRACER
+
 /*
- * irqsoff uses its own tracer function to keep the overhead down:
+ * Prologue for the wakeup function tracers.
+ *
+ * Returns 1 if it is OK to continue, and preemption
+ *            is disabled and data->disabled is incremented.
+ *         0 if the trace is to be ignored, and preemption
+ *            is not disabled and data->disabled is
+ *            kept the same.
+ *
+ * Note, this function is also used outside this ifdef but
+ *  inside the #ifdef of the function graph tracer below.
+ *  This is OK, since the function graph tracer is
+ *  dependent on the function tracer.
  */
-static void
-wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
+static int
+func_prolog_preempt_disable(struct trace_array *tr,
+                           struct trace_array_cpu **data,
+                           int *pc)
 {
-       struct trace_array *tr = wakeup_trace;
-       struct trace_array_cpu *data;
-       unsigned long flags;
        long disabled;
        int cpu;
-       int pc;
 
        if (likely(!wakeup_task))
-               return;
+               return 0;
 
-       pc = preempt_count();
+       *pc = preempt_count();
        preempt_disable_notrace();
 
        cpu = raw_smp_processor_id();
        if (cpu != wakeup_current_cpu)
                goto out_enable;
 
-       data = tr->data[cpu];
-       disabled = atomic_inc_return(&data->disabled);
+       *data = tr->data[cpu];
+       disabled = atomic_inc_return(&(*data)->disabled);
        if (unlikely(disabled != 1))
                goto out;
 
-       local_irq_save(flags);
+       return 1;
 
-       trace_function(tr, ip, parent_ip, flags, pc);
+out:
+       atomic_dec(&(*data)->disabled);
+
+out_enable:
+       preempt_enable_notrace();
+       return 0;
+}
 
+/*
+ * wakeup uses its own tracer function to keep the overhead down:
+ */
+static void
+wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
+{
+       struct trace_array *tr = wakeup_trace;
+       struct trace_array_cpu *data;
+       unsigned long flags;
+       int pc;
+
+       if (!func_prolog_preempt_disable(tr, &data, &pc))
+               return;
+
+       local_irq_save(flags);
+       trace_function(tr, ip, parent_ip, flags, pc);
        local_irq_restore(flags);
 
- out:
        atomic_dec(&data->disabled);
- out_enable:
        preempt_enable_notrace();
 }
 
@@ -82,6 +132,156 @@ static struct ftrace_ops trace_ops __read_mostly =
 };
 #endif /* CONFIG_FUNCTION_TRACER */
 
+static int start_func_tracer(int graph)
+{
+       int ret;
+
+       if (!graph)
+               ret = register_ftrace_function(&trace_ops);
+       else
+               ret = register_ftrace_graph(&wakeup_graph_return,
+                                           &wakeup_graph_entry);
+
+       if (!ret && tracing_is_enabled())
+               tracer_enabled = 1;
+       else
+               tracer_enabled = 0;
+
+       return ret;
+}
+
+static void stop_func_tracer(int graph)
+{
+       tracer_enabled = 0;
+
+       if (!graph)
+               unregister_ftrace_function(&trace_ops);
+       else
+               unregister_ftrace_graph();
+}
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+static int wakeup_set_flag(u32 old_flags, u32 bit, int set)
+{
+
+       if (!(bit & TRACE_DISPLAY_GRAPH))
+               return -EINVAL;
+
+       if (!(is_graph() ^ set))
+               return 0;
+
+       stop_func_tracer(!set);
+
+       wakeup_reset(wakeup_trace);
+       tracing_max_latency = 0;
+
+       return start_func_tracer(set);
+}
+
+static int wakeup_graph_entry(struct ftrace_graph_ent *trace)
+{
+       struct trace_array *tr = wakeup_trace;
+       struct trace_array_cpu *data;
+       unsigned long flags;
+       int pc, ret = 0;
+
+       if (!func_prolog_preempt_disable(tr, &data, &pc))
+               return 0;
+
+       local_save_flags(flags);
+       ret = __trace_graph_entry(tr, trace, flags, pc);
+       atomic_dec(&data->disabled);
+       preempt_enable_notrace();
+
+       return ret;
+}
+
+static void wakeup_graph_return(struct ftrace_graph_ret *trace)
+{
+       struct trace_array *tr = wakeup_trace;
+       struct trace_array_cpu *data;
+       unsigned long flags;
+       int pc;
+
+       if (!func_prolog_preempt_disable(tr, &data, &pc))
+               return;
+
+       local_save_flags(flags);
+       __trace_graph_return(tr, trace, flags, pc);
+       atomic_dec(&data->disabled);
+
+       preempt_enable_notrace();
+       return;
+}
+
+static void wakeup_trace_open(struct trace_iterator *iter)
+{
+       if (is_graph())
+               graph_trace_open(iter);
+}
+
+static void wakeup_trace_close(struct trace_iterator *iter)
+{
+       if (iter->private)
+               graph_trace_close(iter);
+}
+
+#define GRAPH_TRACER_FLAGS (TRACE_GRAPH_PRINT_PROC)
+
+static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
+{
+       /*
+        * In graph mode call the graph tracer output function,
+        * otherwise go with the TRACE_FN event handler
+        */
+       if (is_graph())
+               return print_graph_function_flags(iter, GRAPH_TRACER_FLAGS);
+
+       return TRACE_TYPE_UNHANDLED;
+}
+
+static void wakeup_print_header(struct seq_file *s)
+{
+       if (is_graph())
+               print_graph_headers_flags(s, GRAPH_TRACER_FLAGS);
+       else
+               trace_default_header(s);
+}
+
+static void
+__trace_function(struct trace_array *tr,
+                unsigned long ip, unsigned long parent_ip,
+                unsigned long flags, int pc)
+{
+       if (is_graph())
+               trace_graph_function(tr, ip, parent_ip, flags, pc);
+       else
+               trace_function(tr, ip, parent_ip, flags, pc);
+}
+#else
+#define __trace_function trace_function
+
+static int wakeup_set_flag(u32 old_flags, u32 bit, int set)
+{
+       return -EINVAL;
+}
+
+static int wakeup_graph_entry(struct ftrace_graph_ent *trace)
+{
+       return -1;
+}
+
+static enum print_line_t wakeup_print_line(struct trace_iterator *iter)
+{
+       return TRACE_TYPE_UNHANDLED;
+}
+
+static void wakeup_graph_return(struct ftrace_graph_ret *trace) { }
+static void wakeup_print_header(struct seq_file *s) { }
+static void wakeup_trace_open(struct trace_iterator *iter) { }
+static void wakeup_trace_close(struct trace_iterator *iter) { }
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
 /*
  * Should this new latency be reported/recorded?
  */
@@ -152,7 +352,7 @@ probe_wakeup_sched_switch(void *ignore,
        /* The task we are waiting for is waking up */
        data = wakeup_trace->data[wakeup_cpu];
 
-       trace_function(wakeup_trace, CALLER_ADDR0, CALLER_ADDR1, flags, pc);
+       __trace_function(wakeup_trace, CALLER_ADDR0, CALLER_ADDR1, flags, pc);
        tracing_sched_switch_trace(wakeup_trace, prev, next, flags, pc);
 
        T0 = data->preempt_timestamp;
@@ -252,7 +452,7 @@ probe_wakeup(void *ignore, struct task_struct *p, int success)
         * is not called by an assembly function  (where as schedule is)
         * it should be safe to use it here.
         */
-       trace_function(wakeup_trace, CALLER_ADDR1, CALLER_ADDR2, flags, pc);
+       __trace_function(wakeup_trace, CALLER_ADDR1, CALLER_ADDR2, flags, pc);
 
 out_locked:
        arch_spin_unlock(&wakeup_lock);
@@ -303,12 +503,8 @@ static void start_wakeup_tracer(struct trace_array *tr)
         */
        smp_wmb();
 
-       register_ftrace_function(&trace_ops);
-
-       if (tracing_is_enabled())
-               tracer_enabled = 1;
-       else
-               tracer_enabled = 0;
+       if (start_func_tracer(is_graph()))
+               printk(KERN_ERR "failed to start wakeup tracer\n");
 
        return;
 fail_deprobe_wake_new:
@@ -320,7 +516,7 @@ fail_deprobe:
 static void stop_wakeup_tracer(struct trace_array *tr)
 {
        tracer_enabled = 0;
-       unregister_ftrace_function(&trace_ops);
+       stop_func_tracer(is_graph());
        unregister_trace_sched_switch(probe_wakeup_sched_switch, NULL);
        unregister_trace_sched_wakeup_new(probe_wakeup, NULL);
        unregister_trace_sched_wakeup(probe_wakeup, NULL);
@@ -379,9 +575,15 @@ static struct tracer wakeup_tracer __read_mostly =
        .start          = wakeup_tracer_start,
        .stop           = wakeup_tracer_stop,
        .print_max      = 1,
+       .print_header   = wakeup_print_header,
+       .print_line     = wakeup_print_line,
+       .flags          = &tracer_flags,
+       .set_flag       = wakeup_set_flag,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_wakeup,
 #endif
+       .open           = wakeup_trace_open,
+       .close          = wakeup_trace_close,
        .use_max_tr     = 1,
 };
 
@@ -394,9 +596,15 @@ static struct tracer wakeup_rt_tracer __read_mostly =
        .stop           = wakeup_tracer_stop,
        .wait_pipe      = poll_wait_pipe,
        .print_max      = 1,
+       .print_header   = wakeup_print_header,
+       .print_line     = wakeup_print_line,
+       .flags          = &tracer_flags,
+       .set_flag       = wakeup_set_flag,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_wakeup,
 #endif
+       .open           = wakeup_trace_open,
+       .close          = wakeup_trace_close,
        .use_max_tr     = 1,
 };
 
index a7cc3793baf6897d2535737a52322552040d2737..209b379a47210dad4170e5914e5ecc68207f8784 100644 (file)
@@ -263,6 +263,11 @@ int __init trace_workqueue_early_init(void)
 {
        int ret, cpu;
 
+       for_each_possible_cpu(cpu) {
+               spin_lock_init(&workqueue_cpu_stat(cpu)->lock);
+               INIT_LIST_HEAD(&workqueue_cpu_stat(cpu)->list);
+       }
+
        ret = register_trace_workqueue_insertion(probe_workqueue_insertion, NULL);
        if (ret)
                goto out;
@@ -279,11 +284,6 @@ int __init trace_workqueue_early_init(void)
        if (ret)
                goto no_creation;
 
-       for_each_possible_cpu(cpu) {
-               spin_lock_init(&workqueue_cpu_stat(cpu)->lock);
-               INIT_LIST_HEAD(&workqueue_cpu_stat(cpu)->list);
-       }
-
        return 0;
 
 no_creation:
index c77f3eceea250e49b0ff001959f8df9eeb8e0716..e95ee7f31d43309949893d9e63d1703e619a6ca9 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/jump_label.h>
 
 extern struct tracepoint __start___tracepoints[];
 extern struct tracepoint __stop___tracepoints[];
@@ -263,7 +264,13 @@ static void set_tracepoint(struct tracepoint_entry **entry,
         * is used.
         */
        rcu_assign_pointer(elem->funcs, (*entry)->funcs);
-       elem->state = active;
+       if (!elem->state && active) {
+               jump_label_enable(&elem->state);
+               elem->state = active;
+       } else if (elem->state && !active) {
+               jump_label_disable(&elem->state);
+               elem->state = active;
+       }
 }
 
 /*
@@ -277,7 +284,10 @@ static void disable_tracepoint(struct tracepoint *elem)
        if (elem->unregfunc && elem->state)
                elem->unregfunc();
 
-       elem->state = 0;
+       if (elem->state) {
+               jump_label_disable(&elem->state);
+               elem->state = 0;
+       }
        rcu_assign_pointer(elem->funcs, NULL);
 }
 
index 7f9c3c52ecc12ef5d0de1728839218ff87c2dc7b..bafba687a6d849a11f0201acd3d7ae5e63e9301e 100644 (file)
@@ -43,7 +43,6 @@ static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
 static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
 #endif
 
-static int __read_mostly did_panic;
 static int __initdata no_watchdog;
 
 
@@ -187,18 +186,6 @@ static int is_softlockup(unsigned long touch_ts)
        return 0;
 }
 
-static int
-watchdog_panic(struct notifier_block *this, unsigned long event, void *ptr)
-{
-       did_panic = 1;
-
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block panic_block = {
-       .notifier_call = watchdog_panic,
-};
-
 #ifdef CONFIG_HARDLOCKUP_DETECTOR
 static struct perf_event_attr wd_hw_attr = {
        .type           = PERF_TYPE_HARDWARE,
@@ -209,7 +196,7 @@ static struct perf_event_attr wd_hw_attr = {
 };
 
 /* Callback function for perf event subsystem */
-void watchdog_overflow_callback(struct perf_event *event, int nmi,
+static void watchdog_overflow_callback(struct perf_event *event, int nmi,
                 struct perf_sample_data *data,
                 struct pt_regs *regs)
 {
@@ -371,14 +358,14 @@ static int watchdog_nmi_enable(int cpu)
        /* Try to register using hardware perf events */
        wd_attr = &wd_hw_attr;
        wd_attr->sample_period = hw_nmi_get_sample_period();
-       event = perf_event_create_kernel_counter(wd_attr, cpu, -1, watchdog_overflow_callback);
+       event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback);
        if (!IS_ERR(event)) {
                printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n");
                goto out_save;
        }
 
        printk(KERN_ERR "NMI watchdog failed to create perf event on cpu%i: %p\n", cpu, event);
-       return -1;
+       return PTR_ERR(event);
 
        /* success path */
 out_save:
@@ -422,17 +409,19 @@ static int watchdog_prepare_cpu(int cpu)
 static int watchdog_enable(int cpu)
 {
        struct task_struct *p = per_cpu(softlockup_watchdog, cpu);
+       int err;
 
        /* enable the perf event */
-       if (watchdog_nmi_enable(cpu) != 0)
-               return -1;
+       err = watchdog_nmi_enable(cpu);
+       if (err)
+               return err;
 
        /* create the watchdog thread */
        if (!p) {
                p = kthread_create(watchdog, (void *)(unsigned long)cpu, "watchdog/%d", cpu);
                if (IS_ERR(p)) {
                        printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu);
-                       return -1;
+                       return PTR_ERR(p);
                }
                kthread_bind(p, cpu);
                per_cpu(watchdog_touch_ts, cpu) = 0;
@@ -484,6 +473,9 @@ static void watchdog_disable_all_cpus(void)
 {
        int cpu;
 
+       if (no_watchdog)
+               return;
+
        for_each_online_cpu(cpu)
                watchdog_disable(cpu);
 
@@ -526,17 +518,16 @@ static int __cpuinit
 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
+       int err = 0;
 
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               if (watchdog_prepare_cpu(hotcpu))
-                       return NOTIFY_BAD;
+               err = watchdog_prepare_cpu(hotcpu);
                break;
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
-               if (watchdog_enable(hotcpu))
-                       return NOTIFY_BAD;
+               err = watchdog_enable(hotcpu);
                break;
 #ifdef CONFIG_HOTPLUG_CPU
        case CPU_UP_CANCELED:
@@ -549,7 +540,7 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
                break;
 #endif /* CONFIG_HOTPLUG_CPU */
        }
-       return NOTIFY_OK;
+       return notifier_from_errno(err);
 }
 
 static struct notifier_block __cpuinitdata cpu_nfb = {
@@ -565,13 +556,11 @@ static int __init spawn_watchdog_task(void)
                return 0;
 
        err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
-       WARN_ON(err == NOTIFY_BAD);
+       WARN_ON(notifier_to_errno(err));
 
        cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
        register_cpu_notifier(&cpu_nfb);
 
-       atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
-
        return 0;
 }
 early_initcall(spawn_watchdog_task);
index 1b4afd2e6ca089de0babdacc5781426ef118da5c..21ac83070a805030150bab1a229be48c3f79485a 100644 (file)
@@ -482,6 +482,7 @@ config PROVE_LOCKING
        select DEBUG_SPINLOCK
        select DEBUG_MUTEXES
        select DEBUG_LOCK_ALLOC
+       select TRACE_IRQFLAGS
        default n
        help
         This feature enables the kernel to prove that all locking
@@ -539,6 +540,23 @@ config PROVE_RCU_REPEATEDLY
         disabling, allowing multiple RCU-lockdep warnings to be printed
         on a single reboot.
 
+        Say Y to allow multiple RCU-lockdep warnings per boot.
+
+        Say N if you are unsure.
+
+config SPARSE_RCU_POINTER
+       bool "RCU debugging: sparse-based checks for pointer usage"
+       default n
+       help
+        This feature enables the __rcu sparse annotation for
+        RCU-protected pointers.  This annotation will cause sparse
+        to flag any non-RCU used of annotated pointers.  This can be
+        helpful when debugging RCU usage.  Please note that this feature
+        is not intended to enforce code cleanliness; it is instead merely
+        a debugging aid.
+
+        Say Y to make sparse flag questionable use of RCU-protected pointers
+
         Say N if you are unsure.
 
 config LOCKDEP
@@ -579,11 +597,10 @@ config DEBUG_LOCKDEP
          of more runtime overhead.
 
 config TRACE_IRQFLAGS
-       depends on DEBUG_KERNEL
        bool
-       default y
-       depends on TRACE_IRQFLAGS_SUPPORT
-       depends on PROVE_LOCKING
+       help
+         Enables hooks to interrupt enabling and disabling for
+         either tracing or lock debugging.
 
 config DEBUG_SPINLOCK_SLEEP
        bool "Spinlock debugging: sleep-inside-spinlock checking"
@@ -832,6 +849,30 @@ config RCU_CPU_STALL_DETECTOR
 
          Say Y if you are unsure.
 
+config RCU_CPU_STALL_TIMEOUT
+       int "RCU CPU stall timeout in seconds"
+       depends on RCU_CPU_STALL_DETECTOR
+       range 3 300
+       default 60
+       help
+         If a given RCU grace period extends more than the specified
+         number of seconds, a CPU stall warning is printed.  If the
+         RCU grace period persists, additional CPU stall warnings are
+         printed at more widely spaced intervals.
+
+config RCU_CPU_STALL_DETECTOR_RUNNABLE
+       bool "RCU CPU stall checking starts automatically at boot"
+       depends on RCU_CPU_STALL_DETECTOR
+       default y
+       help
+         If set, start checking for RCU CPU stalls immediately on
+         boot.  Otherwise, RCU CPU stall checking must be manually
+         enabled.
+
+         Say Y if you are unsure.
+
+         Say N if you wish to suppress RCU CPU stall checking during boot.
+
 config RCU_CPU_STALL_VERBOSE
        bool "Print additional per-task information for RCU_CPU_STALL_DETECTOR"
        depends on RCU_CPU_STALL_DETECTOR && TREE_PREEMPT_RCU
index 02afc25337284329d23a998e636240d5a41d337d..7bd6df781ce50198689fae375eef696751c0a47a 100644 (file)
 #include <linux/dynamic_debug.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
+#include <linux/jump_label.h>
 
 extern struct _ddebug __start___verbose[];
 extern struct _ddebug __stop___verbose[];
 
-/* dynamic_debug_enabled, and dynamic_debug_enabled2 are bitmasks in which
- * bit n is set to 1 if any modname hashes into the bucket n, 0 otherwise. They
- * use independent hash functions, to reduce the chance of false positives.
- */
-long long dynamic_debug_enabled;
-EXPORT_SYMBOL_GPL(dynamic_debug_enabled);
-long long dynamic_debug_enabled2;
-EXPORT_SYMBOL_GPL(dynamic_debug_enabled2);
-
 struct ddebug_table {
        struct list_head link;
        char *mod_name;
@@ -87,26 +79,6 @@ static char *ddebug_describe_flags(struct _ddebug *dp, char *buf,
        return buf;
 }
 
-/*
- * must be called with ddebug_lock held
- */
-
-static int disabled_hash(char hash, bool first_table)
-{
-       struct ddebug_table *dt;
-       char table_hash_value;
-
-       list_for_each_entry(dt, &ddebug_tables, link) {
-               if (first_table)
-                       table_hash_value = dt->ddebugs->primary_hash;
-               else
-                       table_hash_value = dt->ddebugs->secondary_hash;
-               if (dt->num_enabled && (hash == table_hash_value))
-                       return 0;
-       }
-       return 1;
-}
-
 /*
  * Search the tables for _ddebug's which match the given
  * `query' and apply the `flags' and `mask' to them.  Tells
@@ -170,17 +142,9 @@ static void ddebug_change(const struct ddebug_query *query,
                                dt->num_enabled++;
                        dp->flags = newflags;
                        if (newflags) {
-                               dynamic_debug_enabled |=
-                                               (1LL << dp->primary_hash);
-                               dynamic_debug_enabled2 |=
-                                               (1LL << dp->secondary_hash);
+                               jump_label_enable(&dp->enabled);
                        } else {
-                               if (disabled_hash(dp->primary_hash, true))
-                                       dynamic_debug_enabled &=
-                                               ~(1LL << dp->primary_hash);
-                               if (disabled_hash(dp->secondary_hash, false))
-                                       dynamic_debug_enabled2 &=
-                                               ~(1LL << dp->secondary_hash);
+                               jump_label_disable(&dp->enabled);
                        }
                        if (verbose)
                                printk(KERN_INFO
index efd16fa80b1cfd55f2e1f1295f1cd45765925abf..6f412ab4c24f812fc8b7290c4a1e06cc0250ea62 100644 (file)
@@ -49,7 +49,7 @@ struct radix_tree_node {
        unsigned int    height;         /* Height from the bottom */
        unsigned int    count;
        struct rcu_head rcu_head;
-       void            *slots[RADIX_TREE_MAP_SIZE];
+       void __rcu      *slots[RADIX_TREE_MAP_SIZE];
        unsigned long   tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
 };
 
index 34e3082632d8311575e27c6d2a4b87c9985dd574..7c06ee51a29a9bfbf79692af3b7e211751005e3c 100644 (file)
@@ -70,7 +70,7 @@ static unsigned long io_tlb_nslabs;
  */
 static unsigned long io_tlb_overflow = 32*1024;
 
-void *io_tlb_overflow_buffer;
+static void *io_tlb_overflow_buffer;
 
 /*
  * This is a free list describing the number of free entries available from
@@ -147,16 +147,16 @@ void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
         * to find contiguous free memory regions of size up to IO_TLB_SEGSIZE
         * between io_tlb_start and io_tlb_end.
         */
-       io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int));
+       io_tlb_list = alloc_bootmem_pages(PAGE_ALIGN(io_tlb_nslabs * sizeof(int)));
        for (i = 0; i < io_tlb_nslabs; i++)
                io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
        io_tlb_index = 0;
-       io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(phys_addr_t));
+       io_tlb_orig_addr = alloc_bootmem_pages(PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)));
 
        /*
         * Get the overflow emergency buffer
         */
-       io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow);
+       io_tlb_overflow_buffer = alloc_bootmem_low_pages(PAGE_ALIGN(io_tlb_overflow));
        if (!io_tlb_overflow_buffer)
                panic("Cannot allocate SWIOTLB overflow buffer!\n");
        if (verbose)
@@ -182,7 +182,7 @@ swiotlb_init_with_default_size(size_t default_size, int verbose)
        /*
         * Get IO TLB memory from the low pages
         */
-       io_tlb_start = alloc_bootmem_low_pages(bytes);
+       io_tlb_start = alloc_bootmem_low_pages(PAGE_ALIGN(bytes));
        if (!io_tlb_start)
                panic("Cannot allocate SWIOTLB buffer");
 
@@ -308,13 +308,13 @@ void __init swiotlb_free(void)
                           get_order(io_tlb_nslabs << IO_TLB_SHIFT));
        } else {
                free_bootmem_late(__pa(io_tlb_overflow_buffer),
-                                 io_tlb_overflow);
+                                 PAGE_ALIGN(io_tlb_overflow));
                free_bootmem_late(__pa(io_tlb_orig_addr),
-                                 io_tlb_nslabs * sizeof(phys_addr_t));
+                                 PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)));
                free_bootmem_late(__pa(io_tlb_list),
-                                 io_tlb_nslabs * sizeof(int));
+                                 PAGE_ALIGN(io_tlb_nslabs * sizeof(int)));
                free_bootmem_late(__pa(io_tlb_start),
-                                 io_tlb_nslabs << IO_TLB_SHIFT);
+                                 PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
        }
 }
 
index 142c84a54993a75ca2fbd5346e3eb5b16552f390..13b0caa9793c008b7fafa09cbe5c586faa6c7447 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/kmemleak.h>
 #include <linux/range.h>
+#include <linux/memblock.h>
 
 #include <asm/bug.h>
 #include <asm/io.h>
@@ -434,7 +435,8 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
                              unsigned long size)
 {
 #ifdef CONFIG_NO_BOOTMEM
-       free_early(physaddr, physaddr + size);
+       kmemleak_free_part(__va(physaddr), size);
+       memblock_x86_free_range(physaddr, physaddr + size);
 #else
        unsigned long start, end;
 
@@ -459,7 +461,8 @@ void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr,
 void __init free_bootmem(unsigned long addr, unsigned long size)
 {
 #ifdef CONFIG_NO_BOOTMEM
-       free_early(addr, addr + size);
+       kmemleak_free_part(__va(addr), size);
+       memblock_x86_free_range(addr, addr + size);
 #else
        unsigned long start, end;
 
@@ -526,6 +529,12 @@ int __init reserve_bootmem(unsigned long addr, unsigned long size,
 }
 
 #ifndef CONFIG_NO_BOOTMEM
+int __weak __init reserve_bootmem_generic(unsigned long phys, unsigned long len,
+                                  int flags)
+{
+       return reserve_bootmem(phys, len, flags);
+}
+
 static unsigned long __init align_idx(struct bootmem_data *bdata,
                                      unsigned long idx, unsigned long step)
 {
index 43840b305ecb2c01ac478d1c3c67aff7993016a7..400dc62697d78056eaa12c7a91ca9f9daa1d4c77 100644 (file)
  */
 
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
+#include <linux/poison.h>
+#include <linux/pfn.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/memblock.h>
 
-#define MEMBLOCK_ALLOC_ANYWHERE        0
+struct memblock memblock __initdata_memblock;
 
-struct memblock memblock;
+int memblock_debug __initdata_memblock;
+int memblock_can_resize __initdata_memblock;
+static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS + 1] __initdata_memblock;
+static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS + 1] __initdata_memblock;
 
-static int memblock_debug;
+/* inline so we don't get a warning when pr_debug is compiled out */
+static inline const char *memblock_type_name(struct memblock_type *type)
+{
+       if (type == &memblock.memory)
+               return "memory";
+       else if (type == &memblock.reserved)
+               return "reserved";
+       else
+               return "unknown";
+}
 
-static int __init early_memblock(char *p)
+/*
+ * Address comparison utilities
+ */
+
+static phys_addr_t __init_memblock memblock_align_down(phys_addr_t addr, phys_addr_t size)
 {
-       if (p && strstr(p, "debug"))
-               memblock_debug = 1;
+       return addr & ~(size - 1);
+}
+
+static phys_addr_t __init_memblock memblock_align_up(phys_addr_t addr, phys_addr_t size)
+{
+       return (addr + (size - 1)) & ~(size - 1);
+}
+
+static unsigned long __init_memblock memblock_addrs_overlap(phys_addr_t base1, phys_addr_t size1,
+                                      phys_addr_t base2, phys_addr_t size2)
+{
+       return ((base1 < (base2 + size2)) && (base2 < (base1 + size1)));
+}
+
+static long __init_memblock memblock_addrs_adjacent(phys_addr_t base1, phys_addr_t size1,
+                              phys_addr_t base2, phys_addr_t size2)
+{
+       if (base2 == base1 + size1)
+               return 1;
+       else if (base1 == base2 + size2)
+               return -1;
+
        return 0;
 }
-early_param("memblock", early_memblock);
 
-static void memblock_dump(struct memblock_region *region, char *name)
+static long __init_memblock memblock_regions_adjacent(struct memblock_type *type,
+                                unsigned long r1, unsigned long r2)
 {
-       unsigned long long base, size;
-       int i;
+       phys_addr_t base1 = type->regions[r1].base;
+       phys_addr_t size1 = type->regions[r1].size;
+       phys_addr_t base2 = type->regions[r2].base;
+       phys_addr_t size2 = type->regions[r2].size;
 
-       pr_info(" %s.cnt  = 0x%lx\n", name, region->cnt);
+       return memblock_addrs_adjacent(base1, size1, base2, size2);
+}
 
-       for (i = 0; i < region->cnt; i++) {
-               base = region->region[i].base;
-               size = region->region[i].size;
+long __init_memblock memblock_overlaps_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size)
+{
+       unsigned long i;
 
-               pr_info(" %s[0x%x]\t0x%016llx - 0x%016llx, 0x%llx bytes\n",
-                   name, i, base, base + size - 1, size);
+       for (i = 0; i < type->cnt; i++) {
+               phys_addr_t rgnbase = type->regions[i].base;
+               phys_addr_t rgnsize = type->regions[i].size;
+               if (memblock_addrs_overlap(base, size, rgnbase, rgnsize))
+                       break;
        }
+
+       return (i < type->cnt) ? i : -1;
 }
 
-void memblock_dump_all(void)
+/*
+ * Find, allocate, deallocate or reserve unreserved regions. All allocations
+ * are top-down.
+ */
+
+static phys_addr_t __init_memblock memblock_find_region(phys_addr_t start, phys_addr_t end,
+                                         phys_addr_t size, phys_addr_t align)
 {
-       if (!memblock_debug)
-               return;
+       phys_addr_t base, res_base;
+       long j;
 
-       pr_info("MEMBLOCK configuration:\n");
-       pr_info(" rmo_size    = 0x%llx\n", (unsigned long long)memblock.rmo_size);
-       pr_info(" memory.size = 0x%llx\n", (unsigned long long)memblock.memory.size);
+       /* In case, huge size is requested */
+       if (end < size)
+               return MEMBLOCK_ERROR;
 
-       memblock_dump(&memblock.memory, "memory");
-       memblock_dump(&memblock.reserved, "reserved");
+       base = memblock_align_down((end - size), align);
+
+       /* Prevent allocations returning 0 as it's also used to
+        * indicate an allocation failure
+        */
+       if (start == 0)
+               start = PAGE_SIZE;
+
+       while (start <= base) {
+               j = memblock_overlaps_region(&memblock.reserved, base, size);
+               if (j < 0)
+                       return base;
+               res_base = memblock.reserved.regions[j].base;
+               if (res_base < size)
+                       break;
+               base = memblock_align_down(res_base - size, align);
+       }
+
+       return MEMBLOCK_ERROR;
 }
 
-static unsigned long memblock_addrs_overlap(u64 base1, u64 size1, u64 base2,
-                                       u64 size2)
+static phys_addr_t __init_memblock memblock_find_base(phys_addr_t size,
+                       phys_addr_t align, phys_addr_t start, phys_addr_t end)
 {
-       return ((base1 < (base2 + size2)) && (base2 < (base1 + size1)));
+       long i;
+
+       BUG_ON(0 == size);
+
+       size = memblock_align_up(size, align);
+
+       /* Pump up max_addr */
+       if (end == MEMBLOCK_ALLOC_ACCESSIBLE)
+               end = memblock.current_limit;
+
+       /* We do a top-down search, this tends to limit memory
+        * fragmentation by keeping early boot allocs near the
+        * top of memory
+        */
+       for (i = memblock.memory.cnt - 1; i >= 0; i--) {
+               phys_addr_t memblockbase = memblock.memory.regions[i].base;
+               phys_addr_t memblocksize = memblock.memory.regions[i].size;
+               phys_addr_t bottom, top, found;
+
+               if (memblocksize < size)
+                       continue;
+               if ((memblockbase + memblocksize) <= start)
+                       break;
+               bottom = max(memblockbase, start);
+               top = min(memblockbase + memblocksize, end);
+               if (bottom >= top)
+                       continue;
+               found = memblock_find_region(bottom, top, size, align);
+               if (found != MEMBLOCK_ERROR)
+                       return found;
+       }
+       return MEMBLOCK_ERROR;
 }
 
-static long memblock_addrs_adjacent(u64 base1, u64 size1, u64 base2, u64 size2)
+/*
+ * Find a free area with specified alignment in a specific range.
+ */
+u64 __init_memblock memblock_find_in_range(u64 start, u64 end, u64 size, u64 align)
 {
-       if (base2 == base1 + size1)
-               return 1;
-       else if (base1 == base2 + size2)
-               return -1;
+       return memblock_find_base(size, align, start, end);
+}
 
-       return 0;
+/*
+ * Free memblock.reserved.regions
+ */
+int __init_memblock memblock_free_reserved_regions(void)
+{
+       if (memblock.reserved.regions == memblock_reserved_init_regions)
+               return 0;
+
+       return memblock_free(__pa(memblock.reserved.regions),
+                sizeof(struct memblock_region) * memblock.reserved.max);
 }
 
-static long memblock_regions_adjacent(struct memblock_region *rgn,
-               unsigned long r1, unsigned long r2)
+/*
+ * Reserve memblock.reserved.regions
+ */
+int __init_memblock memblock_reserve_reserved_regions(void)
 {
-       u64 base1 = rgn->region[r1].base;
-       u64 size1 = rgn->region[r1].size;
-       u64 base2 = rgn->region[r2].base;
-       u64 size2 = rgn->region[r2].size;
+       if (memblock.reserved.regions == memblock_reserved_init_regions)
+               return 0;
 
-       return memblock_addrs_adjacent(base1, size1, base2, size2);
+       return memblock_reserve(__pa(memblock.reserved.regions),
+                sizeof(struct memblock_region) * memblock.reserved.max);
 }
 
-static void memblock_remove_region(struct memblock_region *rgn, unsigned long r)
+static void __init_memblock memblock_remove_region(struct memblock_type *type, unsigned long r)
 {
        unsigned long i;
 
-       for (i = r; i < rgn->cnt - 1; i++) {
-               rgn->region[i].base = rgn->region[i + 1].base;
-               rgn->region[i].size = rgn->region[i + 1].size;
+       for (i = r; i < type->cnt - 1; i++) {
+               type->regions[i].base = type->regions[i + 1].base;
+               type->regions[i].size = type->regions[i + 1].size;
        }
-       rgn->cnt--;
+       type->cnt--;
 }
 
 /* Assumption: base addr of region 1 < base addr of region 2 */
-static void memblock_coalesce_regions(struct memblock_region *rgn,
+static void __init_memblock memblock_coalesce_regions(struct memblock_type *type,
                unsigned long r1, unsigned long r2)
 {
-       rgn->region[r1].size += rgn->region[r2].size;
-       memblock_remove_region(rgn, r2);
+       type->regions[r1].size += type->regions[r2].size;
+       memblock_remove_region(type, r2);
 }
 
-void __init memblock_init(void)
+/* Defined below but needed now */
+static long memblock_add_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size);
+
+static int __init_memblock memblock_double_array(struct memblock_type *type)
 {
-       /* Create a dummy zero size MEMBLOCK which will get coalesced away later.
-        * This simplifies the memblock_add() code below...
+       struct memblock_region *new_array, *old_array;
+       phys_addr_t old_size, new_size, addr;
+       int use_slab = slab_is_available();
+
+       /* We don't allow resizing until we know about the reserved regions
+        * of memory that aren't suitable for allocation
         */
-       memblock.memory.region[0].base = 0;
-       memblock.memory.region[0].size = 0;
-       memblock.memory.cnt = 1;
+       if (!memblock_can_resize)
+               return -1;
 
-       /* Ditto. */
-       memblock.reserved.region[0].base = 0;
-       memblock.reserved.region[0].size = 0;
-       memblock.reserved.cnt = 1;
-}
+       /* Calculate new doubled size */
+       old_size = type->max * sizeof(struct memblock_region);
+       new_size = old_size << 1;
+
+       /* Try to find some space for it.
+        *
+        * WARNING: We assume that either slab_is_available() and we use it or
+        * we use MEMBLOCK for allocations. That means that this is unsafe to use
+        * when bootmem is currently active (unless bootmem itself is implemented
+        * on top of MEMBLOCK which isn't the case yet)
+        *
+        * This should however not be an issue for now, as we currently only
+        * call into MEMBLOCK while it's still active, or much later when slab is
+        * active for memory hotplug operations
+        */
+       if (use_slab) {
+               new_array = kmalloc(new_size, GFP_KERNEL);
+               addr = new_array == NULL ? MEMBLOCK_ERROR : __pa(new_array);
+       } else
+               addr = memblock_find_base(new_size, sizeof(phys_addr_t), 0, MEMBLOCK_ALLOC_ACCESSIBLE);
+       if (addr == MEMBLOCK_ERROR) {
+               pr_err("memblock: Failed to double %s array from %ld to %ld entries !\n",
+                      memblock_type_name(type), type->max, type->max * 2);
+               return -1;
+       }
+       new_array = __va(addr);
 
-void __init memblock_analyze(void)
-{
-       int i;
+       memblock_dbg("memblock: %s array is doubled to %ld at [%#010llx-%#010llx]",
+                memblock_type_name(type), type->max * 2, (u64)addr, (u64)addr + new_size - 1);
 
-       memblock.memory.size = 0;
+       /* Found space, we now need to move the array over before
+        * we add the reserved region since it may be our reserved
+        * array itself that is full.
+        */
+       memcpy(new_array, type->regions, old_size);
+       memset(new_array + type->max, 0, old_size);
+       old_array = type->regions;
+       type->regions = new_array;
+       type->max <<= 1;
+
+       /* If we use SLAB that's it, we are done */
+       if (use_slab)
+               return 0;
 
-       for (i = 0; i < memblock.memory.cnt; i++)
-               memblock.memory.size += memblock.memory.region[i].size;
+       /* Add the new reserved region now. Should not fail ! */
+       BUG_ON(memblock_add_region(&memblock.reserved, addr, new_size) < 0);
+
+       /* If the array wasn't our static init one, then free it. We only do
+        * that before SLAB is available as later on, we don't know whether
+        * to use kfree or free_bootmem_pages(). Shouldn't be a big deal
+        * anyways
+        */
+       if (old_array != memblock_memory_init_regions &&
+           old_array != memblock_reserved_init_regions)
+               memblock_free(__pa(old_array), old_size);
+
+       return 0;
 }
 
-static long memblock_add_region(struct memblock_region *rgn, u64 base, u64 size)
+extern int __init_memblock __weak memblock_memory_can_coalesce(phys_addr_t addr1, phys_addr_t size1,
+                                         phys_addr_t addr2, phys_addr_t size2)
+{
+       return 1;
+}
+
+static long __init_memblock memblock_add_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size)
 {
        unsigned long coalesced = 0;
        long adjacent, i;
 
-       if ((rgn->cnt == 1) && (rgn->region[0].size == 0)) {
-               rgn->region[0].base = base;
-               rgn->region[0].size = size;
+       if ((type->cnt == 1) && (type->regions[0].size == 0)) {
+               type->regions[0].base = base;
+               type->regions[0].size = size;
                return 0;
        }
 
        /* First try and coalesce this MEMBLOCK with another. */
-       for (i = 0; i < rgn->cnt; i++) {
-               u64 rgnbase = rgn->region[i].base;
-               u64 rgnsize = rgn->region[i].size;
+       for (i = 0; i < type->cnt; i++) {
+               phys_addr_t rgnbase = type->regions[i].base;
+               phys_addr_t rgnsize = type->regions[i].size;
 
                if ((rgnbase == base) && (rgnsize == size))
                        /* Already have this region, so we're done */
                        return 0;
 
                adjacent = memblock_addrs_adjacent(base, size, rgnbase, rgnsize);
+               /* Check if arch allows coalescing */
+               if (adjacent != 0 && type == &memblock.memory &&
+                   !memblock_memory_can_coalesce(base, size, rgnbase, rgnsize))
+                       break;
                if (adjacent > 0) {
-                       rgn->region[i].base -= size;
-                       rgn->region[i].size += size;
+                       type->regions[i].base -= size;
+                       type->regions[i].size += size;
                        coalesced++;
                        break;
                } else if (adjacent < 0) {
-                       rgn->region[i].size += size;
+                       type->regions[i].size += size;
                        coalesced++;
                        break;
                }
        }
 
-       if ((i < rgn->cnt - 1) && memblock_regions_adjacent(rgn, i, i+1)) {
-               memblock_coalesce_regions(rgn, i, i+1);
+       /* If we plugged a hole, we may want to also coalesce with the
+        * next region
+        */
+       if ((i < type->cnt - 1) && memblock_regions_adjacent(type, i, i+1) &&
+           ((type != &memblock.memory || memblock_memory_can_coalesce(type->regions[i].base,
+                                                            type->regions[i].size,
+                                                            type->regions[i+1].base,
+                                                            type->regions[i+1].size)))) {
+               memblock_coalesce_regions(type, i, i+1);
                coalesced++;
        }
 
        if (coalesced)
                return coalesced;
-       if (rgn->cnt >= MAX_MEMBLOCK_REGIONS)
+
+       /* If we are out of space, we fail. It's too late to resize the array
+        * but then this shouldn't have happened in the first place.
+        */
+       if (WARN_ON(type->cnt >= type->max))
                return -1;
 
        /* Couldn't coalesce the MEMBLOCK, so add it to the sorted table. */
-       for (i = rgn->cnt - 1; i >= 0; i--) {
-               if (base < rgn->region[i].base) {
-                       rgn->region[i+1].base = rgn->region[i].base;
-                       rgn->region[i+1].size = rgn->region[i].size;
+       for (i = type->cnt - 1; i >= 0; i--) {
+               if (base < type->regions[i].base) {
+                       type->regions[i+1].base = type->regions[i].base;
+                       type->regions[i+1].size = type->regions[i].size;
                } else {
-                       rgn->region[i+1].base = base;
-                       rgn->region[i+1].size = size;
+                       type->regions[i+1].base = base;
+                       type->regions[i+1].size = size;
                        break;
                }
        }
 
-       if (base < rgn->region[0].base) {
-               rgn->region[0].base = base;
-               rgn->region[0].size = size;
+       if (base < type->regions[0].base) {
+               type->regions[0].base = base;
+               type->regions[0].size = size;
+       }
+       type->cnt++;
+
+       /* The array is full ? Try to resize it. If that fails, we undo
+        * our allocation and return an error
+        */
+       if (type->cnt == type->max && memblock_double_array(type)) {
+               type->cnt--;
+               return -1;
        }
-       rgn->cnt++;
 
        return 0;
 }
 
-long memblock_add(u64 base, u64 size)
+long __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)
 {
-       struct memblock_region *_rgn = &memblock.memory;
-
-       /* On pSeries LPAR systems, the first MEMBLOCK is our RMO region. */
-       if (base == 0)
-               memblock.rmo_size = size;
-
-       return memblock_add_region(_rgn, base, size);
+       return memblock_add_region(&memblock.memory, base, size);
 
 }
 
-static long __memblock_remove(struct memblock_region *rgn, u64 base, u64 size)
+static long __init_memblock __memblock_remove(struct memblock_type *type, phys_addr_t base, phys_addr_t size)
 {
-       u64 rgnbegin, rgnend;
-       u64 end = base + size;
+       phys_addr_t rgnbegin, rgnend;
+       phys_addr_t end = base + size;
        int i;
 
        rgnbegin = rgnend = 0; /* supress gcc warnings */
 
        /* Find the region where (base, size) belongs to */
-       for (i=0; i < rgn->cnt; i++) {
-               rgnbegin = rgn->region[i].base;
-               rgnend = rgnbegin + rgn->region[i].size;
+       for (i=0; i < type->cnt; i++) {
+               rgnbegin = type->regions[i].base;
+               rgnend = rgnbegin + type->regions[i].size;
 
                if ((rgnbegin <= base) && (end <= rgnend))
                        break;
        }
 
        /* Didn't find the region */
-       if (i == rgn->cnt)
+       if (i == type->cnt)
                return -1;
 
        /* Check to see if we are removing entire region */
        if ((rgnbegin == base) && (rgnend == end)) {
-               memblock_remove_region(rgn, i);
+               memblock_remove_region(type, i);
                return 0;
        }
 
        /* Check to see if region is matching at the front */
        if (rgnbegin == base) {
-               rgn->region[i].base = end;
-               rgn->region[i].size -= size;
+               type->regions[i].base = end;
+               type->regions[i].size -= size;
                return 0;
        }
 
        /* Check to see if the region is matching at the end */
        if (rgnend == end) {
-               rgn->region[i].size -= size;
+               type->regions[i].size -= size;
                return 0;
        }
 
@@ -249,208 +435,189 @@ static long __memblock_remove(struct memblock_region *rgn, u64 base, u64 size)
         * We need to split the entry -  adjust the current one to the
         * beginging of the hole and add the region after hole.
         */
-       rgn->region[i].size = base - rgn->region[i].base;
-       return memblock_add_region(rgn, end, rgnend - end);
+       type->regions[i].size = base - type->regions[i].base;
+       return memblock_add_region(type, end, rgnend - end);
 }
 
-long memblock_remove(u64 base, u64 size)
+long __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)
 {
        return __memblock_remove(&memblock.memory, base, size);
 }
 
-long __init memblock_free(u64 base, u64 size)
+long __init_memblock memblock_free(phys_addr_t base, phys_addr_t size)
 {
        return __memblock_remove(&memblock.reserved, base, size);
 }
 
-long __init memblock_reserve(u64 base, u64 size)
+long __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)
 {
-       struct memblock_region *_rgn = &memblock.reserved;
+       struct memblock_type *_rgn = &memblock.reserved;
 
        BUG_ON(0 == size);
 
        return memblock_add_region(_rgn, base, size);
 }
 
-long memblock_overlaps_region(struct memblock_region *rgn, u64 base, u64 size)
+phys_addr_t __init __memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
 {
-       unsigned long i;
+       phys_addr_t found;
 
-       for (i = 0; i < rgn->cnt; i++) {
-               u64 rgnbase = rgn->region[i].base;
-               u64 rgnsize = rgn->region[i].size;
-               if (memblock_addrs_overlap(base, size, rgnbase, rgnsize))
-                       break;
-       }
+       /* We align the size to limit fragmentation. Without this, a lot of
+        * small allocs quickly eat up the whole reserve array on sparc
+        */
+       size = memblock_align_up(size, align);
 
-       return (i < rgn->cnt) ? i : -1;
+       found = memblock_find_base(size, align, 0, max_addr);
+       if (found != MEMBLOCK_ERROR &&
+           memblock_add_region(&memblock.reserved, found, size) >= 0)
+               return found;
+
+       return 0;
 }
 
-static u64 memblock_align_down(u64 addr, u64 size)
+phys_addr_t __init memblock_alloc_base(phys_addr_t size, phys_addr_t align, phys_addr_t max_addr)
 {
-       return addr & ~(size - 1);
+       phys_addr_t alloc;
+
+       alloc = __memblock_alloc_base(size, align, max_addr);
+
+       if (alloc == 0)
+               panic("ERROR: Failed to allocate 0x%llx bytes below 0x%llx.\n",
+                     (unsigned long long) size, (unsigned long long) max_addr);
+
+       return alloc;
 }
 
-static u64 memblock_align_up(u64 addr, u64 size)
+phys_addr_t __init memblock_alloc(phys_addr_t size, phys_addr_t align)
 {
-       return (addr + (size - 1)) & ~(size - 1);
+       return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);
 }
 
-static u64 __init memblock_alloc_nid_unreserved(u64 start, u64 end,
-                                          u64 size, u64 align)
+
+/*
+ * Additional node-local allocators. Search for node memory is bottom up
+ * and walks memblock regions within that node bottom-up as well, but allocation
+ * within an memblock region is top-down. XXX I plan to fix that at some stage
+ *
+ * WARNING: Only available after early_node_map[] has been populated,
+ * on some architectures, that is after all the calls to add_active_range()
+ * have been done to populate it.
+ */
+
+phys_addr_t __weak __init memblock_nid_range(phys_addr_t start, phys_addr_t end, int *nid)
 {
-       u64 base, res_base;
-       long j;
+#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
+       /*
+        * This code originates from sparc which really wants use to walk by addresses
+        * and returns the nid. This is not very convenient for early_pfn_map[] users
+        * as the map isn't sorted yet, and it really wants to be walked by nid.
+        *
+        * For now, I implement the inefficient method below which walks the early
+        * map multiple times. Eventually we may want to use an ARCH config option
+        * to implement a completely different method for both case.
+        */
+       unsigned long start_pfn, end_pfn;
+       int i;
 
-       base = memblock_align_down((end - size), align);
-       while (start <= base) {
-               j = memblock_overlaps_region(&memblock.reserved, base, size);
-               if (j < 0) {
-                       /* this area isn't reserved, take it */
-                       if (memblock_add_region(&memblock.reserved, base, size) < 0)
-                               base = ~(u64)0;
-                       return base;
-               }
-               res_base = memblock.reserved.region[j].base;
-               if (res_base < size)
-                       break;
-               base = memblock_align_down(res_base - size, align);
+       for (i = 0; i < MAX_NUMNODES; i++) {
+               get_pfn_range_for_nid(i, &start_pfn, &end_pfn);
+               if (start < PFN_PHYS(start_pfn) || start >= PFN_PHYS(end_pfn))
+                       continue;
+               *nid = i;
+               return min(end, PFN_PHYS(end_pfn));
        }
+#endif
+       *nid = 0;
 
-       return ~(u64)0;
+       return end;
 }
 
-static u64 __init memblock_alloc_nid_region(struct memblock_property *mp,
-                                      u64 (*nid_range)(u64, u64, int *),
-                                      u64 size, u64 align, int nid)
+static phys_addr_t __init memblock_alloc_nid_region(struct memblock_region *mp,
+                                              phys_addr_t size,
+                                              phys_addr_t align, int nid)
 {
-       u64 start, end;
+       phys_addr_t start, end;
 
        start = mp->base;
        end = start + mp->size;
 
        start = memblock_align_up(start, align);
        while (start < end) {
-               u64 this_end;
+               phys_addr_t this_end;
                int this_nid;
 
-               this_end = nid_range(start, end, &this_nid);
+               this_end = memblock_nid_range(start, end, &this_nid);
                if (this_nid == nid) {
-                       u64 ret = memblock_alloc_nid_unreserved(start, this_end,
-                                                          size, align);
-                       if (ret != ~(u64)0)
+                       phys_addr_t ret = memblock_find_region(start, this_end, size, align);
+                       if (ret != MEMBLOCK_ERROR &&
+                           memblock_add_region(&memblock.reserved, ret, size) >= 0)
                                return ret;
                }
                start = this_end;
        }
 
-       return ~(u64)0;
+       return MEMBLOCK_ERROR;
 }
 
-u64 __init memblock_alloc_nid(u64 size, u64 align, int nid,
-                        u64 (*nid_range)(u64 start, u64 end, int *nid))
+phys_addr_t __init memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nid)
 {
-       struct memblock_region *mem = &memblock.memory;
+       struct memblock_type *mem = &memblock.memory;
        int i;
 
        BUG_ON(0 == size);
 
+       /* We align the size to limit fragmentation. Without this, a lot of
+        * small allocs quickly eat up the whole reserve array on sparc
+        */
        size = memblock_align_up(size, align);
 
+       /* We do a bottom-up search for a region with the right
+        * nid since that's easier considering how memblock_nid_range()
+        * works
+        */
        for (i = 0; i < mem->cnt; i++) {
-               u64 ret = memblock_alloc_nid_region(&mem->region[i],
-                                              nid_range,
+               phys_addr_t ret = memblock_alloc_nid_region(&mem->regions[i],
                                               size, align, nid);
-               if (ret != ~(u64)0)
+               if (ret != MEMBLOCK_ERROR)
                        return ret;
        }
 
-       return memblock_alloc(size, align);
-}
-
-u64 __init memblock_alloc(u64 size, u64 align)
-{
-       return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ANYWHERE);
+       return 0;
 }
 
-u64 __init memblock_alloc_base(u64 size, u64 align, u64 max_addr)
+phys_addr_t __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid)
 {
-       u64 alloc;
-
-       alloc = __memblock_alloc_base(size, align, max_addr);
+       phys_addr_t res = memblock_alloc_nid(size, align, nid);
 
-       if (alloc == 0)
-               panic("ERROR: Failed to allocate 0x%llx bytes below 0x%llx.\n",
-                     (unsigned long long) size, (unsigned long long) max_addr);
-
-       return alloc;
+       if (res)
+               return res;
+       return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ANYWHERE);
 }
 
-u64 __init __memblock_alloc_base(u64 size, u64 align, u64 max_addr)
-{
-       long i, j;
-       u64 base = 0;
-       u64 res_base;
-
-       BUG_ON(0 == size);
 
-       size = memblock_align_up(size, align);
-
-       /* On some platforms, make sure we allocate lowmem */
-       /* Note that MEMBLOCK_REAL_LIMIT may be MEMBLOCK_ALLOC_ANYWHERE */
-       if (max_addr == MEMBLOCK_ALLOC_ANYWHERE)
-               max_addr = MEMBLOCK_REAL_LIMIT;
-
-       for (i = memblock.memory.cnt - 1; i >= 0; i--) {
-               u64 memblockbase = memblock.memory.region[i].base;
-               u64 memblocksize = memblock.memory.region[i].size;
-
-               if (memblocksize < size)
-                       continue;
-               if (max_addr == MEMBLOCK_ALLOC_ANYWHERE)
-                       base = memblock_align_down(memblockbase + memblocksize - size, align);
-               else if (memblockbase < max_addr) {
-                       base = min(memblockbase + memblocksize, max_addr);
-                       base = memblock_align_down(base - size, align);
-               } else
-                       continue;
-
-               while (base && memblockbase <= base) {
-                       j = memblock_overlaps_region(&memblock.reserved, base, size);
-                       if (j < 0) {
-                               /* this area isn't reserved, take it */
-                               if (memblock_add_region(&memblock.reserved, base, size) < 0)
-                                       return 0;
-                               return base;
-                       }
-                       res_base = memblock.reserved.region[j].base;
-                       if (res_base < size)
-                               break;
-                       base = memblock_align_down(res_base - size, align);
-               }
-       }
-       return 0;
-}
+/*
+ * Remaining API functions
+ */
 
 /* You must call memblock_analyze() before this. */
-u64 __init memblock_phys_mem_size(void)
+phys_addr_t __init memblock_phys_mem_size(void)
 {
-       return memblock.memory.size;
+       return memblock.memory_size;
 }
 
-u64 memblock_end_of_DRAM(void)
+phys_addr_t __init_memblock memblock_end_of_DRAM(void)
 {
        int idx = memblock.memory.cnt - 1;
 
-       return (memblock.memory.region[idx].base + memblock.memory.region[idx].size);
+       return (memblock.memory.regions[idx].base + memblock.memory.regions[idx].size);
 }
 
 /* You must call memblock_analyze() after this. */
-void __init memblock_enforce_memory_limit(u64 memory_limit)
+void __init memblock_enforce_memory_limit(phys_addr_t memory_limit)
 {
        unsigned long i;
-       u64 limit;
-       struct memblock_property *p;
+       phys_addr_t limit;
+       struct memblock_region *p;
 
        if (!memory_limit)
                return;
@@ -458,24 +625,21 @@ void __init memblock_enforce_memory_limit(u64 memory_limit)
        /* Truncate the memblock regions to satisfy the memory limit. */
        limit = memory_limit;
        for (i = 0; i < memblock.memory.cnt; i++) {
-               if (limit > memblock.memory.region[i].size) {
-                       limit -= memblock.memory.region[i].size;
+               if (limit > memblock.memory.regions[i].size) {
+                       limit -= memblock.memory.regions[i].size;
                        continue;
                }
 
-               memblock.memory.region[i].size = limit;
+               memblock.memory.regions[i].size = limit;
                memblock.memory.cnt = i + 1;
                break;
        }
 
-       if (memblock.memory.region[0].size < memblock.rmo_size)
-               memblock.rmo_size = memblock.memory.region[0].size;
-
        memory_limit = memblock_end_of_DRAM();
 
        /* And truncate any reserves above the limit also. */
        for (i = 0; i < memblock.reserved.cnt; i++) {
-               p = &memblock.reserved.region[i];
+               p = &memblock.reserved.regions[i];
 
                if (p->base > memory_limit)
                        p->size = 0;
@@ -489,53 +653,190 @@ void __init memblock_enforce_memory_limit(u64 memory_limit)
        }
 }
 
-int __init memblock_is_reserved(u64 addr)
+static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
+{
+       unsigned int left = 0, right = type->cnt;
+
+       do {
+               unsigned int mid = (right + left) / 2;
+
+               if (addr < type->regions[mid].base)
+                       right = mid;
+               else if (addr >= (type->regions[mid].base +
+                                 type->regions[mid].size))
+                       left = mid + 1;
+               else
+                       return mid;
+       } while (left < right);
+       return -1;
+}
+
+int __init memblock_is_reserved(phys_addr_t addr)
+{
+       return memblock_search(&memblock.reserved, addr) != -1;
+}
+
+int __init_memblock memblock_is_memory(phys_addr_t addr)
+{
+       return memblock_search(&memblock.memory, addr) != -1;
+}
+
+int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)
+{
+       int idx = memblock_search(&memblock.reserved, base);
+
+       if (idx == -1)
+               return 0;
+       return memblock.reserved.regions[idx].base <= base &&
+               (memblock.reserved.regions[idx].base +
+                memblock.reserved.regions[idx].size) >= (base + size);
+}
+
+int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)
+{
+       return memblock_overlaps_region(&memblock.reserved, base, size) >= 0;
+}
+
+
+void __init_memblock memblock_set_current_limit(phys_addr_t limit)
 {
+       memblock.current_limit = limit;
+}
+
+static void __init_memblock memblock_dump(struct memblock_type *region, char *name)
+{
+       unsigned long long base, size;
        int i;
 
-       for (i = 0; i < memblock.reserved.cnt; i++) {
-               u64 upper = memblock.reserved.region[i].base +
-                       memblock.reserved.region[i].size - 1;
-               if ((addr >= memblock.reserved.region[i].base) && (addr <= upper))
-                       return 1;
+       pr_info(" %s.cnt  = 0x%lx\n", name, region->cnt);
+
+       for (i = 0; i < region->cnt; i++) {
+               base = region->regions[i].base;
+               size = region->regions[i].size;
+
+               pr_info(" %s[%#x]\t[%#016llx-%#016llx], %#llx bytes\n",
+                   name, i, base, base + size - 1, size);
        }
-       return 0;
 }
 
-int memblock_is_region_reserved(u64 base, u64 size)
+void __init_memblock memblock_dump_all(void)
 {
-       return memblock_overlaps_region(&memblock.reserved, base, size) >= 0;
+       if (!memblock_debug)
+               return;
+
+       pr_info("MEMBLOCK configuration:\n");
+       pr_info(" memory size = 0x%llx\n", (unsigned long long)memblock.memory_size);
+
+       memblock_dump(&memblock.memory, "memory");
+       memblock_dump(&memblock.reserved, "reserved");
 }
 
-/*
- * Given a <base, len>, find which memory regions belong to this range.
- * Adjust the request and return a contiguous chunk.
- */
-int memblock_find(struct memblock_property *res)
+void __init memblock_analyze(void)
 {
        int i;
-       u64 rstart, rend;
 
-       rstart = res->base;
-       rend = rstart + res->size - 1;
+       /* Check marker in the unused last array entry */
+       WARN_ON(memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS].base
+               != (phys_addr_t)RED_INACTIVE);
+       WARN_ON(memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS].base
+               != (phys_addr_t)RED_INACTIVE);
+
+       memblock.memory_size = 0;
+
+       for (i = 0; i < memblock.memory.cnt; i++)
+               memblock.memory_size += memblock.memory.regions[i].size;
+
+       /* We allow resizing from there */
+       memblock_can_resize = 1;
+}
+
+void __init memblock_init(void)
+{
+       static int init_done __initdata = 0;
+
+       if (init_done)
+               return;
+       init_done = 1;
+
+       /* Hookup the initial arrays */
+       memblock.memory.regions = memblock_memory_init_regions;
+       memblock.memory.max             = INIT_MEMBLOCK_REGIONS;
+       memblock.reserved.regions       = memblock_reserved_init_regions;
+       memblock.reserved.max   = INIT_MEMBLOCK_REGIONS;
+
+       /* Write a marker in the unused last array entry */
+       memblock.memory.regions[INIT_MEMBLOCK_REGIONS].base = (phys_addr_t)RED_INACTIVE;
+       memblock.reserved.regions[INIT_MEMBLOCK_REGIONS].base = (phys_addr_t)RED_INACTIVE;
+
+       /* Create a dummy zero size MEMBLOCK which will get coalesced away later.
+        * This simplifies the memblock_add() code below...
+        */
+       memblock.memory.regions[0].base = 0;
+       memblock.memory.regions[0].size = 0;
+       memblock.memory.cnt = 1;
+
+       /* Ditto. */
+       memblock.reserved.regions[0].base = 0;
+       memblock.reserved.regions[0].size = 0;
+       memblock.reserved.cnt = 1;
+
+       memblock.current_limit = MEMBLOCK_ALLOC_ANYWHERE;
+}
+
+static int __init early_memblock(char *p)
+{
+       if (p && strstr(p, "debug"))
+               memblock_debug = 1;
+       return 0;
+}
+early_param("memblock", early_memblock);
+
+#if defined(CONFIG_DEBUG_FS) && !defined(ARCH_DISCARD_MEMBLOCK)
+
+static int memblock_debug_show(struct seq_file *m, void *private)
+{
+       struct memblock_type *type = m->private;
+       struct memblock_region *reg;
+       int i;
+
+       for (i = 0; i < type->cnt; i++) {
+               reg = &type->regions[i];
+               seq_printf(m, "%4d: ", i);
+               if (sizeof(phys_addr_t) == 4)
+                       seq_printf(m, "0x%08lx..0x%08lx\n",
+                                  (unsigned long)reg->base,
+                                  (unsigned long)(reg->base + reg->size - 1));
+               else
+                       seq_printf(m, "0x%016llx..0x%016llx\n",
+                                  (unsigned long long)reg->base,
+                                  (unsigned long long)(reg->base + reg->size - 1));
 
-       for (i = 0; i < memblock.memory.cnt; i++) {
-               u64 start = memblock.memory.region[i].base;
-               u64 end = start + memblock.memory.region[i].size - 1;
-
-               if (start > rend)
-                       return -1;
-
-               if ((end >= rstart) && (start < rend)) {
-                       /* adjust the request */
-                       if (rstart < start)
-                               rstart = start;
-                       if (rend > end)
-                               rend = end;
-                       res->base = rstart;
-                       res->size = rend - rstart + 1;
-                       return 0;
-               }
        }
-       return -1;
+       return 0;
+}
+
+static int memblock_debug_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, memblock_debug_show, inode->i_private);
 }
+
+static const struct file_operations memblock_debug_fops = {
+       .open = memblock_debug_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static int __init memblock_init_debugfs(void)
+{
+       struct dentry *root = debugfs_create_dir("memblock", NULL);
+       if (!root)
+               return -ENXIO;
+       debugfs_create_file("memory", S_IRUGO, root, &memblock.memory, &memblock_debug_fops);
+       debugfs_create_file("reserved", S_IRUGO, root, &memblock.reserved, &memblock_debug_fops);
+
+       return 0;
+}
+__initcall(memblock_init_debugfs);
+
+#endif /* CONFIG_DEBUG_FS */
index 0e18b4d649ec82abc83c208e5f9dce9cbb2cf905..98b58fecedeffc236a9c7285689fe4720409bd30 100644 (file)
@@ -3185,7 +3185,7 @@ static inline int handle_pte_fault(struct mm_struct *mm,
                 * with threads.
                 */
                if (flags & FAULT_FLAG_WRITE)
-                       flush_tlb_page(vma, address);
+                       flush_tlb_fix_spurious_fault(vma, address);
        }
 unlock:
        pte_unmap_unlock(pte, ptl);
index f12ad1836abe115b1b8e3bf4b9187c01249e8a30..2a362c52fdf482144eac24111059f56b5147bd42 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/pagemap.h>
 #include <linux/jiffies.h>
 #include <linux/bootmem.h>
+#include <linux/memblock.h>
 #include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/kmemcheck.h>
@@ -3636,6 +3637,41 @@ void __init free_bootmem_with_active_regions(int nid,
        }
 }
 
+#ifdef CONFIG_HAVE_MEMBLOCK
+u64 __init find_memory_core_early(int nid, u64 size, u64 align,
+                                       u64 goal, u64 limit)
+{
+       int i;
+
+       /* Need to go over early_node_map to find out good range for node */
+       for_each_active_range_index_in_nid(i, nid) {
+               u64 addr;
+               u64 ei_start, ei_last;
+               u64 final_start, final_end;
+
+               ei_last = early_node_map[i].end_pfn;
+               ei_last <<= PAGE_SHIFT;
+               ei_start = early_node_map[i].start_pfn;
+               ei_start <<= PAGE_SHIFT;
+
+               final_start = max(ei_start, goal);
+               final_end = min(ei_last, limit);
+
+               if (final_start >= final_end)
+                       continue;
+
+               addr = memblock_find_in_range(final_start, final_end, size, align);
+
+               if (addr == MEMBLOCK_ERROR)
+                       continue;
+
+               return addr;
+       }
+
+       return MEMBLOCK_ERROR;
+}
+#endif
+
 int __init add_from_early_node_map(struct range *range, int az,
                                   int nr_range, int nid)
 {
@@ -3655,46 +3691,26 @@ int __init add_from_early_node_map(struct range *range, int az,
 void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
                                        u64 goal, u64 limit)
 {
-       int i;
        void *ptr;
+       u64 addr;
 
-       if (limit > get_max_mapped())
-               limit = get_max_mapped();
-
-       /* need to go over early_node_map to find out good range for node */
-       for_each_active_range_index_in_nid(i, nid) {
-               u64 addr;
-               u64 ei_start, ei_last;
-
-               ei_last = early_node_map[i].end_pfn;
-               ei_last <<= PAGE_SHIFT;
-               ei_start = early_node_map[i].start_pfn;
-               ei_start <<= PAGE_SHIFT;
-               addr = find_early_area(ei_start, ei_last,
-                                        goal, limit, size, align);
-
-               if (addr == -1ULL)
-                       continue;
+       if (limit > memblock.current_limit)
+               limit = memblock.current_limit;
 
-#if 0
-               printk(KERN_DEBUG "alloc (nid=%d %llx - %llx) (%llx - %llx) %llx %llx => %llx\n",
-                               nid,
-                               ei_start, ei_last, goal, limit, size,
-                               align, addr);
-#endif
+       addr = find_memory_core_early(nid, size, align, goal, limit);
 
-               ptr = phys_to_virt(addr);
-               memset(ptr, 0, size);
-               reserve_early_without_check(addr, addr + size, "BOOTMEM");
-               /*
-                * The min_count is set to 0 so that bootmem allocated blocks
-                * are never reported as leaks.
-                */
-               kmemleak_alloc(ptr, size, 0, 0);
-               return ptr;
-       }
+       if (addr == MEMBLOCK_ERROR)
+               return NULL;
 
-       return NULL;
+       ptr = phys_to_virt(addr);
+       memset(ptr, 0, size);
+       memblock_x86_reserve_range(addr, addr + size, "BOOTMEM");
+       /*
+        * The min_count is set to 0 so that bootmem allocated blocks
+        * are never reported as leaks.
+        */
+       kmemleak_alloc(ptr, size, 0, 0);
+       return ptr;
 }
 #endif
 
index aa33fd67fa412bee2cef32e18c163d626e88bd00..29d6cbffb28306323847f0d8daa6b091048dd397 100644 (file)
@@ -220,18 +220,7 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
 
        if (vmemmap_buf_start) {
                /* need to free left buf */
-#ifdef CONFIG_NO_BOOTMEM
-               free_early(__pa(vmemmap_buf_start), __pa(vmemmap_buf_end));
-               if (vmemmap_buf_start < vmemmap_buf) {
-                       char name[15];
-
-                       snprintf(name, sizeof(name), "MEMMAP %d", nodeid);
-                       reserve_early_without_check(__pa(vmemmap_buf_start),
-                                                   __pa(vmemmap_buf), name);
-               }
-#else
                free_bootmem(__pa(vmemmap_buf), vmemmap_buf_end - vmemmap_buf);
-#endif
                vmemmap_buf = NULL;
                vmemmap_buf_end = NULL;
        }
index 6b8889da69a60612301c2bd26244ae0f3e1e1966..d8087f0db5073fc9ed3f879c7bc582c4fc462d0f 100644 (file)
@@ -516,6 +516,15 @@ static atomic_t vmap_lazy_nr = ATOMIC_INIT(0);
 /* for per-CPU blocks */
 static void purge_fragmented_blocks_allcpus(void);
 
+/*
+ * called before a call to iounmap() if the caller wants vm_area_struct's
+ * immediately freed.
+ */
+void set_iounmap_nonlazy(void)
+{
+       atomic_set(&vmap_lazy_nr, lazy_max_pages()+1);
+}
+
 /*
  * Purges all lazily-freed vmap areas.
  *
index e926884c1675c04c3d150ddc83eaa89f91a0cb4a..55fd82e9ffd91e9fd48878147f3068923373ce16 100644 (file)
@@ -293,6 +293,7 @@ source "net/wimax/Kconfig"
 source "net/rfkill/Kconfig"
 source "net/9p/Kconfig"
 source "net/caif/Kconfig"
+source "net/ceph/Kconfig"
 
 
 endif   # if NET
index ea60fbce9b1ba3e623ee9f1ec9ce622169a3596d..6b7bfd7f1416d9950e90cb3ddd065d998c0e78ee 100644 (file)
@@ -68,3 +68,4 @@ obj-$(CONFIG_SYSCTL)          += sysctl_net.o
 endif
 obj-$(CONFIG_WIMAX)            += wimax/
 obj-$(CONFIG_DNS_RESOLVER)     += dns_resolver/
+obj-$(CONFIG_CEPH_LIB)         += ceph/
diff --git a/net/ceph/Kconfig b/net/ceph/Kconfig
new file mode 100644 (file)
index 0000000..ad42404
--- /dev/null
@@ -0,0 +1,28 @@
+config CEPH_LIB
+        tristate "Ceph core library (EXPERIMENTAL)"
+       depends on INET && EXPERIMENTAL
+       select LIBCRC32C
+       select CRYPTO_AES
+       select CRYPTO
+       default n
+       help
+         Choose Y or M here to include cephlib, which provides the
+         common functionality to both the Ceph filesystem and
+         to the rados block device (rbd).
+
+         More information at http://ceph.newdream.net/.
+
+         If unsure, say N.
+
+config CEPH_LIB_PRETTYDEBUG
+       bool "Include file:line in ceph debug output"
+       depends on CEPH_LIB
+       default n
+       help
+         If you say Y here, debug output will include a filename and
+         line to aid debugging.  This increases kernel size and slows
+         execution slightly when debug call sites are enabled (e.g.,
+         via CONFIG_DYNAMIC_DEBUG).
+
+         If unsure, say N.
+
diff --git a/net/ceph/Makefile b/net/ceph/Makefile
new file mode 100644 (file)
index 0000000..aab1cab
--- /dev/null
@@ -0,0 +1,37 @@
+#
+# Makefile for CEPH filesystem.
+#
+
+ifneq ($(KERNELRELEASE),)
+
+obj-$(CONFIG_CEPH_LIB) += libceph.o
+
+libceph-objs := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \
+       mon_client.o \
+       osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \
+       debugfs.o \
+       auth.o auth_none.o \
+       crypto.o armor.o \
+       auth_x.o \
+       ceph_fs.o ceph_strings.o ceph_hash.o \
+       pagevec.o
+
+else
+#Otherwise we were called directly from the command
+# line; invoke the kernel build system.
+
+KERNELDIR ?= /lib/modules/$(shell uname -r)/build
+PWD := $(shell pwd)
+
+default: all
+
+all:
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_LIB=m modules
+
+modules_install:
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_LIB=m modules_install
+
+clean:
+       $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
+
+endif
similarity index 100%
rename from fs/ceph/armor.c
rename to net/ceph/armor.c
similarity index 97%
rename from fs/ceph/auth.c
rename to net/ceph/auth.c
index 6d2e30600627e71d25c2f93d5862952a078472b8..549c1f43e1d53b134c045954e103260fee9033b7 100644 (file)
@@ -1,16 +1,16 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include "types.h"
+#include <linux/ceph/types.h>
+#include <linux/ceph/decode.h>
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/messenger.h>
 #include "auth_none.h"
 #include "auth_x.h"
-#include "decode.h"
-#include "super.h"
 
-#include "messenger.h"
 
 /*
  * get protocol handler
similarity index 96%
rename from fs/ceph/auth_none.c
rename to net/ceph/auth_none.c
index ad1dc21286c7f3ca9c84d75d7a2630bc0069dae4..214c2bb43d6252056a7a77dcd2d8eb5877c719d1 100644 (file)
@@ -1,14 +1,15 @@
 
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/slab.h>
 
+#include <linux/ceph/decode.h>
+#include <linux/ceph/auth.h>
+
 #include "auth_none.h"
-#include "auth.h"
-#include "decode.h"
 
 static void reset(struct ceph_auth_client *ac)
 {
similarity index 94%
rename from fs/ceph/auth_none.h
rename to net/ceph/auth_none.h
index 8164df1a08be5060aa065106bdbeb539f9caabec..ed7d088b1bc92e14372e2f24c8f5016750e07014 100644 (file)
@@ -2,8 +2,7 @@
 #define _FS_CEPH_AUTH_NONE_H
 
 #include <linux/slab.h>
-
-#include "auth.h"
+#include <linux/ceph/auth.h>
 
 /*
  * null security mode.
similarity index 99%
rename from fs/ceph/auth_x.c
rename to net/ceph/auth_x.c
index a2d002cbdec23d15d30624a345ae6090ea452a53..7fd5dfcf6e188551f9a25638129239d79df9d874 100644 (file)
@@ -1,16 +1,17 @@
 
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/random.h>
 #include <linux/slab.h>
 
+#include <linux/ceph/decode.h>
+#include <linux/ceph/auth.h>
+
+#include "crypto.h"
 #include "auth_x.h"
 #include "auth_x_protocol.h"
-#include "crypto.h"
-#include "auth.h"
-#include "decode.h"
 
 #define TEMP_TICKET_BUF_LEN    256
 
similarity index 96%
rename from fs/ceph/auth_x.h
rename to net/ceph/auth_x.h
index ff6f8180e6816a352ca5184d8db1b47e110b64f4..e02da7a5c5a1052b881f383e7fca318da0675421 100644 (file)
@@ -3,8 +3,9 @@
 
 #include <linux/rbtree.h>
 
+#include <linux/ceph/auth.h>
+
 #include "crypto.h"
-#include "auth.h"
 #include "auth_x_protocol.h"
 
 /*
similarity index 86%
rename from fs/ceph/buffer.c
rename to net/ceph/buffer.c
index cd39f17021de9ab6cde35ce444a727970f4f8fab..53d8abfa25d5ede4b487c88a5341b376c4921c26 100644 (file)
@@ -1,10 +1,11 @@
 
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
+#include <linux/module.h>
 #include <linux/slab.h>
 
-#include "buffer.h"
-#include "decode.h"
+#include <linux/ceph/buffer.h>
+#include <linux/ceph/decode.h>
 
 struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
 {
@@ -32,6 +33,7 @@ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
        dout("buffer_new %p\n", b);
        return b;
 }
+EXPORT_SYMBOL(ceph_buffer_new);
 
 void ceph_buffer_release(struct kref *kref)
 {
@@ -46,6 +48,7 @@ void ceph_buffer_release(struct kref *kref)
        }
        kfree(b);
 }
+EXPORT_SYMBOL(ceph_buffer_release);
 
 int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end)
 {
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
new file mode 100644 (file)
index 0000000..f3e4a13
--- /dev/null
@@ -0,0 +1,529 @@
+
+#include <linux/ceph/ceph_debug.h>
+#include <linux/backing-dev.h>
+#include <linux/ctype.h>
+#include <linux/fs.h>
+#include <linux/inet.h>
+#include <linux/in6.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/parser.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/statfs.h>
+#include <linux/string.h>
+
+
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/debugfs.h>
+#include <linux/ceph/decode.h>
+#include <linux/ceph/mon_client.h>
+#include <linux/ceph/auth.h>
+
+
+
+/*
+ * find filename portion of a path (/foo/bar/baz -> baz)
+ */
+const char *ceph_file_part(const char *s, int len)
+{
+       const char *e = s + len;
+
+       while (e != s && *(e-1) != '/')
+               e--;
+       return e;
+}
+EXPORT_SYMBOL(ceph_file_part);
+
+const char *ceph_msg_type_name(int type)
+{
+       switch (type) {
+       case CEPH_MSG_SHUTDOWN: return "shutdown";
+       case CEPH_MSG_PING: return "ping";
+       case CEPH_MSG_AUTH: return "auth";
+       case CEPH_MSG_AUTH_REPLY: return "auth_reply";
+       case CEPH_MSG_MON_MAP: return "mon_map";
+       case CEPH_MSG_MON_GET_MAP: return "mon_get_map";
+       case CEPH_MSG_MON_SUBSCRIBE: return "mon_subscribe";
+       case CEPH_MSG_MON_SUBSCRIBE_ACK: return "mon_subscribe_ack";
+       case CEPH_MSG_STATFS: return "statfs";
+       case CEPH_MSG_STATFS_REPLY: return "statfs_reply";
+       case CEPH_MSG_MDS_MAP: return "mds_map";
+       case CEPH_MSG_CLIENT_SESSION: return "client_session";
+       case CEPH_MSG_CLIENT_RECONNECT: return "client_reconnect";
+       case CEPH_MSG_CLIENT_REQUEST: return "client_request";
+       case CEPH_MSG_CLIENT_REQUEST_FORWARD: return "client_request_forward";
+       case CEPH_MSG_CLIENT_REPLY: return "client_reply";
+       case CEPH_MSG_CLIENT_CAPS: return "client_caps";
+       case CEPH_MSG_CLIENT_CAPRELEASE: return "client_cap_release";
+       case CEPH_MSG_CLIENT_SNAP: return "client_snap";
+       case CEPH_MSG_CLIENT_LEASE: return "client_lease";
+       case CEPH_MSG_OSD_MAP: return "osd_map";
+       case CEPH_MSG_OSD_OP: return "osd_op";
+       case CEPH_MSG_OSD_OPREPLY: return "osd_opreply";
+       default: return "unknown";
+       }
+}
+EXPORT_SYMBOL(ceph_msg_type_name);
+
+/*
+ * Initially learn our fsid, or verify an fsid matches.
+ */
+int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid)
+{
+       if (client->have_fsid) {
+               if (ceph_fsid_compare(&client->fsid, fsid)) {
+                       pr_err("bad fsid, had %pU got %pU",
+                              &client->fsid, fsid);
+                       return -1;
+               }
+       } else {
+               pr_info("client%lld fsid %pU\n", ceph_client_id(client), fsid);
+               memcpy(&client->fsid, fsid, sizeof(*fsid));
+               ceph_debugfs_client_init(client);
+               client->have_fsid = true;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(ceph_check_fsid);
+
+static int strcmp_null(const char *s1, const char *s2)
+{
+       if (!s1 && !s2)
+               return 0;
+       if (s1 && !s2)
+               return -1;
+       if (!s1 && s2)
+               return 1;
+       return strcmp(s1, s2);
+}
+
+int ceph_compare_options(struct ceph_options *new_opt,
+                        struct ceph_client *client)
+{
+       struct ceph_options *opt1 = new_opt;
+       struct ceph_options *opt2 = client->options;
+       int ofs = offsetof(struct ceph_options, mon_addr);
+       int i;
+       int ret;
+
+       ret = memcmp(opt1, opt2, ofs);
+       if (ret)
+               return ret;
+
+       ret = strcmp_null(opt1->name, opt2->name);
+       if (ret)
+               return ret;
+
+       ret = strcmp_null(opt1->secret, opt2->secret);
+       if (ret)
+               return ret;
+
+       /* any matching mon ip implies a match */
+       for (i = 0; i < opt1->num_mon; i++) {
+               if (ceph_monmap_contains(client->monc.monmap,
+                                &opt1->mon_addr[i]))
+                       return 0;
+       }
+       return -1;
+}
+EXPORT_SYMBOL(ceph_compare_options);
+
+
+static int parse_fsid(const char *str, struct ceph_fsid *fsid)
+{
+       int i = 0;
+       char tmp[3];
+       int err = -EINVAL;
+       int d;
+
+       dout("parse_fsid '%s'\n", str);
+       tmp[2] = 0;
+       while (*str && i < 16) {
+               if (ispunct(*str)) {
+                       str++;
+                       continue;
+               }
+               if (!isxdigit(str[0]) || !isxdigit(str[1]))
+                       break;
+               tmp[0] = str[0];
+               tmp[1] = str[1];
+               if (sscanf(tmp, "%x", &d) < 1)
+                       break;
+               fsid->fsid[i] = d & 0xff;
+               i++;
+               str += 2;
+       }
+
+       if (i == 16)
+               err = 0;
+       dout("parse_fsid ret %d got fsid %pU", err, fsid);
+       return err;
+}
+
+/*
+ * ceph options
+ */
+enum {
+       Opt_osdtimeout,
+       Opt_osdkeepalivetimeout,
+       Opt_mount_timeout,
+       Opt_osd_idle_ttl,
+       Opt_last_int,
+       /* int args above */
+       Opt_fsid,
+       Opt_name,
+       Opt_secret,
+       Opt_ip,
+       Opt_last_string,
+       /* string args above */
+       Opt_noshare,
+       Opt_nocrc,
+};
+
+static match_table_t opt_tokens = {
+       {Opt_osdtimeout, "osdtimeout=%d"},
+       {Opt_osdkeepalivetimeout, "osdkeepalive=%d"},
+       {Opt_mount_timeout, "mount_timeout=%d"},
+       {Opt_osd_idle_ttl, "osd_idle_ttl=%d"},
+       /* int args above */
+       {Opt_fsid, "fsid=%s"},
+       {Opt_name, "name=%s"},
+       {Opt_secret, "secret=%s"},
+       {Opt_ip, "ip=%s"},
+       /* string args above */
+       {Opt_noshare, "noshare"},
+       {Opt_nocrc, "nocrc"},
+       {-1, NULL}
+};
+
+void ceph_destroy_options(struct ceph_options *opt)
+{
+       dout("destroy_options %p\n", opt);
+       kfree(opt->name);
+       kfree(opt->secret);
+       kfree(opt);
+}
+EXPORT_SYMBOL(ceph_destroy_options);
+
+int ceph_parse_options(struct ceph_options **popt, char *options,
+                      const char *dev_name, const char *dev_name_end,
+                      int (*parse_extra_token)(char *c, void *private),
+                      void *private)
+{
+       struct ceph_options *opt;
+       const char *c;
+       int err = -ENOMEM;
+       substring_t argstr[MAX_OPT_ARGS];
+
+       opt = kzalloc(sizeof(*opt), GFP_KERNEL);
+       if (!opt)
+               return err;
+       opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
+                               GFP_KERNEL);
+       if (!opt->mon_addr)
+               goto out;
+
+       dout("parse_options %p options '%s' dev_name '%s'\n", opt, options,
+            dev_name);
+
+       /* start with defaults */
+       opt->flags = CEPH_OPT_DEFAULT;
+       opt->osd_timeout = CEPH_OSD_TIMEOUT_DEFAULT;
+       opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
+       opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */
+       opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;   /* seconds */
+
+       /* get mon ip(s) */
+       /* ip1[:port1][,ip2[:port2]...] */
+       err = ceph_parse_ips(dev_name, dev_name_end, opt->mon_addr,
+                            CEPH_MAX_MON, &opt->num_mon);
+       if (err < 0)
+               goto out;
+
+       /* parse mount options */
+       while ((c = strsep(&options, ",")) != NULL) {
+               int token, intval, ret;
+               if (!*c)
+                       continue;
+               err = -EINVAL;
+               token = match_token((char *)c, opt_tokens, argstr);
+               if (token < 0 && parse_extra_token) {
+                       /* extra? */
+                       err = parse_extra_token((char *)c, private);
+                       if (err < 0) {
+                               pr_err("bad option at '%s'\n", c);
+                               goto out;
+                       }
+                       continue;
+               }
+               if (token < Opt_last_int) {
+                       ret = match_int(&argstr[0], &intval);
+                       if (ret < 0) {
+                               pr_err("bad mount option arg (not int) "
+                                      "at '%s'\n", c);
+                               continue;
+                       }
+                       dout("got int token %d val %d\n", token, intval);
+               } else if (token > Opt_last_int && token < Opt_last_string) {
+                       dout("got string token %d val %s\n", token,
+                            argstr[0].from);
+               } else {
+                       dout("got token %d\n", token);
+               }
+               switch (token) {
+               case Opt_ip:
+                       err = ceph_parse_ips(argstr[0].from,
+                                            argstr[0].to,
+                                            &opt->my_addr,
+                                            1, NULL);
+                       if (err < 0)
+                               goto out;
+                       opt->flags |= CEPH_OPT_MYIP;
+                       break;
+
+               case Opt_fsid:
+                       err = parse_fsid(argstr[0].from, &opt->fsid);
+                       if (err == 0)
+                               opt->flags |= CEPH_OPT_FSID;
+                       break;
+               case Opt_name:
+                       opt->name = kstrndup(argstr[0].from,
+                                             argstr[0].to-argstr[0].from,
+                                             GFP_KERNEL);
+                       break;
+               case Opt_secret:
+                       opt->secret = kstrndup(argstr[0].from,
+                                               argstr[0].to-argstr[0].from,
+                                               GFP_KERNEL);
+                       break;
+
+                       /* misc */
+               case Opt_osdtimeout:
+                       opt->osd_timeout = intval;
+                       break;
+               case Opt_osdkeepalivetimeout:
+                       opt->osd_keepalive_timeout = intval;
+                       break;
+               case Opt_osd_idle_ttl:
+                       opt->osd_idle_ttl = intval;
+                       break;
+               case Opt_mount_timeout:
+                       opt->mount_timeout = intval;
+                       break;
+
+               case Opt_noshare:
+                       opt->flags |= CEPH_OPT_NOSHARE;
+                       break;
+
+               case Opt_nocrc:
+                       opt->flags |= CEPH_OPT_NOCRC;
+                       break;
+
+               default:
+                       BUG_ON(token);
+               }
+       }
+
+       /* success */
+       *popt = opt;
+       return 0;
+
+out:
+       ceph_destroy_options(opt);
+       return err;
+}
+EXPORT_SYMBOL(ceph_parse_options);
+
+u64 ceph_client_id(struct ceph_client *client)
+{
+       return client->monc.auth->global_id;
+}
+EXPORT_SYMBOL(ceph_client_id);
+
+/*
+ * create a fresh client instance
+ */
+struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private)
+{
+       struct ceph_client *client;
+       int err = -ENOMEM;
+
+       client = kzalloc(sizeof(*client), GFP_KERNEL);
+       if (client == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       client->private = private;
+       client->options = opt;
+
+       mutex_init(&client->mount_mutex);
+       init_waitqueue_head(&client->auth_wq);
+       client->auth_err = 0;
+
+       client->extra_mon_dispatch = NULL;
+       client->supported_features = CEPH_FEATURE_SUPPORTED_DEFAULT;
+       client->required_features = CEPH_FEATURE_REQUIRED_DEFAULT;
+
+       client->msgr = NULL;
+
+       /* subsystems */
+       err = ceph_monc_init(&client->monc, client);
+       if (err < 0)
+               goto fail;
+       err = ceph_osdc_init(&client->osdc, client);
+       if (err < 0)
+               goto fail_monc;
+
+       return client;
+
+fail_monc:
+       ceph_monc_stop(&client->monc);
+fail:
+       kfree(client);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL(ceph_create_client);
+
+void ceph_destroy_client(struct ceph_client *client)
+{
+       dout("destroy_client %p\n", client);
+
+       /* unmount */
+       ceph_osdc_stop(&client->osdc);
+
+       /*
+        * make sure mds and osd connections close out before destroying
+        * the auth module, which is needed to free those connections'
+        * ceph_authorizers.
+        */
+       ceph_msgr_flush();
+
+       ceph_monc_stop(&client->monc);
+
+       ceph_debugfs_client_cleanup(client);
+
+       if (client->msgr)
+               ceph_messenger_destroy(client->msgr);
+
+       ceph_destroy_options(client->options);
+
+       kfree(client);
+       dout("destroy_client %p done\n", client);
+}
+EXPORT_SYMBOL(ceph_destroy_client);
+
+/*
+ * true if we have the mon map (and have thus joined the cluster)
+ */
+static int have_mon_and_osd_map(struct ceph_client *client)
+{
+       return client->monc.monmap && client->monc.monmap->epoch &&
+              client->osdc.osdmap && client->osdc.osdmap->epoch;
+}
+
+/*
+ * mount: join the ceph cluster, and open root directory.
+ */
+int __ceph_open_session(struct ceph_client *client, unsigned long started)
+{
+       struct ceph_entity_addr *myaddr = NULL;
+       int err;
+       unsigned long timeout = client->options->mount_timeout * HZ;
+
+       /* initialize the messenger */
+       if (client->msgr == NULL) {
+               if (ceph_test_opt(client, MYIP))
+                       myaddr = &client->options->my_addr;
+               client->msgr = ceph_messenger_create(myaddr,
+                                       client->supported_features,
+                                       client->required_features);
+               if (IS_ERR(client->msgr)) {
+                       client->msgr = NULL;
+                       return PTR_ERR(client->msgr);
+               }
+               client->msgr->nocrc = ceph_test_opt(client, NOCRC);
+       }
+
+       /* open session, and wait for mon and osd maps */
+       err = ceph_monc_open_session(&client->monc);
+       if (err < 0)
+               return err;
+
+       while (!have_mon_and_osd_map(client)) {
+               err = -EIO;
+               if (timeout && time_after_eq(jiffies, started + timeout))
+                       return err;
+
+               /* wait */
+               dout("mount waiting for mon_map\n");
+               err = wait_event_interruptible_timeout(client->auth_wq,
+                       have_mon_and_osd_map(client) || (client->auth_err < 0),
+                       timeout);
+               if (err == -EINTR || err == -ERESTARTSYS)
+                       return err;
+               if (client->auth_err < 0)
+                       return client->auth_err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(__ceph_open_session);
+
+
+int ceph_open_session(struct ceph_client *client)
+{
+       int ret;
+       unsigned long started = jiffies;  /* note the start time */
+
+       dout("open_session start\n");
+       mutex_lock(&client->mount_mutex);
+
+       ret = __ceph_open_session(client, started);
+
+       mutex_unlock(&client->mount_mutex);
+       return ret;
+}
+EXPORT_SYMBOL(ceph_open_session);
+
+
+static int __init init_ceph_lib(void)
+{
+       int ret = 0;
+
+       ret = ceph_debugfs_init();
+       if (ret < 0)
+               goto out;
+
+       ret = ceph_msgr_init();
+       if (ret < 0)
+               goto out_debugfs;
+
+       pr_info("loaded (mon/osd proto %d/%d, osdmap %d/%d %d/%d)\n",
+               CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL,
+               CEPH_OSDMAP_VERSION, CEPH_OSDMAP_VERSION_EXT,
+               CEPH_OSDMAP_INC_VERSION, CEPH_OSDMAP_INC_VERSION_EXT);
+
+       return 0;
+
+out_debugfs:
+       ceph_debugfs_cleanup();
+out:
+       return ret;
+}
+
+static void __exit exit_ceph_lib(void)
+{
+       dout("exit_ceph_lib\n");
+       ceph_msgr_exit();
+       ceph_debugfs_cleanup();
+}
+
+module_init(init_ceph_lib);
+module_exit(exit_ceph_lib);
+
+MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
+MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
+MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
+MODULE_DESCRIPTION("Ceph filesystem for Linux");
+MODULE_LICENSE("GPL");
similarity index 92%
rename from fs/ceph/ceph_fs.c
rename to net/ceph/ceph_fs.c
index 3ac6cc7c1156dafd78262e7290edf914c3f01e31..a3a3a31d3c37b0006d0e9bfe26fd06a7ebe3b47d 100644 (file)
@@ -1,7 +1,8 @@
 /*
  * Some non-inline ceph helpers
  */
-#include "types.h"
+#include <linux/module.h>
+#include <linux/ceph/types.h>
 
 /*
  * return true if @layout appears to be valid
@@ -52,6 +53,7 @@ int ceph_flags_to_mode(int flags)
 
        return mode;
 }
+EXPORT_SYMBOL(ceph_flags_to_mode);
 
 int ceph_caps_for_mode(int mode)
 {
@@ -70,3 +72,4 @@ int ceph_caps_for_mode(int mode)
 
        return caps;
 }
+EXPORT_SYMBOL(ceph_caps_for_mode);
similarity index 98%
rename from fs/ceph/ceph_hash.c
rename to net/ceph/ceph_hash.c
index bd570015d147ca2b1ce52061d359a56bb936a4df..815ef8826796a82b6b80030830a1663e9421b417 100644 (file)
@@ -1,5 +1,5 @@
 
-#include "types.h"
+#include <linux/ceph/types.h>
 
 /*
  * Robert Jenkin's hash function.
diff --git a/net/ceph/ceph_strings.c b/net/ceph/ceph_strings.c
new file mode 100644 (file)
index 0000000..3fbda04
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Ceph string constants
+ */
+#include <linux/module.h>
+#include <linux/ceph/types.h>
+
+const char *ceph_entity_type_name(int type)
+{
+       switch (type) {
+       case CEPH_ENTITY_TYPE_MDS: return "mds";
+       case CEPH_ENTITY_TYPE_OSD: return "osd";
+       case CEPH_ENTITY_TYPE_MON: return "mon";
+       case CEPH_ENTITY_TYPE_CLIENT: return "client";
+       case CEPH_ENTITY_TYPE_AUTH: return "auth";
+       default: return "unknown";
+       }
+}
+
+const char *ceph_osd_op_name(int op)
+{
+       switch (op) {
+       case CEPH_OSD_OP_READ: return "read";
+       case CEPH_OSD_OP_STAT: return "stat";
+
+       case CEPH_OSD_OP_MASKTRUNC: return "masktrunc";
+
+       case CEPH_OSD_OP_WRITE: return "write";
+       case CEPH_OSD_OP_DELETE: return "delete";
+       case CEPH_OSD_OP_TRUNCATE: return "truncate";
+       case CEPH_OSD_OP_ZERO: return "zero";
+       case CEPH_OSD_OP_WRITEFULL: return "writefull";
+       case CEPH_OSD_OP_ROLLBACK: return "rollback";
+
+       case CEPH_OSD_OP_APPEND: return "append";
+       case CEPH_OSD_OP_STARTSYNC: return "startsync";
+       case CEPH_OSD_OP_SETTRUNC: return "settrunc";
+       case CEPH_OSD_OP_TRIMTRUNC: return "trimtrunc";
+
+       case CEPH_OSD_OP_TMAPUP: return "tmapup";
+       case CEPH_OSD_OP_TMAPGET: return "tmapget";
+       case CEPH_OSD_OP_TMAPPUT: return "tmapput";
+
+       case CEPH_OSD_OP_GETXATTR: return "getxattr";
+       case CEPH_OSD_OP_GETXATTRS: return "getxattrs";
+       case CEPH_OSD_OP_SETXATTR: return "setxattr";
+       case CEPH_OSD_OP_SETXATTRS: return "setxattrs";
+       case CEPH_OSD_OP_RESETXATTRS: return "resetxattrs";
+       case CEPH_OSD_OP_RMXATTR: return "rmxattr";
+       case CEPH_OSD_OP_CMPXATTR: return "cmpxattr";
+
+       case CEPH_OSD_OP_PULL: return "pull";
+       case CEPH_OSD_OP_PUSH: return "push";
+       case CEPH_OSD_OP_BALANCEREADS: return "balance-reads";
+       case CEPH_OSD_OP_UNBALANCEREADS: return "unbalance-reads";
+       case CEPH_OSD_OP_SCRUB: return "scrub";
+
+       case CEPH_OSD_OP_WRLOCK: return "wrlock";
+       case CEPH_OSD_OP_WRUNLOCK: return "wrunlock";
+       case CEPH_OSD_OP_RDLOCK: return "rdlock";
+       case CEPH_OSD_OP_RDUNLOCK: return "rdunlock";
+       case CEPH_OSD_OP_UPLOCK: return "uplock";
+       case CEPH_OSD_OP_DNLOCK: return "dnlock";
+
+       case CEPH_OSD_OP_CALL: return "call";
+
+       case CEPH_OSD_OP_PGLS: return "pgls";
+       }
+       return "???";
+}
+
+
+const char *ceph_pool_op_name(int op)
+{
+       switch (op) {
+       case POOL_OP_CREATE: return "create";
+       case POOL_OP_DELETE: return "delete";
+       case POOL_OP_AUID_CHANGE: return "auid change";
+       case POOL_OP_CREATE_SNAP: return "create snap";
+       case POOL_OP_DELETE_SNAP: return "delete snap";
+       case POOL_OP_CREATE_UNMANAGED_SNAP: return "create unmanaged snap";
+       case POOL_OP_DELETE_UNMANAGED_SNAP: return "delete unmanaged snap";
+       }
+       return "???";
+}
similarity index 99%
rename from fs/ceph/crush/crush.c
rename to net/ceph/crush/crush.c
index fabd302e5779c0188b55916be81d7913dce84105..d6ebb13a18a4bc787eb249ad3e4b62ec1c174f97 100644 (file)
@@ -8,7 +8,7 @@
 # define BUG_ON(x) assert(!(x))
 #endif
 
-#include "crush.h"
+#include <linux/crush/crush.h>
 
 const char *crush_bucket_alg_name(int alg)
 {
similarity index 99%
rename from fs/ceph/crush/hash.c
rename to net/ceph/crush/hash.c
index 5873aed694bf5a06a092102a2209c5ad71a9aff8..5bb63e37a8a10f3419a399b32339cf5baf279762 100644 (file)
@@ -1,6 +1,6 @@
 
 #include <linux/types.h>
-#include "hash.h"
+#include <linux/crush/hash.h>
 
 /*
  * Robert Jenkins' function for mixing 32-bit values
similarity index 99%
rename from fs/ceph/crush/mapper.c
rename to net/ceph/crush/mapper.c
index a4eec133258e80a880a8cecca0282c54e11982ac..42599e31dcad8a6ceb1f3b29d9171f6a249e56a3 100644 (file)
@@ -18,8 +18,8 @@
 # define kfree(x) free(x)
 #endif
 
-#include "crush.h"
-#include "hash.h"
+#include <linux/crush/crush.h>
+#include <linux/crush/hash.h>
 
 /*
  * Implement the core CRUSH mapping algorithm.
similarity index 99%
rename from fs/ceph/crypto.c
rename to net/ceph/crypto.c
index a3e627f63293b2d329f620525328280a9ae15291..7b505b0c983f74eaffa51e306e38f2cd90aad3fb 100644 (file)
@@ -1,13 +1,13 @@
 
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/err.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <crypto/hash.h>
 
+#include <linux/ceph/decode.h>
 #include "crypto.h"
-#include "decode.h"
 
 int ceph_crypto_key_encode(struct ceph_crypto_key *key, void **p, void *end)
 {
similarity index 95%
rename from fs/ceph/crypto.h
rename to net/ceph/crypto.h
index bdf38607323c2da2eb87d2c3ebf7b3d158bd7d0d..f9eccace592b63b10a68c8f7d5d99abe2b2eba55 100644 (file)
@@ -1,8 +1,8 @@
 #ifndef _FS_CEPH_CRYPTO_H
 #define _FS_CEPH_CRYPTO_H
 
-#include "types.h"
-#include "buffer.h"
+#include <linux/ceph/types.h>
+#include <linux/ceph/buffer.h>
 
 /*
  * cryptographic secret
diff --git a/net/ceph/debugfs.c b/net/ceph/debugfs.c
new file mode 100644 (file)
index 0000000..27d4ea3
--- /dev/null
@@ -0,0 +1,267 @@
+#include <linux/ceph/ceph_debug.h>
+
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/mon_client.h>
+#include <linux/ceph/auth.h>
+#include <linux/ceph/debugfs.h>
+
+#ifdef CONFIG_DEBUG_FS
+
+/*
+ * Implement /sys/kernel/debug/ceph fun
+ *
+ * /sys/kernel/debug/ceph/client*  - an instance of the ceph client
+ *      .../osdmap      - current osdmap
+ *      .../monmap      - current monmap
+ *      .../osdc        - active osd requests
+ *      .../monc        - mon client state
+ *      .../dentry_lru  - dump contents of dentry lru
+ *      .../caps        - expose cap (reservation) stats
+ *      .../bdi         - symlink to ../../bdi/something
+ */
+
+static struct dentry *ceph_debugfs_dir;
+
+static int monmap_show(struct seq_file *s, void *p)
+{
+       int i;
+       struct ceph_client *client = s->private;
+
+       if (client->monc.monmap == NULL)
+               return 0;
+
+       seq_printf(s, "epoch %d\n", client->monc.monmap->epoch);
+       for (i = 0; i < client->monc.monmap->num_mon; i++) {
+               struct ceph_entity_inst *inst =
+                       &client->monc.monmap->mon_inst[i];
+
+               seq_printf(s, "\t%s%lld\t%s\n",
+                          ENTITY_NAME(inst->name),
+                          ceph_pr_addr(&inst->addr.in_addr));
+       }
+       return 0;
+}
+
+static int osdmap_show(struct seq_file *s, void *p)
+{
+       int i;
+       struct ceph_client *client = s->private;
+       struct rb_node *n;
+
+       if (client->osdc.osdmap == NULL)
+               return 0;
+       seq_printf(s, "epoch %d\n", client->osdc.osdmap->epoch);
+       seq_printf(s, "flags%s%s\n",
+                  (client->osdc.osdmap->flags & CEPH_OSDMAP_NEARFULL) ?
+                  " NEARFULL" : "",
+                  (client->osdc.osdmap->flags & CEPH_OSDMAP_FULL) ?
+                  " FULL" : "");
+       for (n = rb_first(&client->osdc.osdmap->pg_pools); n; n = rb_next(n)) {
+               struct ceph_pg_pool_info *pool =
+                       rb_entry(n, struct ceph_pg_pool_info, node);
+               seq_printf(s, "pg_pool %d pg_num %d / %d, lpg_num %d / %d\n",
+                          pool->id, pool->v.pg_num, pool->pg_num_mask,
+                          pool->v.lpg_num, pool->lpg_num_mask);
+       }
+       for (i = 0; i < client->osdc.osdmap->max_osd; i++) {
+               struct ceph_entity_addr *addr =
+                       &client->osdc.osdmap->osd_addr[i];
+               int state = client->osdc.osdmap->osd_state[i];
+               char sb[64];
+
+               seq_printf(s, "\tosd%d\t%s\t%3d%%\t(%s)\n",
+                          i, ceph_pr_addr(&addr->in_addr),
+                          ((client->osdc.osdmap->osd_weight[i]*100) >> 16),
+                          ceph_osdmap_state_str(sb, sizeof(sb), state));
+       }
+       return 0;
+}
+
+static int monc_show(struct seq_file *s, void *p)
+{
+       struct ceph_client *client = s->private;
+       struct ceph_mon_generic_request *req;
+       struct ceph_mon_client *monc = &client->monc;
+       struct rb_node *rp;
+
+       mutex_lock(&monc->mutex);
+
+       if (monc->have_mdsmap)
+               seq_printf(s, "have mdsmap %u\n", (unsigned)monc->have_mdsmap);
+       if (monc->have_osdmap)
+               seq_printf(s, "have osdmap %u\n", (unsigned)monc->have_osdmap);
+       if (monc->want_next_osdmap)
+               seq_printf(s, "want next osdmap\n");
+
+       for (rp = rb_first(&monc->generic_request_tree); rp; rp = rb_next(rp)) {
+               __u16 op;
+               req = rb_entry(rp, struct ceph_mon_generic_request, node);
+               op = le16_to_cpu(req->request->hdr.type);
+               if (op == CEPH_MSG_STATFS)
+                       seq_printf(s, "%lld statfs\n", req->tid);
+               else
+                       seq_printf(s, "%lld unknown\n", req->tid);
+       }
+
+       mutex_unlock(&monc->mutex);
+       return 0;
+}
+
+static int osdc_show(struct seq_file *s, void *pp)
+{
+       struct ceph_client *client = s->private;
+       struct ceph_osd_client *osdc = &client->osdc;
+       struct rb_node *p;
+
+       mutex_lock(&osdc->request_mutex);
+       for (p = rb_first(&osdc->requests); p; p = rb_next(p)) {
+               struct ceph_osd_request *req;
+               struct ceph_osd_request_head *head;
+               struct ceph_osd_op *op;
+               int num_ops;
+               int opcode, olen;
+               int i;
+
+               req = rb_entry(p, struct ceph_osd_request, r_node);
+
+               seq_printf(s, "%lld\tosd%d\t%d.%x\t", req->r_tid,
+                          req->r_osd ? req->r_osd->o_osd : -1,
+                          le32_to_cpu(req->r_pgid.pool),
+                          le16_to_cpu(req->r_pgid.ps));
+
+               head = req->r_request->front.iov_base;
+               op = (void *)(head + 1);
+
+               num_ops = le16_to_cpu(head->num_ops);
+               olen = le32_to_cpu(head->object_len);
+               seq_printf(s, "%.*s", olen,
+                          (const char *)(head->ops + num_ops));
+
+               if (req->r_reassert_version.epoch)
+                       seq_printf(s, "\t%u'%llu",
+                          (unsigned)le32_to_cpu(req->r_reassert_version.epoch),
+                          le64_to_cpu(req->r_reassert_version.version));
+               else
+                       seq_printf(s, "\t");
+
+               for (i = 0; i < num_ops; i++) {
+                       opcode = le16_to_cpu(op->op);
+                       seq_printf(s, "\t%s", ceph_osd_op_name(opcode));
+                       op++;
+               }
+
+               seq_printf(s, "\n");
+       }
+       mutex_unlock(&osdc->request_mutex);
+       return 0;
+}
+
+CEPH_DEFINE_SHOW_FUNC(monmap_show)
+CEPH_DEFINE_SHOW_FUNC(osdmap_show)
+CEPH_DEFINE_SHOW_FUNC(monc_show)
+CEPH_DEFINE_SHOW_FUNC(osdc_show)
+
+int ceph_debugfs_init(void)
+{
+       ceph_debugfs_dir = debugfs_create_dir("ceph", NULL);
+       if (!ceph_debugfs_dir)
+               return -ENOMEM;
+       return 0;
+}
+
+void ceph_debugfs_cleanup(void)
+{
+       debugfs_remove(ceph_debugfs_dir);
+}
+
+int ceph_debugfs_client_init(struct ceph_client *client)
+{
+       int ret = -ENOMEM;
+       char name[80];
+
+       snprintf(name, sizeof(name), "%pU.client%lld", &client->fsid,
+                client->monc.auth->global_id);
+
+       client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir);
+       if (!client->debugfs_dir)
+               goto out;
+
+       client->monc.debugfs_file = debugfs_create_file("monc",
+                                                     0600,
+                                                     client->debugfs_dir,
+                                                     client,
+                                                     &monc_show_fops);
+       if (!client->monc.debugfs_file)
+               goto out;
+
+       client->osdc.debugfs_file = debugfs_create_file("osdc",
+                                                     0600,
+                                                     client->debugfs_dir,
+                                                     client,
+                                                     &osdc_show_fops);
+       if (!client->osdc.debugfs_file)
+               goto out;
+
+       client->debugfs_monmap = debugfs_create_file("monmap",
+                                       0600,
+                                       client->debugfs_dir,
+                                       client,
+                                       &monmap_show_fops);
+       if (!client->debugfs_monmap)
+               goto out;
+
+       client->debugfs_osdmap = debugfs_create_file("osdmap",
+                                       0600,
+                                       client->debugfs_dir,
+                                       client,
+                                       &osdmap_show_fops);
+       if (!client->debugfs_osdmap)
+               goto out;
+
+       return 0;
+
+out:
+       ceph_debugfs_client_cleanup(client);
+       return ret;
+}
+
+void ceph_debugfs_client_cleanup(struct ceph_client *client)
+{
+       debugfs_remove(client->debugfs_osdmap);
+       debugfs_remove(client->debugfs_monmap);
+       debugfs_remove(client->osdc.debugfs_file);
+       debugfs_remove(client->monc.debugfs_file);
+       debugfs_remove(client->debugfs_dir);
+}
+
+#else  /* CONFIG_DEBUG_FS */
+
+int ceph_debugfs_init(void)
+{
+       return 0;
+}
+
+void ceph_debugfs_cleanup(void)
+{
+}
+
+int ceph_debugfs_client_init(struct ceph_client *client)
+{
+       return 0;
+}
+
+void ceph_debugfs_client_cleanup(struct ceph_client *client)
+{
+}
+
+#endif  /* CONFIG_DEBUG_FS */
+
+EXPORT_SYMBOL(ceph_debugfs_init);
+EXPORT_SYMBOL(ceph_debugfs_cleanup);
similarity index 89%
rename from fs/ceph/messenger.c
rename to net/ceph/messenger.c
index 2502d76fcec175ddb8500bcd1863c52add1208e5..0e8157ee5d4382a32992f34c2b1cf0d78f2868b4 100644 (file)
@@ -1,4 +1,4 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/crc32c.h>
 #include <linux/ctype.h>
@@ -9,12 +9,14 @@
 #include <linux/slab.h>
 #include <linux/socket.h>
 #include <linux/string.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
 #include <net/tcp.h>
 
-#include "super.h"
-#include "messenger.h"
-#include "decode.h"
-#include "pagelist.h"
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/messenger.h>
+#include <linux/ceph/decode.h>
+#include <linux/ceph/pagelist.h>
 
 /*
  * Ceph uses the messenger to exchange ceph_msg messages with other
@@ -48,7 +50,7 @@ static char addr_str[MAX_ADDR_STR][MAX_ADDR_STR_LEN];
 static DEFINE_SPINLOCK(addr_str_lock);
 static int last_addr_str;
 
-const char *pr_addr(const struct sockaddr_storage *ss)
+const char *ceph_pr_addr(const struct sockaddr_storage *ss)
 {
        int i;
        char *s;
@@ -79,6 +81,7 @@ const char *pr_addr(const struct sockaddr_storage *ss)
 
        return s;
 }
+EXPORT_SYMBOL(ceph_pr_addr);
 
 static void encode_my_addr(struct ceph_messenger *msgr)
 {
@@ -91,7 +94,7 @@ static void encode_my_addr(struct ceph_messenger *msgr)
  */
 struct workqueue_struct *ceph_msgr_wq;
 
-int __init ceph_msgr_init(void)
+int ceph_msgr_init(void)
 {
        ceph_msgr_wq = create_workqueue("ceph-msgr");
        if (IS_ERR(ceph_msgr_wq)) {
@@ -102,16 +105,19 @@ int __init ceph_msgr_init(void)
        }
        return 0;
 }
+EXPORT_SYMBOL(ceph_msgr_init);
 
 void ceph_msgr_exit(void)
 {
        destroy_workqueue(ceph_msgr_wq);
 }
+EXPORT_SYMBOL(ceph_msgr_exit);
 
 void ceph_msgr_flush(void)
 {
        flush_workqueue(ceph_msgr_wq);
 }
+EXPORT_SYMBOL(ceph_msgr_flush);
 
 
 /*
@@ -221,19 +227,19 @@ static struct socket *ceph_tcp_connect(struct ceph_connection *con)
 
        set_sock_callbacks(sock, con);
 
-       dout("connect %s\n", pr_addr(&con->peer_addr.in_addr));
+       dout("connect %s\n", ceph_pr_addr(&con->peer_addr.in_addr));
 
        ret = sock->ops->connect(sock, (struct sockaddr *)paddr, sizeof(*paddr),
                                 O_NONBLOCK);
        if (ret == -EINPROGRESS) {
                dout("connect %s EINPROGRESS sk_state = %u\n",
-                    pr_addr(&con->peer_addr.in_addr),
+                    ceph_pr_addr(&con->peer_addr.in_addr),
                     sock->sk->sk_state);
                ret = 0;
        }
        if (ret < 0) {
                pr_err("connect %s error %d\n",
-                      pr_addr(&con->peer_addr.in_addr), ret);
+                      ceph_pr_addr(&con->peer_addr.in_addr), ret);
                sock_release(sock);
                con->sock = NULL;
                con->error_msg = "connect error";
@@ -334,7 +340,8 @@ static void reset_connection(struct ceph_connection *con)
  */
 void ceph_con_close(struct ceph_connection *con)
 {
-       dout("con_close %p peer %s\n", con, pr_addr(&con->peer_addr.in_addr));
+       dout("con_close %p peer %s\n", con,
+            ceph_pr_addr(&con->peer_addr.in_addr));
        set_bit(CLOSED, &con->state);  /* in case there's queued work */
        clear_bit(STANDBY, &con->state);  /* avoid connect_seq bump */
        clear_bit(LOSSYTX, &con->state);  /* so we retry next connect */
@@ -347,19 +354,21 @@ void ceph_con_close(struct ceph_connection *con)
        mutex_unlock(&con->mutex);
        queue_con(con);
 }
+EXPORT_SYMBOL(ceph_con_close);
 
 /*
  * Reopen a closed connection, with a new peer address.
  */
 void ceph_con_open(struct ceph_connection *con, struct ceph_entity_addr *addr)
 {
-       dout("con_open %p %s\n", con, pr_addr(&addr->in_addr));
+       dout("con_open %p %s\n", con, ceph_pr_addr(&addr->in_addr));
        set_bit(OPENING, &con->state);
        clear_bit(CLOSED, &con->state);
        memcpy(&con->peer_addr, addr, sizeof(*addr));
        con->delay = 0;      /* reset backoff memory */
        queue_con(con);
 }
+EXPORT_SYMBOL(ceph_con_open);
 
 /*
  * return true if this connection ever successfully opened
@@ -406,6 +415,7 @@ void ceph_con_init(struct ceph_messenger *msgr, struct ceph_connection *con)
        INIT_LIST_HEAD(&con->out_sent);
        INIT_DELAYED_WORK(&con->work, con_work);
 }
+EXPORT_SYMBOL(ceph_con_init);
 
 
 /*
@@ -529,8 +539,11 @@ static void prepare_write_message(struct ceph_connection *con)
        if (le32_to_cpu(m->hdr.data_len) > 0) {
                /* initialize page iterator */
                con->out_msg_pos.page = 0;
-               con->out_msg_pos.page_pos =
-                       le16_to_cpu(m->hdr.data_off) & ~PAGE_MASK;
+               if (m->pages)
+                       con->out_msg_pos.page_pos =
+                               le16_to_cpu(m->hdr.data_off) & ~PAGE_MASK;
+               else
+                       con->out_msg_pos.page_pos = 0;
                con->out_msg_pos.data_pos = 0;
                con->out_msg_pos.did_page_crc = 0;
                con->out_more = 1;  /* data + footer will follow */
@@ -647,7 +660,7 @@ static void prepare_write_connect(struct ceph_messenger *msgr,
        dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con,
             con->connect_seq, global_seq, proto);
 
-       con->out_connect.features = cpu_to_le64(CEPH_FEATURE_SUPPORTED);
+       con->out_connect.features = cpu_to_le64(msgr->supported_features);
        con->out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT);
        con->out_connect.connect_seq = cpu_to_le32(con->connect_seq);
        con->out_connect.global_seq = cpu_to_le32(global_seq);
@@ -712,6 +725,31 @@ out:
        return ret;  /* done! */
 }
 
+#ifdef CONFIG_BLOCK
+static void init_bio_iter(struct bio *bio, struct bio **iter, int *seg)
+{
+       if (!bio) {
+               *iter = NULL;
+               *seg = 0;
+               return;
+       }
+       *iter = bio;
+       *seg = bio->bi_idx;
+}
+
+static void iter_bio_next(struct bio **bio_iter, int *seg)
+{
+       if (*bio_iter == NULL)
+               return;
+
+       BUG_ON(*seg >= (*bio_iter)->bi_vcnt);
+
+       (*seg)++;
+       if (*seg == (*bio_iter)->bi_vcnt)
+               init_bio_iter((*bio_iter)->bi_next, bio_iter, seg);
+}
+#endif
+
 /*
  * Write as much message data payload as we can.  If we finish, queue
  * up the footer.
@@ -726,21 +764,46 @@ static int write_partial_msg_pages(struct ceph_connection *con)
        size_t len;
        int crc = con->msgr->nocrc;
        int ret;
+       int total_max_write;
+       int in_trail = 0;
+       size_t trail_len = (msg->trail ? msg->trail->length : 0);
 
        dout("write_partial_msg_pages %p msg %p page %d/%d offset %d\n",
             con, con->out_msg, con->out_msg_pos.page, con->out_msg->nr_pages,
             con->out_msg_pos.page_pos);
 
-       while (con->out_msg_pos.page < con->out_msg->nr_pages) {
+#ifdef CONFIG_BLOCK
+       if (msg->bio && !msg->bio_iter)
+               init_bio_iter(msg->bio, &msg->bio_iter, &msg->bio_seg);
+#endif
+
+       while (data_len > con->out_msg_pos.data_pos) {
                struct page *page = NULL;
                void *kaddr = NULL;
+               int max_write = PAGE_SIZE;
+               int page_shift = 0;
+
+               total_max_write = data_len - trail_len -
+                       con->out_msg_pos.data_pos;
 
                /*
                 * if we are calculating the data crc (the default), we need
                 * to map the page.  if our pages[] has been revoked, use the
                 * zero page.
                 */
-               if (msg->pages) {
+
+               /* have we reached the trail part of the data? */
+               if (con->out_msg_pos.data_pos >= data_len - trail_len) {
+                       in_trail = 1;
+
+                       total_max_write = data_len - con->out_msg_pos.data_pos;
+
+                       page = list_first_entry(&msg->trail->head,
+                                               struct page, lru);
+                       if (crc)
+                               kaddr = kmap(page);
+                       max_write = PAGE_SIZE;
+               } else if (msg->pages) {
                        page = msg->pages[con->out_msg_pos.page];
                        if (crc)
                                kaddr = kmap(page);
@@ -749,13 +812,25 @@ static int write_partial_msg_pages(struct ceph_connection *con)
                                                struct page, lru);
                        if (crc)
                                kaddr = kmap(page);
+#ifdef CONFIG_BLOCK
+               } else if (msg->bio) {
+                       struct bio_vec *bv;
+
+                       bv = bio_iovec_idx(msg->bio_iter, msg->bio_seg);
+                       page = bv->bv_page;
+                       page_shift = bv->bv_offset;
+                       if (crc)
+                               kaddr = kmap(page) + page_shift;
+                       max_write = bv->bv_len;
+#endif
                } else {
                        page = con->msgr->zero_page;
                        if (crc)
                                kaddr = page_address(con->msgr->zero_page);
                }
-               len = min((int)(PAGE_SIZE - con->out_msg_pos.page_pos),
-                         (int)(data_len - con->out_msg_pos.data_pos));
+               len = min_t(int, max_write - con->out_msg_pos.page_pos,
+                           total_max_write);
+
                if (crc && !con->out_msg_pos.did_page_crc) {
                        void *base = kaddr + con->out_msg_pos.page_pos;
                        u32 tmpcrc = le32_to_cpu(con->out_msg->footer.data_crc);
@@ -765,13 +840,14 @@ static int write_partial_msg_pages(struct ceph_connection *con)
                                cpu_to_le32(crc32c(tmpcrc, base, len));
                        con->out_msg_pos.did_page_crc = 1;
                }
-
                ret = kernel_sendpage(con->sock, page,
-                                     con->out_msg_pos.page_pos, len,
+                                     con->out_msg_pos.page_pos + page_shift,
+                                     len,
                                      MSG_DONTWAIT | MSG_NOSIGNAL |
                                      MSG_MORE);
 
-               if (crc && (msg->pages || msg->pagelist))
+               if (crc &&
+                   (msg->pages || msg->pagelist || msg->bio || in_trail))
                        kunmap(page);
 
                if (ret <= 0)
@@ -783,9 +859,16 @@ static int write_partial_msg_pages(struct ceph_connection *con)
                        con->out_msg_pos.page_pos = 0;
                        con->out_msg_pos.page++;
                        con->out_msg_pos.did_page_crc = 0;
-                       if (msg->pagelist)
+                       if (in_trail)
+                               list_move_tail(&page->lru,
+                                              &msg->trail->head);
+                       else if (msg->pagelist)
                                list_move_tail(&page->lru,
                                               &msg->pagelist->head);
+#ifdef CONFIG_BLOCK
+                       else if (msg->bio)
+                               iter_bio_next(&msg->bio_iter, &msg->bio_seg);
+#endif
                }
        }
 
@@ -938,7 +1021,7 @@ static int verify_hello(struct ceph_connection *con)
 {
        if (memcmp(con->in_banner, CEPH_BANNER, strlen(CEPH_BANNER))) {
                pr_err("connect to %s got bad banner\n",
-                      pr_addr(&con->peer_addr.in_addr));
+                      ceph_pr_addr(&con->peer_addr.in_addr));
                con->error_msg = "protocol error, bad banner";
                return -1;
        }
@@ -1041,7 +1124,7 @@ int ceph_parse_ips(const char *c, const char *end,
 
                addr_set_port(ss, port);
 
-               dout("parse_ips got %s\n", pr_addr(ss));
+               dout("parse_ips got %s\n", ceph_pr_addr(ss));
 
                if (p == end)
                        break;
@@ -1061,6 +1144,7 @@ bad:
        pr_err("parse_ips bad ip '%.*s'\n", (int)(end - c), c);
        return -EINVAL;
 }
+EXPORT_SYMBOL(ceph_parse_ips);
 
 static int process_banner(struct ceph_connection *con)
 {
@@ -1082,9 +1166,9 @@ static int process_banner(struct ceph_connection *con)
            !(addr_is_blank(&con->actual_peer_addr.in_addr) &&
              con->actual_peer_addr.nonce == con->peer_addr.nonce)) {
                pr_warning("wrong peer, want %s/%d, got %s/%d\n",
-                          pr_addr(&con->peer_addr.in_addr),
+                          ceph_pr_addr(&con->peer_addr.in_addr),
                           (int)le32_to_cpu(con->peer_addr.nonce),
-                          pr_addr(&con->actual_peer_addr.in_addr),
+                          ceph_pr_addr(&con->actual_peer_addr.in_addr),
                           (int)le32_to_cpu(con->actual_peer_addr.nonce));
                con->error_msg = "wrong peer at address";
                return -1;
@@ -1102,7 +1186,7 @@ static int process_banner(struct ceph_connection *con)
                addr_set_port(&con->msgr->inst.addr.in_addr, port);
                encode_my_addr(con->msgr);
                dout("process_banner learned my addr is %s\n",
-                    pr_addr(&con->msgr->inst.addr.in_addr));
+                    ceph_pr_addr(&con->msgr->inst.addr.in_addr));
        }
 
        set_bit(NEGOTIATING, &con->state);
@@ -1123,8 +1207,8 @@ static void fail_protocol(struct ceph_connection *con)
 
 static int process_connect(struct ceph_connection *con)
 {
-       u64 sup_feat = CEPH_FEATURE_SUPPORTED;
-       u64 req_feat = CEPH_FEATURE_REQUIRED;
+       u64 sup_feat = con->msgr->supported_features;
+       u64 req_feat = con->msgr->required_features;
        u64 server_feat = le64_to_cpu(con->in_reply.features);
 
        dout("process_connect on %p tag %d\n", con, (int)con->in_tag);
@@ -1134,7 +1218,7 @@ static int process_connect(struct ceph_connection *con)
                pr_err("%s%lld %s feature set mismatch,"
                       " my %llx < server's %llx, missing %llx\n",
                       ENTITY_NAME(con->peer_name),
-                      pr_addr(&con->peer_addr.in_addr),
+                      ceph_pr_addr(&con->peer_addr.in_addr),
                       sup_feat, server_feat, server_feat & ~sup_feat);
                con->error_msg = "missing required protocol features";
                fail_protocol(con);
@@ -1144,7 +1228,7 @@ static int process_connect(struct ceph_connection *con)
                pr_err("%s%lld %s protocol version mismatch,"
                       " my %d != server's %d\n",
                       ENTITY_NAME(con->peer_name),
-                      pr_addr(&con->peer_addr.in_addr),
+                      ceph_pr_addr(&con->peer_addr.in_addr),
                       le32_to_cpu(con->out_connect.protocol_version),
                       le32_to_cpu(con->in_reply.protocol_version));
                con->error_msg = "protocol version mismatch";
@@ -1178,7 +1262,7 @@ static int process_connect(struct ceph_connection *con)
                     le32_to_cpu(con->in_connect.connect_seq));
                pr_err("%s%lld %s connection reset\n",
                       ENTITY_NAME(con->peer_name),
-                      pr_addr(&con->peer_addr.in_addr));
+                      ceph_pr_addr(&con->peer_addr.in_addr));
                reset_connection(con);
                prepare_write_connect(con->msgr, con, 0);
                prepare_read_connect(con);
@@ -1223,7 +1307,7 @@ static int process_connect(struct ceph_connection *con)
                        pr_err("%s%lld %s protocol feature mismatch,"
                               " my required %llx > server's %llx, need %llx\n",
                               ENTITY_NAME(con->peer_name),
-                              pr_addr(&con->peer_addr.in_addr),
+                              ceph_pr_addr(&con->peer_addr.in_addr),
                               req_feat, server_feat, req_feat & ~server_feat);
                        con->error_msg = "missing required protocol features";
                        fail_protocol(con);
@@ -1305,8 +1389,7 @@ static int read_partial_message_section(struct ceph_connection *con,
                                        struct kvec *section,
                                        unsigned int sec_len, u32 *crc)
 {
-       int left;
-       int ret;
+       int ret, left;
 
        BUG_ON(!section);
 
@@ -1329,13 +1412,83 @@ static int read_partial_message_section(struct ceph_connection *con,
 static struct ceph_msg *ceph_alloc_msg(struct ceph_connection *con,
                                struct ceph_msg_header *hdr,
                                int *skip);
+
+
+static int read_partial_message_pages(struct ceph_connection *con,
+                                     struct page **pages,
+                                     unsigned data_len, int datacrc)
+{
+       void *p;
+       int ret;
+       int left;
+
+       left = min((int)(data_len - con->in_msg_pos.data_pos),
+                  (int)(PAGE_SIZE - con->in_msg_pos.page_pos));
+       /* (page) data */
+       BUG_ON(pages == NULL);
+       p = kmap(pages[con->in_msg_pos.page]);
+       ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos,
+                              left);
+       if (ret > 0 && datacrc)
+               con->in_data_crc =
+                       crc32c(con->in_data_crc,
+                                 p + con->in_msg_pos.page_pos, ret);
+       kunmap(pages[con->in_msg_pos.page]);
+       if (ret <= 0)
+               return ret;
+       con->in_msg_pos.data_pos += ret;
+       con->in_msg_pos.page_pos += ret;
+       if (con->in_msg_pos.page_pos == PAGE_SIZE) {
+               con->in_msg_pos.page_pos = 0;
+               con->in_msg_pos.page++;
+       }
+
+       return ret;
+}
+
+#ifdef CONFIG_BLOCK
+static int read_partial_message_bio(struct ceph_connection *con,
+                                   struct bio **bio_iter, int *bio_seg,
+                                   unsigned data_len, int datacrc)
+{
+       struct bio_vec *bv = bio_iovec_idx(*bio_iter, *bio_seg);
+       void *p;
+       int ret, left;
+
+       if (IS_ERR(bv))
+               return PTR_ERR(bv);
+
+       left = min((int)(data_len - con->in_msg_pos.data_pos),
+                  (int)(bv->bv_len - con->in_msg_pos.page_pos));
+
+       p = kmap(bv->bv_page) + bv->bv_offset;
+
+       ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos,
+                              left);
+       if (ret > 0 && datacrc)
+               con->in_data_crc =
+                       crc32c(con->in_data_crc,
+                                 p + con->in_msg_pos.page_pos, ret);
+       kunmap(bv->bv_page);
+       if (ret <= 0)
+               return ret;
+       con->in_msg_pos.data_pos += ret;
+       con->in_msg_pos.page_pos += ret;
+       if (con->in_msg_pos.page_pos == bv->bv_len) {
+               con->in_msg_pos.page_pos = 0;
+               iter_bio_next(bio_iter, bio_seg);
+       }
+
+       return ret;
+}
+#endif
+
 /*
  * read (part of) a message.
  */
 static int read_partial_message(struct ceph_connection *con)
 {
        struct ceph_msg *m = con->in_msg;
-       void *p;
        int ret;
        int to, left;
        unsigned front_len, middle_len, data_len, data_off;
@@ -1381,7 +1534,7 @@ static int read_partial_message(struct ceph_connection *con)
        if ((s64)seq - (s64)con->in_seq < 1) {
                pr_info("skipping %s%lld %s seq %lld, expected %lld\n",
                        ENTITY_NAME(con->peer_name),
-                       pr_addr(&con->peer_addr.in_addr),
+                       ceph_pr_addr(&con->peer_addr.in_addr),
                        seq, con->in_seq + 1);
                con->in_base_pos = -front_len - middle_len - data_len -
                        sizeof(m->footer);
@@ -1422,7 +1575,10 @@ static int read_partial_message(struct ceph_connection *con)
                        m->middle->vec.iov_len = 0;
 
                con->in_msg_pos.page = 0;
-               con->in_msg_pos.page_pos = data_off & ~PAGE_MASK;
+               if (m->pages)
+                       con->in_msg_pos.page_pos = data_off & ~PAGE_MASK;
+               else
+                       con->in_msg_pos.page_pos = 0;
                con->in_msg_pos.data_pos = 0;
        }
 
@@ -1440,27 +1596,29 @@ static int read_partial_message(struct ceph_connection *con)
                if (ret <= 0)
                        return ret;
        }
+#ifdef CONFIG_BLOCK
+       if (m->bio && !m->bio_iter)
+               init_bio_iter(m->bio, &m->bio_iter, &m->bio_seg);
+#endif
 
        /* (page) data */
        while (con->in_msg_pos.data_pos < data_len) {
-               left = min((int)(data_len - con->in_msg_pos.data_pos),
-                          (int)(PAGE_SIZE - con->in_msg_pos.page_pos));
-               BUG_ON(m->pages == NULL);
-               p = kmap(m->pages[con->in_msg_pos.page]);
-               ret = ceph_tcp_recvmsg(con->sock, p + con->in_msg_pos.page_pos,
-                                      left);
-               if (ret > 0 && datacrc)
-                       con->in_data_crc =
-                               crc32c(con->in_data_crc,
-                                         p + con->in_msg_pos.page_pos, ret);
-               kunmap(m->pages[con->in_msg_pos.page]);
-               if (ret <= 0)
-                       return ret;
-               con->in_msg_pos.data_pos += ret;
-               con->in_msg_pos.page_pos += ret;
-               if (con->in_msg_pos.page_pos == PAGE_SIZE) {
-                       con->in_msg_pos.page_pos = 0;
-                       con->in_msg_pos.page++;
+               if (m->pages) {
+                       ret = read_partial_message_pages(con, m->pages,
+                                                data_len, datacrc);
+                       if (ret <= 0)
+                               return ret;
+#ifdef CONFIG_BLOCK
+               } else if (m->bio) {
+
+                       ret = read_partial_message_bio(con,
+                                                &m->bio_iter, &m->bio_seg,
+                                                data_len, datacrc);
+                       if (ret <= 0)
+                               return ret;
+#endif
+               } else {
+                       BUG_ON(1);
                }
        }
 
@@ -1874,9 +2032,9 @@ out:
 static void ceph_fault(struct ceph_connection *con)
 {
        pr_err("%s%lld %s %s\n", ENTITY_NAME(con->peer_name),
-              pr_addr(&con->peer_addr.in_addr), con->error_msg);
+              ceph_pr_addr(&con->peer_addr.in_addr), con->error_msg);
        dout("fault %p state %lu to peer %s\n",
-            con, con->state, pr_addr(&con->peer_addr.in_addr));
+            con, con->state, ceph_pr_addr(&con->peer_addr.in_addr));
 
        if (test_bit(LOSSYTX, &con->state)) {
                dout("fault on LOSSYTX channel\n");
@@ -1936,7 +2094,9 @@ out:
 /*
  * create a new messenger instance
  */
-struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr)
+struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr,
+                                            u32 supported_features,
+                                            u32 required_features)
 {
        struct ceph_messenger *msgr;
 
@@ -1944,6 +2104,9 @@ struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr)
        if (msgr == NULL)
                return ERR_PTR(-ENOMEM);
 
+       msgr->supported_features = supported_features;
+       msgr->required_features = required_features;
+
        spin_lock_init(&msgr->global_seq_lock);
 
        /* the zero page is needed if a request is "canceled" while the message
@@ -1966,6 +2129,7 @@ struct ceph_messenger *ceph_messenger_create(struct ceph_entity_addr *myaddr)
        dout("messenger_create %p\n", msgr);
        return msgr;
 }
+EXPORT_SYMBOL(ceph_messenger_create);
 
 void ceph_messenger_destroy(struct ceph_messenger *msgr)
 {
@@ -1975,6 +2139,7 @@ void ceph_messenger_destroy(struct ceph_messenger *msgr)
        kfree(msgr);
        dout("destroyed messenger %p\n", msgr);
 }
+EXPORT_SYMBOL(ceph_messenger_destroy);
 
 /*
  * Queue up an outgoing message on the given connection.
@@ -2011,6 +2176,7 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
        if (test_and_set_bit(WRITE_PENDING, &con->state) == 0)
                queue_con(con);
 }
+EXPORT_SYMBOL(ceph_con_send);
 
 /*
  * Revoke a message that was previously queued for send
@@ -2076,6 +2242,7 @@ void ceph_con_keepalive(struct ceph_connection *con)
            test_and_set_bit(WRITE_PENDING, &con->state) == 0)
                queue_con(con);
 }
+EXPORT_SYMBOL(ceph_con_keepalive);
 
 
 /*
@@ -2136,6 +2303,10 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags)
        m->nr_pages = 0;
        m->pages = NULL;
        m->pagelist = NULL;
+       m->bio = NULL;
+       m->bio_iter = NULL;
+       m->bio_seg = 0;
+       m->trail = NULL;
 
        dout("ceph_msg_new %p front %d\n", m, front_len);
        return m;
@@ -2146,6 +2317,7 @@ out:
        pr_err("msg_new can't create type %d front %d\n", type, front_len);
        return NULL;
 }
+EXPORT_SYMBOL(ceph_msg_new);
 
 /*
  * Allocate "middle" portion of a message, if it is needed and wasn't
@@ -2250,11 +2422,14 @@ void ceph_msg_last_put(struct kref *kref)
                m->pagelist = NULL;
        }
 
+       m->trail = NULL;
+
        if (m->pool)
                ceph_msgpool_put(m->pool, m);
        else
                ceph_msg_kfree(m);
 }
+EXPORT_SYMBOL(ceph_msg_last_put);
 
 void ceph_msg_dump(struct ceph_msg *msg)
 {
@@ -2275,3 +2450,4 @@ void ceph_msg_dump(struct ceph_msg *msg)
                       DUMP_PREFIX_OFFSET, 16, 1,
                       &msg->footer, sizeof(msg->footer), true);
 }
+EXPORT_SYMBOL(ceph_msg_dump);
similarity index 94%
rename from fs/ceph/mon_client.c
rename to net/ceph/mon_client.c
index b2a5a3e4a671c336fc7495d473792ddc25f71110..8a079399174a27fc0c86e50e0891318cbb33cf97 100644 (file)
@@ -1,14 +1,16 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/random.h>
 #include <linux/sched.h>
 
-#include "mon_client.h"
-#include "super.h"
-#include "auth.h"
-#include "decode.h"
+#include <linux/ceph/mon_client.h>
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/decode.h>
+
+#include <linux/ceph/auth.h>
 
 /*
  * Interact with Ceph monitor cluster.  Handle requests for new map
@@ -74,7 +76,7 @@ struct ceph_monmap *ceph_monmap_decode(void *p, void *end)
             m->num_mon);
        for (i = 0; i < m->num_mon; i++)
                dout("monmap_decode  mon%d is %s\n", i,
-                    pr_addr(&m->mon_inst[i].addr.in_addr));
+                    ceph_pr_addr(&m->mon_inst[i].addr.in_addr));
        return m;
 
 bad:
@@ -191,30 +193,33 @@ static void __send_subscribe(struct ceph_mon_client *monc)
                struct ceph_msg *msg = monc->m_subscribe;
                struct ceph_mon_subscribe_item *i;
                void *p, *end;
+               int num;
 
                p = msg->front.iov_base;
                end = p + msg->front_max;
 
-               dout("__send_subscribe to 'mdsmap' %u+\n",
-                    (unsigned)monc->have_mdsmap);
+               num = 1 + !!monc->want_next_osdmap + !!monc->want_mdsmap;
+               ceph_encode_32(&p, num);
+
                if (monc->want_next_osdmap) {
                        dout("__send_subscribe to 'osdmap' %u\n",
                             (unsigned)monc->have_osdmap);
-                       ceph_encode_32(&p, 3);
                        ceph_encode_string(&p, end, "osdmap", 6);
                        i = p;
                        i->have = cpu_to_le64(monc->have_osdmap);
                        i->onetime = 1;
                        p += sizeof(*i);
                        monc->want_next_osdmap = 2;  /* requested */
-               } else {
-                       ceph_encode_32(&p, 2);
                }
-               ceph_encode_string(&p, end, "mdsmap", 6);
-               i = p;
-               i->have = cpu_to_le64(monc->have_mdsmap);
-               i->onetime = 0;
-               p += sizeof(*i);
+               if (monc->want_mdsmap) {
+                       dout("__send_subscribe to 'mdsmap' %u+\n",
+                            (unsigned)monc->have_mdsmap);
+                       ceph_encode_string(&p, end, "mdsmap", 6);
+                       i = p;
+                       i->have = cpu_to_le64(monc->have_mdsmap);
+                       i->onetime = 0;
+                       p += sizeof(*i);
+               }
                ceph_encode_string(&p, end, "monmap", 6);
                i = p;
                i->have = 0;
@@ -243,7 +248,8 @@ static void handle_subscribe_ack(struct ceph_mon_client *monc,
        mutex_lock(&monc->mutex);
        if (monc->hunting) {
                pr_info("mon%d %s session established\n",
-                       monc->cur_mon, pr_addr(&monc->con->peer_addr.in_addr));
+                       monc->cur_mon,
+                       ceph_pr_addr(&monc->con->peer_addr.in_addr));
                monc->hunting = false;
        }
        dout("handle_subscribe_ack after %d seconds\n", seconds);
@@ -266,6 +272,7 @@ int ceph_monc_got_mdsmap(struct ceph_mon_client *monc, u32 got)
        mutex_unlock(&monc->mutex);
        return 0;
 }
+EXPORT_SYMBOL(ceph_monc_got_mdsmap);
 
 int ceph_monc_got_osdmap(struct ceph_mon_client *monc, u32 got)
 {
@@ -310,6 +317,7 @@ int ceph_monc_open_session(struct ceph_mon_client *monc)
        mutex_unlock(&monc->mutex);
        return 0;
 }
+EXPORT_SYMBOL(ceph_monc_open_session);
 
 /*
  * The monitor responds with mount ack indicate mount success.  The
@@ -540,6 +548,7 @@ out:
        kref_put(&req->kref, release_generic_request);
        return err;
 }
+EXPORT_SYMBOL(ceph_monc_do_statfs);
 
 /*
  * pool ops
@@ -651,6 +660,7 @@ int ceph_monc_create_snapid(struct ceph_mon_client *monc,
                                   pool, 0, (char *)snapid, sizeof(*snapid));
 
 }
+EXPORT_SYMBOL(ceph_monc_create_snapid);
 
 int ceph_monc_delete_snapid(struct ceph_mon_client *monc,
                            u32 pool, u64 snapid)
@@ -708,9 +718,9 @@ static void delayed_work(struct work_struct *work)
  */
 static int build_initial_monmap(struct ceph_mon_client *monc)
 {
-       struct ceph_mount_args *args = monc->client->mount_args;
-       struct ceph_entity_addr *mon_addr = args->mon_addr;
-       int num_mon = args->num_mon;
+       struct ceph_options *opt = monc->client->options;
+       struct ceph_entity_addr *mon_addr = opt->mon_addr;
+       int num_mon = opt->num_mon;
        int i;
 
        /* build initial monmap */
@@ -728,11 +738,6 @@ static int build_initial_monmap(struct ceph_mon_client *monc)
        }
        monc->monmap->num_mon = num_mon;
        monc->have_fsid = false;
-
-       /* release addr memory */
-       kfree(args->mon_addr);
-       args->mon_addr = NULL;
-       args->num_mon = 0;
        return 0;
 }
 
@@ -753,8 +758,8 @@ int ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
        monc->con = NULL;
 
        /* authentication */
-       monc->auth = ceph_auth_init(cl->mount_args->name,
-                                   cl->mount_args->secret);
+       monc->auth = ceph_auth_init(cl->options->name,
+                                   cl->options->secret);
        if (IS_ERR(monc->auth))
                return PTR_ERR(monc->auth);
        monc->auth->want_keys =
@@ -808,6 +813,7 @@ out_monmap:
 out:
        return err;
 }
+EXPORT_SYMBOL(ceph_monc_init);
 
 void ceph_monc_stop(struct ceph_mon_client *monc)
 {
@@ -832,6 +838,7 @@ void ceph_monc_stop(struct ceph_mon_client *monc)
 
        kfree(monc->monmap);
 }
+EXPORT_SYMBOL(ceph_monc_stop);
 
 static void handle_auth_reply(struct ceph_mon_client *monc,
                              struct ceph_msg *msg)
@@ -889,6 +896,7 @@ int ceph_monc_validate_auth(struct ceph_mon_client *monc)
        mutex_unlock(&monc->mutex);
        return ret;
 }
+EXPORT_SYMBOL(ceph_monc_validate_auth);
 
 /*
  * handle incoming message
@@ -922,15 +930,16 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
                ceph_monc_handle_map(monc, msg);
                break;
 
-       case CEPH_MSG_MDS_MAP:
-               ceph_mdsc_handle_map(&monc->client->mdsc, msg);
-               break;
-
        case CEPH_MSG_OSD_MAP:
                ceph_osdc_handle_map(&monc->client->osdc, msg);
                break;
 
        default:
+               /* can the chained handler handle it? */
+               if (monc->client->extra_mon_dispatch &&
+                   monc->client->extra_mon_dispatch(monc->client, msg) == 0)
+                       break;
+                       
                pr_err("received unknown message type %d %s\n", type,
                       ceph_msg_type_name(type));
        }
@@ -994,7 +1003,7 @@ static void mon_fault(struct ceph_connection *con)
        if (monc->con && !monc->hunting)
                pr_info("mon%d %s session lost, "
                        "hunting for new mon\n", monc->cur_mon,
-                       pr_addr(&monc->con->peer_addr.in_addr));
+                       ceph_pr_addr(&monc->con->peer_addr.in_addr));
 
        __close_session(monc);
        if (!monc->hunting) {
similarity index 95%
rename from fs/ceph/msgpool.c
rename to net/ceph/msgpool.c
index dd65a6438131c5f08cbe97085b6b1ba3f671076d..d5f2d97ac05caf40124fe4f628efe77a514d8e55 100644 (file)
@@ -1,11 +1,11 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
 #include <linux/err.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/vmalloc.h>
 
-#include "msgpool.h"
+#include <linux/ceph/msgpool.h>
 
 static void *alloc_fn(gfp_t gfp_mask, void *arg)
 {
similarity index 84%
rename from fs/ceph/osd_client.c
rename to net/ceph/osd_client.c
index 3b5571b8ce22e2ef8abdcf3d2dd4da1598bf6233..79391994b3edee7d531b823c0720262090db6618 100644 (file)
@@ -1,17 +1,22 @@
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
+#include <linux/module.h>
 #include <linux/err.h>
 #include <linux/highmem.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#ifdef CONFIG_BLOCK
+#include <linux/bio.h>
+#endif
 
-#include "super.h"
-#include "osd_client.h"
-#include "messenger.h"
-#include "decode.h"
-#include "auth.h"
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/osd_client.h>
+#include <linux/ceph/messenger.h>
+#include <linux/ceph/decode.h>
+#include <linux/ceph/auth.h>
+#include <linux/ceph/pagelist.h>
 
 #define OSD_OP_FRONT_LEN       4096
 #define OSD_OPREPLY_FRONT_LEN  512
@@ -22,6 +27,59 @@ static int __kick_requests(struct ceph_osd_client *osdc,
 
 static void kick_requests(struct ceph_osd_client *osdc, struct ceph_osd *osd);
 
+static int op_needs_trail(int op)
+{
+       switch (op) {
+       case CEPH_OSD_OP_GETXATTR:
+       case CEPH_OSD_OP_SETXATTR:
+       case CEPH_OSD_OP_CMPXATTR:
+       case CEPH_OSD_OP_CALL:
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+static int op_has_extent(int op)
+{
+       return (op == CEPH_OSD_OP_READ ||
+               op == CEPH_OSD_OP_WRITE);
+}
+
+void ceph_calc_raw_layout(struct ceph_osd_client *osdc,
+                       struct ceph_file_layout *layout,
+                       u64 snapid,
+                       u64 off, u64 *plen, u64 *bno,
+                       struct ceph_osd_request *req,
+                       struct ceph_osd_req_op *op)
+{
+       struct ceph_osd_request_head *reqhead = req->r_request->front.iov_base;
+       u64 orig_len = *plen;
+       u64 objoff, objlen;    /* extent in object */
+
+       reqhead->snapid = cpu_to_le64(snapid);
+
+       /* object extent? */
+       ceph_calc_file_object_mapping(layout, off, plen, bno,
+                                     &objoff, &objlen);
+       if (*plen < orig_len)
+               dout(" skipping last %llu, final file extent %llu~%llu\n",
+                    orig_len - *plen, off, *plen);
+
+       if (op_has_extent(op->op)) {
+               op->extent.offset = objoff;
+               op->extent.length = objlen;
+       }
+       req->r_num_pages = calc_pages_for(off, *plen);
+       if (op->op == CEPH_OSD_OP_WRITE)
+               op->payload_len = *plen;
+
+       dout("calc_layout bno=%llx %llu~%llu (%d pages)\n",
+            *bno, objoff, objlen, req->r_num_pages);
+
+}
+EXPORT_SYMBOL(ceph_calc_raw_layout);
+
 /*
  * Implement client access to distributed object storage cluster.
  *
@@ -48,34 +106,19 @@ static void kick_requests(struct ceph_osd_client *osdc, struct ceph_osd *osd);
  * fill osd op in request message.
  */
 static void calc_layout(struct ceph_osd_client *osdc,
-                       struct ceph_vino vino, struct ceph_file_layout *layout,
+                       struct ceph_vino vino,
+                       struct ceph_file_layout *layout,
                        u64 off, u64 *plen,
-                       struct ceph_osd_request *req)
+                       struct ceph_osd_request *req,
+                       struct ceph_osd_req_op *op)
 {
-       struct ceph_osd_request_head *reqhead = req->r_request->front.iov_base;
-       struct ceph_osd_op *op = (void *)(reqhead + 1);
-       u64 orig_len = *plen;
-       u64 objoff, objlen;    /* extent in object */
        u64 bno;
 
-       reqhead->snapid = cpu_to_le64(vino.snap);
-
-       /* object extent? */
-       ceph_calc_file_object_mapping(layout, off, plen, &bno,
-                                     &objoff, &objlen);
-       if (*plen < orig_len)
-               dout(" skipping last %llu, final file extent %llu~%llu\n",
-                    orig_len - *plen, off, *plen);
+       ceph_calc_raw_layout(osdc, layout, vino.snap, off,
+                            plen, &bno, req, op);
 
        sprintf(req->r_oid, "%llx.%08llx", vino.ino, bno);
        req->r_oid_len = strlen(req->r_oid);
-
-       op->extent.offset = cpu_to_le64(objoff);
-       op->extent.length = cpu_to_le64(objlen);
-       req->r_num_pages = calc_pages_for(off, *plen);
-
-       dout("calc_layout %s (%d) %llu~%llu (%d pages)\n",
-            req->r_oid, req->r_oid_len, objoff, objlen, req->r_num_pages);
 }
 
 /*
@@ -101,56 +144,66 @@ void ceph_osdc_release_request(struct kref *kref)
        if (req->r_own_pages)
                ceph_release_page_vector(req->r_pages,
                                         req->r_num_pages);
+#ifdef CONFIG_BLOCK
+       if (req->r_bio)
+               bio_put(req->r_bio);
+#endif
        ceph_put_snap_context(req->r_snapc);
+       if (req->r_trail) {
+               ceph_pagelist_release(req->r_trail);
+               kfree(req->r_trail);
+       }
        if (req->r_mempool)
                mempool_free(req, req->r_osdc->req_mempool);
        else
                kfree(req);
 }
+EXPORT_SYMBOL(ceph_osdc_release_request);
 
-/*
- * build new request AND message, calculate layout, and adjust file
- * extent as needed.
- *
- * if the file was recently truncated, we include information about its
- * old and new size so that the object can be updated appropriately.  (we
- * avoid synchronously deleting truncated objects because it's slow.)
- *
- * if @do_sync, include a 'startsync' command so that the osd will flush
- * data quickly.
- */
-struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
-                                              struct ceph_file_layout *layout,
-                                              struct ceph_vino vino,
-                                              u64 off, u64 *plen,
-                                              int opcode, int flags,
+static int get_num_ops(struct ceph_osd_req_op *ops, int *needs_trail)
+{
+       int i = 0;
+
+       if (needs_trail)
+               *needs_trail = 0;
+       while (ops[i].op) {
+               if (needs_trail && op_needs_trail(ops[i].op))
+                       *needs_trail = 1;
+               i++;
+       }
+
+       return i;
+}
+
+struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
+                                              int flags,
                                               struct ceph_snap_context *snapc,
-                                              int do_sync,
-                                              u32 truncate_seq,
-                                              u64 truncate_size,
-                                              struct timespec *mtime,
-                                              bool use_mempool, int num_reply)
+                                              struct ceph_osd_req_op *ops,
+                                              bool use_mempool,
+                                              gfp_t gfp_flags,
+                                              struct page **pages,
+                                              struct bio *bio)
 {
        struct ceph_osd_request *req;
        struct ceph_msg *msg;
-       struct ceph_osd_request_head *head;
-       struct ceph_osd_op *op;
-       void *p;
-       int num_op = 1 + do_sync;
-       size_t msg_size = sizeof(*head) + num_op*sizeof(*op);
-       int i;
+       int needs_trail;
+       int num_op = get_num_ops(ops, &needs_trail);
+       size_t msg_size = sizeof(struct ceph_osd_request_head);
+
+       msg_size += num_op*sizeof(struct ceph_osd_op);
 
        if (use_mempool) {
-               req = mempool_alloc(osdc->req_mempool, GFP_NOFS);
+               req = mempool_alloc(osdc->req_mempool, gfp_flags);
                memset(req, 0, sizeof(*req));
        } else {
-               req = kzalloc(sizeof(*req), GFP_NOFS);
+               req = kzalloc(sizeof(*req), gfp_flags);
        }
        if (req == NULL)
                return NULL;
 
        req->r_osdc = osdc;
        req->r_mempool = use_mempool;
+
        kref_init(&req->r_kref);
        init_completion(&req->r_completion);
        init_completion(&req->r_safe_completion);
@@ -164,13 +217,22 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
                msg = ceph_msgpool_get(&osdc->msgpool_op_reply, 0);
        else
                msg = ceph_msg_new(CEPH_MSG_OSD_OPREPLY,
-                                  OSD_OPREPLY_FRONT_LEN, GFP_NOFS);
+                                  OSD_OPREPLY_FRONT_LEN, gfp_flags);
        if (!msg) {
                ceph_osdc_put_request(req);
                return NULL;
        }
        req->r_reply = msg;
 
+       /* allocate space for the trailing data */
+       if (needs_trail) {
+               req->r_trail = kmalloc(sizeof(struct ceph_pagelist), gfp_flags);
+               if (!req->r_trail) {
+                       ceph_osdc_put_request(req);
+                       return NULL;
+               }
+               ceph_pagelist_init(req->r_trail);
+       }
        /* create request message; allow space for oid */
        msg_size += 40;
        if (snapc)
@@ -178,18 +240,115 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
        if (use_mempool)
                msg = ceph_msgpool_get(&osdc->msgpool_op, 0);
        else
-               msg = ceph_msg_new(CEPH_MSG_OSD_OP, msg_size, GFP_NOFS);
+               msg = ceph_msg_new(CEPH_MSG_OSD_OP, msg_size, gfp_flags);
        if (!msg) {
                ceph_osdc_put_request(req);
                return NULL;
        }
+
        msg->hdr.type = cpu_to_le16(CEPH_MSG_OSD_OP);
        memset(msg->front.iov_base, 0, msg->front.iov_len);
+
+       req->r_request = msg;
+       req->r_pages = pages;
+#ifdef CONFIG_BLOCK
+       if (bio) {
+               req->r_bio = bio;
+               bio_get(req->r_bio);
+       }
+#endif
+
+       return req;
+}
+EXPORT_SYMBOL(ceph_osdc_alloc_request);
+
+static void osd_req_encode_op(struct ceph_osd_request *req,
+                             struct ceph_osd_op *dst,
+                             struct ceph_osd_req_op *src)
+{
+       dst->op = cpu_to_le16(src->op);
+
+       switch (dst->op) {
+       case CEPH_OSD_OP_READ:
+       case CEPH_OSD_OP_WRITE:
+               dst->extent.offset =
+                       cpu_to_le64(src->extent.offset);
+               dst->extent.length =
+                       cpu_to_le64(src->extent.length);
+               dst->extent.truncate_size =
+                       cpu_to_le64(src->extent.truncate_size);
+               dst->extent.truncate_seq =
+                       cpu_to_le32(src->extent.truncate_seq);
+               break;
+
+       case CEPH_OSD_OP_GETXATTR:
+       case CEPH_OSD_OP_SETXATTR:
+       case CEPH_OSD_OP_CMPXATTR:
+               BUG_ON(!req->r_trail);
+
+               dst->xattr.name_len = cpu_to_le32(src->xattr.name_len);
+               dst->xattr.value_len = cpu_to_le32(src->xattr.value_len);
+               dst->xattr.cmp_op = src->xattr.cmp_op;
+               dst->xattr.cmp_mode = src->xattr.cmp_mode;
+               ceph_pagelist_append(req->r_trail, src->xattr.name,
+                                    src->xattr.name_len);
+               ceph_pagelist_append(req->r_trail, src->xattr.val,
+                                    src->xattr.value_len);
+               break;
+       case CEPH_OSD_OP_CALL:
+               BUG_ON(!req->r_trail);
+
+               dst->cls.class_len = src->cls.class_len;
+               dst->cls.method_len = src->cls.method_len;
+               dst->cls.indata_len = cpu_to_le32(src->cls.indata_len);
+
+               ceph_pagelist_append(req->r_trail, src->cls.class_name,
+                                    src->cls.class_len);
+               ceph_pagelist_append(req->r_trail, src->cls.method_name,
+                                    src->cls.method_len);
+               ceph_pagelist_append(req->r_trail, src->cls.indata,
+                                    src->cls.indata_len);
+               break;
+       case CEPH_OSD_OP_ROLLBACK:
+               dst->snap.snapid = cpu_to_le64(src->snap.snapid);
+               break;
+       case CEPH_OSD_OP_STARTSYNC:
+               break;
+       default:
+               pr_err("unrecognized osd opcode %d\n", dst->op);
+               WARN_ON(1);
+               break;
+       }
+       dst->payload_len = cpu_to_le32(src->payload_len);
+}
+
+/*
+ * build new request AND message
+ *
+ */
+void ceph_osdc_build_request(struct ceph_osd_request *req,
+                            u64 off, u64 *plen,
+                            struct ceph_osd_req_op *src_ops,
+                            struct ceph_snap_context *snapc,
+                            struct timespec *mtime,
+                            const char *oid,
+                            int oid_len)
+{
+       struct ceph_msg *msg = req->r_request;
+       struct ceph_osd_request_head *head;
+       struct ceph_osd_req_op *src_op;
+       struct ceph_osd_op *op;
+       void *p;
+       int num_op = get_num_ops(src_ops, NULL);
+       size_t msg_size = sizeof(*head) + num_op*sizeof(*op);
+       int flags = req->r_flags;
+       u64 data_len = 0;
+       int i;
+
        head = msg->front.iov_base;
        op = (void *)(head + 1);
        p = (void *)(op + num_op);
 
-       req->r_request = msg;
        req->r_snapc = ceph_get_snap_context(snapc);
 
        head->client_inc = cpu_to_le32(1); /* always, for now. */
@@ -197,29 +356,23 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
        if (flags & CEPH_OSD_FLAG_WRITE)
                ceph_encode_timespec(&head->mtime, mtime);
        head->num_ops = cpu_to_le16(num_op);
-       op->op = cpu_to_le16(opcode);
 
-       /* calculate max write size */
-       calc_layout(osdc, vino, layout, off, plen, req);
-       req->r_file_layout = *layout;  /* keep a copy */
-
-       if (flags & CEPH_OSD_FLAG_WRITE) {
-               req->r_request->hdr.data_off = cpu_to_le16(off);
-               req->r_request->hdr.data_len = cpu_to_le32(*plen);
-               op->payload_len = cpu_to_le32(*plen);
-       }
-       op->extent.truncate_size = cpu_to_le64(truncate_size);
-       op->extent.truncate_seq = cpu_to_le32(truncate_seq);
 
        /* fill in oid */
-       head->object_len = cpu_to_le32(req->r_oid_len);
-       memcpy(p, req->r_oid, req->r_oid_len);
-       p += req->r_oid_len;
-
-       if (do_sync) {
+       head->object_len = cpu_to_le32(oid_len);
+       memcpy(p, oid, oid_len);
+       p += oid_len;
+
+       src_op = src_ops;
+       while (src_op->op) {
+               osd_req_encode_op(req, op, src_op);
+               src_op++;
                op++;
-               op->op = cpu_to_le16(CEPH_OSD_OP_STARTSYNC);
        }
+
+       if (req->r_trail)
+               data_len += req->r_trail->length;
+
        if (snapc) {
                head->snap_seq = cpu_to_le64(snapc->seq);
                head->num_snaps = cpu_to_le32(snapc->num_snaps);
@@ -229,12 +382,79 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
                }
        }
 
+       if (flags & CEPH_OSD_FLAG_WRITE) {
+               req->r_request->hdr.data_off = cpu_to_le16(off);
+               req->r_request->hdr.data_len = cpu_to_le32(*plen + data_len);
+       } else if (data_len) {
+               req->r_request->hdr.data_off = 0;
+               req->r_request->hdr.data_len = cpu_to_le32(data_len);
+       }
+
        BUG_ON(p > msg->front.iov_base + msg->front.iov_len);
        msg_size = p - msg->front.iov_base;
        msg->front.iov_len = msg_size;
        msg->hdr.front_len = cpu_to_le32(msg_size);
+       return;
+}
+EXPORT_SYMBOL(ceph_osdc_build_request);
+
+/*
+ * build new request AND message, calculate layout, and adjust file
+ * extent as needed.
+ *
+ * if the file was recently truncated, we include information about its
+ * old and new size so that the object can be updated appropriately.  (we
+ * avoid synchronously deleting truncated objects because it's slow.)
+ *
+ * if @do_sync, include a 'startsync' command so that the osd will flush
+ * data quickly.
+ */
+struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
+                                              struct ceph_file_layout *layout,
+                                              struct ceph_vino vino,
+                                              u64 off, u64 *plen,
+                                              int opcode, int flags,
+                                              struct ceph_snap_context *snapc,
+                                              int do_sync,
+                                              u32 truncate_seq,
+                                              u64 truncate_size,
+                                              struct timespec *mtime,
+                                              bool use_mempool, int num_reply)
+{
+       struct ceph_osd_req_op ops[3];
+       struct ceph_osd_request *req;
+
+       ops[0].op = opcode;
+       ops[0].extent.truncate_seq = truncate_seq;
+       ops[0].extent.truncate_size = truncate_size;
+       ops[0].payload_len = 0;
+
+       if (do_sync) {
+               ops[1].op = CEPH_OSD_OP_STARTSYNC;
+               ops[1].payload_len = 0;
+               ops[2].op = 0;
+       } else
+               ops[1].op = 0;
+
+       req = ceph_osdc_alloc_request(osdc, flags,
+                                        snapc, ops,
+                                        use_mempool,
+                                        GFP_NOFS, NULL, NULL);
+       if (IS_ERR(req))
+               return req;
+
+       /* calculate max write size */
+       calc_layout(osdc, vino, layout, off, plen, req, ops);
+       req->r_file_layout = *layout;  /* keep a copy */
+
+       ceph_osdc_build_request(req, off, plen, ops,
+                               snapc,
+                               mtime,
+                               req->r_oid, req->r_oid_len);
+
        return req;
 }
+EXPORT_SYMBOL(ceph_osdc_new_request);
 
 /*
  * We keep osd requests in an rbtree, sorted by ->r_tid.
@@ -389,7 +609,7 @@ static void __move_osd_to_lru(struct ceph_osd_client *osdc,
        dout("__move_osd_to_lru %p\n", osd);
        BUG_ON(!list_empty(&osd->o_osd_lru));
        list_add_tail(&osd->o_osd_lru, &osdc->osd_lru);
-       osd->lru_ttl = jiffies + osdc->client->mount_args->osd_idle_ttl * HZ;
+       osd->lru_ttl = jiffies + osdc->client->options->osd_idle_ttl * HZ;
 }
 
 static void __remove_osd_from_lru(struct ceph_osd *osd)
@@ -483,7 +703,7 @@ static struct ceph_osd *__lookup_osd(struct ceph_osd_client *osdc, int o)
 static void __schedule_osd_timeout(struct ceph_osd_client *osdc)
 {
        schedule_delayed_work(&osdc->timeout_work,
-                       osdc->client->mount_args->osd_keepalive_timeout * HZ);
+                       osdc->client->options->osd_keepalive_timeout * HZ);
 }
 
 static void __cancel_osd_timeout(struct ceph_osd_client *osdc)
@@ -684,9 +904,9 @@ static void handle_timeout(struct work_struct *work)
                container_of(work, struct ceph_osd_client, timeout_work.work);
        struct ceph_osd_request *req, *last_req = NULL;
        struct ceph_osd *osd;
-       unsigned long timeout = osdc->client->mount_args->osd_timeout * HZ;
+       unsigned long timeout = osdc->client->options->osd_timeout * HZ;
        unsigned long keepalive =
-               osdc->client->mount_args->osd_keepalive_timeout * HZ;
+               osdc->client->options->osd_keepalive_timeout * HZ;
        unsigned long last_stamp = 0;
        struct rb_node *p;
        struct list_head slow_osds;
@@ -773,7 +993,7 @@ static void handle_osds_timeout(struct work_struct *work)
                container_of(work, struct ceph_osd_client,
                             osds_timeout_work.work);
        unsigned long delay =
-               osdc->client->mount_args->osd_idle_ttl * HZ >> 2;
+               osdc->client->options->osd_idle_ttl * HZ >> 2;
 
        dout("osds timeout\n");
        down_read(&osdc->map_sem);
@@ -1104,6 +1324,10 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
 
        req->r_request->pages = req->r_pages;
        req->r_request->nr_pages = req->r_num_pages;
+#ifdef CONFIG_BLOCK
+       req->r_request->bio = req->r_bio;
+#endif
+       req->r_request->trail = req->r_trail;
 
        register_request(osdc, req);
 
@@ -1131,6 +1355,7 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
        up_read(&osdc->map_sem);
        return rc;
 }
+EXPORT_SYMBOL(ceph_osdc_start_request);
 
 /*
  * wait for a request to complete
@@ -1153,6 +1378,7 @@ int ceph_osdc_wait_request(struct ceph_osd_client *osdc,
        dout("wait_request tid %llu result %d\n", req->r_tid, req->r_result);
        return req->r_result;
 }
+EXPORT_SYMBOL(ceph_osdc_wait_request);
 
 /*
  * sync - wait for all in-flight requests to flush.  avoid starvation.
@@ -1186,6 +1412,7 @@ void ceph_osdc_sync(struct ceph_osd_client *osdc)
        mutex_unlock(&osdc->request_mutex);
        dout("sync done (thru tid %llu)\n", last_tid);
 }
+EXPORT_SYMBOL(ceph_osdc_sync);
 
 /*
  * init, shutdown
@@ -1211,7 +1438,7 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
        INIT_DELAYED_WORK(&osdc->osds_timeout_work, handle_osds_timeout);
 
        schedule_delayed_work(&osdc->osds_timeout_work,
-          round_jiffies_relative(osdc->client->mount_args->osd_idle_ttl * HZ));
+          round_jiffies_relative(osdc->client->options->osd_idle_ttl * HZ));
 
        err = -ENOMEM;
        osdc->req_mempool = mempool_create_kmalloc_pool(10,
@@ -1237,6 +1464,7 @@ out_mempool:
 out:
        return err;
 }
+EXPORT_SYMBOL(ceph_osdc_init);
 
 void ceph_osdc_stop(struct ceph_osd_client *osdc)
 {
@@ -1251,6 +1479,7 @@ void ceph_osdc_stop(struct ceph_osd_client *osdc)
        ceph_msgpool_destroy(&osdc->msgpool_op);
        ceph_msgpool_destroy(&osdc->msgpool_op_reply);
 }
+EXPORT_SYMBOL(ceph_osdc_stop);
 
 /*
  * Read some contiguous pages.  If we cross a stripe boundary, shorten
@@ -1288,6 +1517,7 @@ int ceph_osdc_readpages(struct ceph_osd_client *osdc,
        dout("readpages result %d\n", rc);
        return rc;
 }
+EXPORT_SYMBOL(ceph_osdc_readpages);
 
 /*
  * do a synchronous write on N pages
@@ -1330,6 +1560,7 @@ int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino,
        dout("writepages result %d\n", rc);
        return rc;
 }
+EXPORT_SYMBOL(ceph_osdc_writepages);
 
 /*
  * handle incoming message
@@ -1420,6 +1651,9 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
                }
                m->pages = req->r_pages;
                m->nr_pages = req->r_num_pages;
+#ifdef CONFIG_BLOCK
+               m->bio = req->r_bio;
+#endif
        }
        *skip = 0;
        req->r_con_filling_msg = ceph_con_get(con);
similarity index 97%
rename from fs/ceph/osdmap.c
rename to net/ceph/osdmap.c
index e31f118f1392988351257d2385863c37228bc7df..d73f3f6efa36ff6cf9efc33cada1853afa8073e7 100644 (file)
@@ -1,14 +1,15 @@
 
-#include "ceph_debug.h"
+#include <linux/ceph/ceph_debug.h>
 
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <asm/div64.h>
 
-#include "super.h"
-#include "osdmap.h"
-#include "crush/hash.h"
-#include "crush/mapper.h"
-#include "decode.h"
+#include <linux/ceph/libceph.h>
+#include <linux/ceph/osdmap.h>
+#include <linux/ceph/decode.h>
+#include <linux/crush/hash.h>
+#include <linux/crush/mapper.h>
 
 char *ceph_osdmap_state_str(char *str, int len, int state)
 {
@@ -417,6 +418,20 @@ static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, int id)
        return NULL;
 }
 
+int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name)
+{
+       struct rb_node *rbp;
+
+       for (rbp = rb_first(&map->pg_pools); rbp; rbp = rb_next(rbp)) {
+               struct ceph_pg_pool_info *pi =
+                       rb_entry(rbp, struct ceph_pg_pool_info, node);
+               if (pi->name && strcmp(pi->name, name) == 0)
+                       return pi->id;
+       }
+       return -ENOENT;
+}
+EXPORT_SYMBOL(ceph_pg_poolid_by_name);
+
 static void __remove_pg_pool(struct rb_root *root, struct ceph_pg_pool_info *pi)
 {
        rb_erase(&pi->node, root);
@@ -966,6 +981,7 @@ void ceph_calc_file_object_mapping(struct ceph_file_layout *layout,
 
        dout(" obj extent %llu~%llu\n", *oxoff, *oxlen);
 }
+EXPORT_SYMBOL(ceph_calc_file_object_mapping);
 
 /*
  * calculate an object layout (i.e. pgid) from an oid,
@@ -1011,6 +1027,7 @@ int ceph_calc_object_layout(struct ceph_object_layout *ol,
        ol->ol_stripe_unit = fl->fl_object_stripe_unit;
        return 0;
 }
+EXPORT_SYMBOL(ceph_calc_object_layout);
 
 /*
  * Calculate raw osd vector for the given pgid.  Return pointer to osd
@@ -1108,3 +1125,4 @@ int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid)
                        return osds[i];
        return -1;
 }
+EXPORT_SYMBOL(ceph_calc_pg_primary);
diff --git a/net/ceph/pagelist.c b/net/ceph/pagelist.c
new file mode 100644 (file)
index 0000000..13cb409
--- /dev/null
@@ -0,0 +1,154 @@
+
+#include <linux/module.h>
+#include <linux/gfp.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/ceph/pagelist.h>
+
+static void ceph_pagelist_unmap_tail(struct ceph_pagelist *pl)
+{
+       if (pl->mapped_tail) {
+               struct page *page = list_entry(pl->head.prev, struct page, lru);
+               kunmap(page);
+               pl->mapped_tail = NULL;
+       }
+}
+
+int ceph_pagelist_release(struct ceph_pagelist *pl)
+{
+       ceph_pagelist_unmap_tail(pl);
+       while (!list_empty(&pl->head)) {
+               struct page *page = list_first_entry(&pl->head, struct page,
+                                                    lru);
+               list_del(&page->lru);
+               __free_page(page);
+       }
+       ceph_pagelist_free_reserve(pl);
+       return 0;
+}
+EXPORT_SYMBOL(ceph_pagelist_release);
+
+static int ceph_pagelist_addpage(struct ceph_pagelist *pl)
+{
+       struct page *page;
+
+       if (!pl->num_pages_free) {
+               page = __page_cache_alloc(GFP_NOFS);
+       } else {
+               page = list_first_entry(&pl->free_list, struct page, lru);
+               list_del(&page->lru);
+               --pl->num_pages_free;
+       }
+       if (!page)
+               return -ENOMEM;
+       pl->room += PAGE_SIZE;
+       ceph_pagelist_unmap_tail(pl);
+       list_add_tail(&page->lru, &pl->head);
+       pl->mapped_tail = kmap(page);
+       return 0;
+}
+
+int ceph_pagelist_append(struct ceph_pagelist *pl, const void *buf, size_t len)
+{
+       while (pl->room < len) {
+               size_t bit = pl->room;
+               int ret;
+
+               memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK),
+                      buf, bit);
+               pl->length += bit;
+               pl->room -= bit;
+               buf += bit;
+               len -= bit;
+               ret = ceph_pagelist_addpage(pl);
+               if (ret)
+                       return ret;
+       }
+
+       memcpy(pl->mapped_tail + (pl->length & ~PAGE_CACHE_MASK), buf, len);
+       pl->length += len;
+       pl->room -= len;
+       return 0;
+}
+EXPORT_SYMBOL(ceph_pagelist_append);
+
+/**
+ * Allocate enough pages for a pagelist to append the given amount
+ * of data without without allocating.
+ * Returns: 0 on success, -ENOMEM on error.
+ */
+int ceph_pagelist_reserve(struct ceph_pagelist *pl, size_t space)
+{
+       if (space <= pl->room)
+               return 0;
+       space -= pl->room;
+       space = (space + PAGE_SIZE - 1) >> PAGE_SHIFT;   /* conv to num pages */
+
+       while (space > pl->num_pages_free) {
+               struct page *page = __page_cache_alloc(GFP_NOFS);
+               if (!page)
+                       return -ENOMEM;
+               list_add_tail(&page->lru, &pl->free_list);
+               ++pl->num_pages_free;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(ceph_pagelist_reserve);
+
+/**
+ * Free any pages that have been preallocated.
+ */
+int ceph_pagelist_free_reserve(struct ceph_pagelist *pl)
+{
+       while (!list_empty(&pl->free_list)) {
+               struct page *page = list_first_entry(&pl->free_list,
+                                                    struct page, lru);
+               list_del(&page->lru);
+               __free_page(page);
+               --pl->num_pages_free;
+       }
+       BUG_ON(pl->num_pages_free);
+       return 0;
+}
+EXPORT_SYMBOL(ceph_pagelist_free_reserve);
+
+/**
+ * Create a truncation point.
+ */
+void ceph_pagelist_set_cursor(struct ceph_pagelist *pl,
+                             struct ceph_pagelist_cursor *c)
+{
+       c->pl = pl;
+       c->page_lru = pl->head.prev;
+       c->room = pl->room;
+}
+EXPORT_SYMBOL(ceph_pagelist_set_cursor);
+
+/**
+ * Truncate a pagelist to the given point. Move extra pages to reserve.
+ * This won't sleep.
+ * Returns: 0 on success,
+ *          -EINVAL if the pagelist doesn't match the trunc point pagelist
+ */
+int ceph_pagelist_truncate(struct ceph_pagelist *pl,
+                          struct ceph_pagelist_cursor *c)
+{
+       struct page *page;
+
+       if (pl != c->pl)
+               return -EINVAL;
+       ceph_pagelist_unmap_tail(pl);
+       while (pl->head.prev != c->page_lru) {
+               page = list_entry(pl->head.prev, struct page, lru);
+               list_del(&page->lru);                /* remove from pagelist */
+               list_add_tail(&page->lru, &pl->free_list); /* add to reserve */
+               ++pl->num_pages_free;
+       }
+       pl->room = c->room;
+       if (!list_empty(&pl->head)) {
+               page = list_entry(pl->head.prev, struct page, lru);
+               pl->mapped_tail = kmap(page);
+       }
+       return 0;
+}
+EXPORT_SYMBOL(ceph_pagelist_truncate);
diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c
new file mode 100644 (file)
index 0000000..54caf06
--- /dev/null
@@ -0,0 +1,223 @@
+#include <linux/ceph/ceph_debug.h>
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <linux/writeback.h>
+
+#include <linux/ceph/libceph.h>
+
+/*
+ * build a vector of user pages
+ */
+struct page **ceph_get_direct_page_vector(const char __user *data,
+                                                int num_pages,
+                                                loff_t off, size_t len)
+{
+       struct page **pages;
+       int rc;
+
+       pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);
+       if (!pages)
+               return ERR_PTR(-ENOMEM);
+
+       down_read(&current->mm->mmap_sem);
+       rc = get_user_pages(current, current->mm, (unsigned long)data,
+                           num_pages, 0, 0, pages, NULL);
+       up_read(&current->mm->mmap_sem);
+       if (rc < 0)
+               goto fail;
+       return pages;
+
+fail:
+       kfree(pages);
+       return ERR_PTR(rc);
+}
+EXPORT_SYMBOL(ceph_get_direct_page_vector);
+
+void ceph_put_page_vector(struct page **pages, int num_pages)
+{
+       int i;
+
+       for (i = 0; i < num_pages; i++)
+               put_page(pages[i]);
+       kfree(pages);
+}
+EXPORT_SYMBOL(ceph_put_page_vector);
+
+void ceph_release_page_vector(struct page **pages, int num_pages)
+{
+       int i;
+
+       for (i = 0; i < num_pages; i++)
+               __free_pages(pages[i], 0);
+       kfree(pages);
+}
+EXPORT_SYMBOL(ceph_release_page_vector);
+
+/*
+ * allocate a vector new pages
+ */
+struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags)
+{
+       struct page **pages;
+       int i;
+
+       pages = kmalloc(sizeof(*pages) * num_pages, flags);
+       if (!pages)
+               return ERR_PTR(-ENOMEM);
+       for (i = 0; i < num_pages; i++) {
+               pages[i] = __page_cache_alloc(flags);
+               if (pages[i] == NULL) {
+                       ceph_release_page_vector(pages, i);
+                       return ERR_PTR(-ENOMEM);
+               }
+       }
+       return pages;
+}
+EXPORT_SYMBOL(ceph_alloc_page_vector);
+
+/*
+ * copy user data into a page vector
+ */
+int ceph_copy_user_to_page_vector(struct page **pages,
+                                        const char __user *data,
+                                        loff_t off, size_t len)
+{
+       int i = 0;
+       int po = off & ~PAGE_CACHE_MASK;
+       int left = len;
+       int l, bad;
+
+       while (left > 0) {
+               l = min_t(int, PAGE_CACHE_SIZE-po, left);
+               bad = copy_from_user(page_address(pages[i]) + po, data, l);
+               if (bad == l)
+                       return -EFAULT;
+               data += l - bad;
+               left -= l - bad;
+               po += l - bad;
+               if (po == PAGE_CACHE_SIZE) {
+                       po = 0;
+                       i++;
+               }
+       }
+       return len;
+}
+EXPORT_SYMBOL(ceph_copy_user_to_page_vector);
+
+int ceph_copy_to_page_vector(struct page **pages,
+                                   const char *data,
+                                   loff_t off, size_t len)
+{
+       int i = 0;
+       size_t po = off & ~PAGE_CACHE_MASK;
+       size_t left = len;
+       size_t l;
+
+       while (left > 0) {
+               l = min_t(size_t, PAGE_CACHE_SIZE-po, left);
+               memcpy(page_address(pages[i]) + po, data, l);
+               data += l;
+               left -= l;
+               po += l;
+               if (po == PAGE_CACHE_SIZE) {
+                       po = 0;
+                       i++;
+               }
+       }
+       return len;
+}
+EXPORT_SYMBOL(ceph_copy_to_page_vector);
+
+int ceph_copy_from_page_vector(struct page **pages,
+                                   char *data,
+                                   loff_t off, size_t len)
+{
+       int i = 0;
+       size_t po = off & ~PAGE_CACHE_MASK;
+       size_t left = len;
+       size_t l;
+
+       while (left > 0) {
+               l = min_t(size_t, PAGE_CACHE_SIZE-po, left);
+               memcpy(data, page_address(pages[i]) + po, l);
+               data += l;
+               left -= l;
+               po += l;
+               if (po == PAGE_CACHE_SIZE) {
+                       po = 0;
+                       i++;
+               }
+       }
+       return len;
+}
+EXPORT_SYMBOL(ceph_copy_from_page_vector);
+
+/*
+ * copy user data from a page vector into a user pointer
+ */
+int ceph_copy_page_vector_to_user(struct page **pages,
+                                        char __user *data,
+                                        loff_t off, size_t len)
+{
+       int i = 0;
+       int po = off & ~PAGE_CACHE_MASK;
+       int left = len;
+       int l, bad;
+
+       while (left > 0) {
+               l = min_t(int, left, PAGE_CACHE_SIZE-po);
+               bad = copy_to_user(data, page_address(pages[i]) + po, l);
+               if (bad == l)
+                       return -EFAULT;
+               data += l - bad;
+               left -= l - bad;
+               if (po) {
+                       po += l - bad;
+                       if (po == PAGE_CACHE_SIZE)
+                               po = 0;
+               }
+               i++;
+       }
+       return len;
+}
+EXPORT_SYMBOL(ceph_copy_page_vector_to_user);
+
+/*
+ * Zero an extent within a page vector.  Offset is relative to the
+ * start of the first page.
+ */
+void ceph_zero_page_vector_range(int off, int len, struct page **pages)
+{
+       int i = off >> PAGE_CACHE_SHIFT;
+
+       off &= ~PAGE_CACHE_MASK;
+
+       dout("zero_page_vector_page %u~%u\n", off, len);
+
+       /* leading partial page? */
+       if (off) {
+               int end = min((int)PAGE_CACHE_SIZE, off + len);
+               dout("zeroing %d %p head from %d\n", i, pages[i],
+                    (int)off);
+               zero_user_segment(pages[i], off, end);
+               len -= (end - off);
+               i++;
+       }
+       while (len >= PAGE_CACHE_SIZE) {
+               dout("zeroing %d %p len=%d\n", i, pages[i], len);
+               zero_user_segment(pages[i], 0, PAGE_CACHE_SIZE);
+               len -= PAGE_CACHE_SIZE;
+               i++;
+       }
+       /* trailing partial page? */
+       if (len) {
+               dout("zeroing %d %p tail to %d\n", i, pages[i], (int)len);
+               zero_user_segment(pages[i], 0, len);
+       }
+}
+EXPORT_SYMBOL(ceph_zero_page_vector_range);
+
index 251997a9548362c5ebc8a0a34842971a0198539a..282806ba7a57e60991f2f7806bc3015d9b8596a5 100644 (file)
@@ -243,6 +243,7 @@ void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb)
        unlock_sock_fast(sk, slow);
 
        /* skb is now orphaned, can be freed outside of locked section */
+       trace_kfree_skb(skb, skb_free_datagram_locked);
        __kfree_skb(skb);
 }
 EXPORT_SYMBOL(skb_free_datagram_locked);
index 660dd41aaaa6629c0d59547e04d23353ba935af8..7ec85e27beed840b8da5f9dae620bcd48453f3f7 100644 (file)
 #include <linux/jhash.h>
 #include <linux/random.h>
 #include <trace/events/napi.h>
+#include <trace/events/net.h>
+#include <trace/events/skb.h>
 #include <linux/pci.h>
 
 #include "net-sysfs.h"
@@ -1978,6 +1980,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                }
 
                rc = ops->ndo_start_xmit(skb, dev);
+               trace_net_dev_xmit(skb, rc);
                if (rc == NETDEV_TX_OK)
                        txq_trans_update(txq);
                return rc;
@@ -1998,6 +2001,7 @@ gso:
                        skb_dst_drop(nskb);
 
                rc = ops->ndo_start_xmit(nskb, dev);
+               trace_net_dev_xmit(nskb, rc);
                if (unlikely(rc != NETDEV_TX_OK)) {
                        if (rc & ~NETDEV_TX_MASK)
                                goto out_kfree_gso_skb;
@@ -2186,6 +2190,7 @@ int dev_queue_xmit(struct sk_buff *skb)
 #ifdef CONFIG_NET_CLS_ACT
        skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);
 #endif
+       trace_net_dev_queue(skb);
        if (q->enqueue) {
                rc = __dev_xmit_skb(skb, q, dev, txq);
                goto out;
@@ -2512,6 +2517,7 @@ int netif_rx(struct sk_buff *skb)
        if (netdev_tstamp_prequeue)
                net_timestamp_check(skb);
 
+       trace_netif_rx(skb);
 #ifdef CONFIG_RPS
        {
                struct rps_dev_flow voidflow, *rflow = &voidflow;
@@ -2571,6 +2577,7 @@ static void net_tx_action(struct softirq_action *h)
                        clist = clist->next;
 
                        WARN_ON(atomic_read(&skb->users));
+                       trace_kfree_skb(skb, net_tx_action);
                        __kfree_skb(skb);
                }
        }
@@ -2828,6 +2835,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
        if (!netdev_tstamp_prequeue)
                net_timestamp_check(skb);
 
+       trace_netif_receive_skb(skb);
        if (vlan_tx_tag_present(skb) && vlan_hwaccel_do_receive(skb))
                return NET_RX_SUCCESS;
 
index afa6380ed88ac2ee0b5cd8c8a731dcb9f3dcb809..7f1bb2aba03bf0e501ee1625ba6f07163b528ab9 100644 (file)
@@ -26,6 +26,7 @@
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/skb.h>
+#include <trace/events/net.h>
 #include <trace/events/napi.h>
 
 EXPORT_TRACEPOINT_SYMBOL_GPL(kfree_skb);
index c83b421341c01b4a1de702e42d3380fac2f0aa2b..56ba3c4e4761c6584375a8acf45022bc5c40d6e8 100644 (file)
@@ -466,6 +466,7 @@ void consume_skb(struct sk_buff *skb)
                smp_rmb();
        else if (likely(!atomic_dec_and_test(&skb->users)))
                return;
+       trace_consume_skb(skb);
        __kfree_skb(skb);
 }
 EXPORT_SYMBOL(consume_skb);
index ef30e9d286e703cccaffbd5ee10394cc167fe057..7d99e13148e6287f1cca0f5e3417ee5d535c366c 100644 (file)
@@ -1078,8 +1078,11 @@ static void sk_prot_free(struct proto *prot, struct sock *sk)
 #ifdef CONFIG_CGROUPS
 void sock_update_classid(struct sock *sk)
 {
-       u32 classid = task_cls_classid(current);
+       u32 classid;
 
+       rcu_read_lock();  /* doing current task, which cannot vanish. */
+       classid = task_cls_classid(current);
+       rcu_read_unlock();
        if (classid && classid != sk->sk_classid)
                sk->sk_classid = classid;
 }
index 244f7cb08d681d35f9a08744ca449ce90f5b8972..37f8adb68c79e8619d1a45a496ca6e1ef37c7c8a 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/percpu.h>
+#include <linux/security.h>
 #include <net/net_namespace.h>
 
 #include <linux/netfilter.h>
@@ -87,6 +88,29 @@ static void ct_seq_stop(struct seq_file *s, void *v)
        rcu_read_unlock();
 }
 
+#ifdef CONFIG_NF_CONNTRACK_SECMARK
+static int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
+{
+       int ret;
+       u32 len;
+       char *secctx;
+
+       ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
+       if (ret)
+               return ret;
+
+       ret = seq_printf(s, "secctx=%s ", secctx);
+
+       security_release_secctx(secctx, len);
+       return ret;
+}
+#else
+static inline int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
+{
+       return 0;
+}
+#endif
+
 static int ct_seq_show(struct seq_file *s, void *v)
 {
        struct nf_conntrack_tuple_hash *hash = v;
@@ -148,10 +172,8 @@ static int ct_seq_show(struct seq_file *s, void *v)
                goto release;
 #endif
 
-#ifdef CONFIG_NF_CONNTRACK_SECMARK
-       if (seq_printf(s, "secmark=%u ", ct->secmark))
+       if (ct_show_secctx(s, ct))
                goto release;
-#endif
 
        if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use)))
                goto release;
index 8c8632d9b93cead0cd115945a9566d1e57829667..957c9241fb0ce1d91cde6c1b098f81b52337690a 100644 (file)
@@ -38,7 +38,7 @@ static DEFINE_SPINLOCK(nf_nat_lock);
 static struct nf_conntrack_l3proto *l3proto __read_mostly;
 
 #define MAX_IP_NAT_PROTO 256
-static const struct nf_nat_protocol *nf_nat_protos[MAX_IP_NAT_PROTO]
+static const struct nf_nat_protocol __rcu *nf_nat_protos[MAX_IP_NAT_PROTO]
                                                __read_mostly;
 
 static inline const struct nf_nat_protocol *
index 78b505d33bfb42cdf1033be323c2fdb1a359a833..fdaec7daff1d539038ef6ee6c0d0acfeae6e7cf6 100644 (file)
@@ -27,7 +27,7 @@
 
 static DEFINE_MUTEX(afinfo_mutex);
 
-const struct nf_afinfo *nf_afinfo[NFPROTO_NUMPROTO] __read_mostly;
+const struct nf_afinfo __rcu *nf_afinfo[NFPROTO_NUMPROTO] __read_mostly;
 EXPORT_SYMBOL(nf_afinfo);
 
 int nf_register_afinfo(const struct nf_afinfo *afinfo)
index cdcc7649476b60e0e8584a7c2b2d31e7509a4bd4..5702de35e2bb327ea0e9bd346f57bf8ebf36c951 100644 (file)
 
 static DEFINE_MUTEX(nf_ct_ecache_mutex);
 
-struct nf_ct_event_notifier *nf_conntrack_event_cb __read_mostly;
+struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb __read_mostly;
 EXPORT_SYMBOL_GPL(nf_conntrack_event_cb);
 
-struct nf_exp_event_notifier *nf_expect_event_cb __read_mostly;
+struct nf_exp_event_notifier __rcu *nf_expect_event_cb __read_mostly;
 EXPORT_SYMBOL_GPL(nf_expect_event_cb);
 
 /* deliver cached events and clear cache entry - must be called with locally
index 8d9e4c949b9618eafc4a7b301d305a15cab805b6..bd82450c193f5dbb4895f4fc7565040686fa740d 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/skbuff.h>
 #include <net/netfilter/nf_conntrack_extend.h>
 
-static struct nf_ct_ext_type *nf_ct_ext_types[NF_CT_EXT_NUM];
+static struct nf_ct_ext_type __rcu *nf_ct_ext_types[NF_CT_EXT_NUM];
 static DEFINE_MUTEX(nf_ct_ext_type_mutex);
 
 void __nf_ct_ext_destroy(struct nf_conn *ct)
index 5bae1cd15eea93ee3f74cb51dab972c10c96d33c..146476c6441a9ea8894d78bc5a00c558c84a0874 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/rculist_nulls.h>
 #include <linux/types.h>
 #include <linux/timer.h>
+#include <linux/security.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
 #include <linux/netlink.h>
@@ -245,16 +246,31 @@ nla_put_failure:
 
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
 static inline int
-ctnetlink_dump_secmark(struct sk_buff *skb, const struct nf_conn *ct)
+ctnetlink_dump_secctx(struct sk_buff *skb, const struct nf_conn *ct)
 {
-       NLA_PUT_BE32(skb, CTA_SECMARK, htonl(ct->secmark));
-       return 0;
+       struct nlattr *nest_secctx;
+       int len, ret;
+       char *secctx;
+
+       ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
+       if (ret)
+               return ret;
+
+       ret = -1;
+       nest_secctx = nla_nest_start(skb, CTA_SECCTX | NLA_F_NESTED);
+       if (!nest_secctx)
+               goto nla_put_failure;
+
+       NLA_PUT_STRING(skb, CTA_SECCTX_NAME, secctx);
+       nla_nest_end(skb, nest_secctx);
 
+       ret = 0;
 nla_put_failure:
-       return -1;
+       security_release_secctx(secctx, len);
+       return ret;
 }
 #else
-#define ctnetlink_dump_secmark(a, b) (0)
+#define ctnetlink_dump_secctx(a, b) (0)
 #endif
 
 #define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple)
@@ -391,7 +407,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
            ctnetlink_dump_protoinfo(skb, ct) < 0 ||
            ctnetlink_dump_helpinfo(skb, ct) < 0 ||
            ctnetlink_dump_mark(skb, ct) < 0 ||
-           ctnetlink_dump_secmark(skb, ct) < 0 ||
+           ctnetlink_dump_secctx(skb, ct) < 0 ||
            ctnetlink_dump_id(skb, ct) < 0 ||
            ctnetlink_dump_use(skb, ct) < 0 ||
            ctnetlink_dump_master(skb, ct) < 0 ||
@@ -437,6 +453,17 @@ ctnetlink_counters_size(const struct nf_conn *ct)
               ;
 }
 
+#ifdef CONFIG_NF_CONNTRACK_SECMARK
+static int ctnetlink_nlmsg_secctx_size(const struct nf_conn *ct)
+{
+       int len;
+
+       security_secid_to_secctx(ct->secmark, NULL, &len);
+
+       return sizeof(char) * len;
+}
+#endif
+
 static inline size_t
 ctnetlink_nlmsg_size(const struct nf_conn *ct)
 {
@@ -453,7 +480,8 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct)
               + nla_total_size(0) /* CTA_HELP */
               + nla_total_size(NF_CT_HELPER_NAME_LEN) /* CTA_HELP_NAME */
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
-              + nla_total_size(sizeof(u_int32_t)) /* CTA_SECMARK */
+              + nla_total_size(0) /* CTA_SECCTX */
+              + nla_total_size(ctnetlink_nlmsg_secctx_size(ct)) /* CTA_SECCTX_NAME */
 #endif
 #ifdef CONFIG_NF_NAT_NEEDED
               + 2 * nla_total_size(0) /* CTA_NAT_SEQ_ADJ_ORIG|REPL */
@@ -556,7 +584,7 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
 
 #ifdef CONFIG_NF_CONNTRACK_SECMARK
                if ((events & (1 << IPCT_SECMARK) || ct->secmark)
-                   && ctnetlink_dump_secmark(skb, ct) < 0)
+                   && ctnetlink_dump_secctx(skb, ct) < 0)
                        goto nla_put_failure;
 #endif
 
index 5886ba1d52a0c353a2538313c717328cacfdcac3..ed6d929580236c1b4aa77a42db959c9e522f2fc5 100644 (file)
@@ -28,8 +28,8 @@
 #include <net/netfilter/nf_conntrack_l4proto.h>
 #include <net/netfilter/nf_conntrack_core.h>
 
-static struct nf_conntrack_l4proto **nf_ct_protos[PF_MAX] __read_mostly;
-struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX] __read_mostly;
+static struct nf_conntrack_l4proto __rcu **nf_ct_protos[PF_MAX] __read_mostly;
+struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX] __read_mostly;
 EXPORT_SYMBOL_GPL(nf_ct_l3protos);
 
 static DEFINE_MUTEX(nf_ct_proto_mutex);
index eb973fcd67ab4273a3cdee566a5f4a4fb44a24f2..0fb65705b44b522e3ba4de6c02d06f119f43f2d9 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/seq_file.h>
 #include <linux/percpu.h>
 #include <linux/netdevice.h>
+#include <linux/security.h>
 #include <net/net_namespace.h>
 #ifdef CONFIG_SYSCTL
 #include <linux/sysctl.h>
@@ -108,6 +109,29 @@ static void ct_seq_stop(struct seq_file *s, void *v)
        rcu_read_unlock();
 }
 
+#ifdef CONFIG_NF_CONNTRACK_SECMARK
+static int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
+{
+       int ret;
+       u32 len;
+       char *secctx;
+
+       ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
+       if (ret)
+               return ret;
+
+       ret = seq_printf(s, "secctx=%s ", secctx);
+
+       security_release_secctx(secctx, len);
+       return ret;
+}
+#else
+static inline int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
+{
+       return 0;
+}
+#endif
+
 /* return 0 on success, 1 in case of error */
 static int ct_seq_show(struct seq_file *s, void *v)
 {
@@ -168,10 +192,8 @@ static int ct_seq_show(struct seq_file *s, void *v)
                goto release;
 #endif
 
-#ifdef CONFIG_NF_CONNTRACK_SECMARK
-       if (seq_printf(s, "secmark=%u ", ct->secmark))
+       if (ct_show_secctx(s, ct))
                goto release;
-#endif
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
        if (seq_printf(s, "zone=%u ", nf_ct_zone(ct)))
index 7df37fd786bc19406a5ed8a8558df95cd26d93be..b07393eab88e2fb86a21d7556f7ce532c807a172 100644 (file)
@@ -16,7 +16,7 @@
 #define NF_LOG_PREFIXLEN               128
 #define NFLOGGER_NAME_LEN              64
 
-static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly;
+static const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO] __read_mostly;
 static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly;
 static DEFINE_MUTEX(nf_log_mutex);
 
index 78b3cf9c519ca86e66b0ba4ae88c6797a7518c3f..74aebed5bd28bb5c0c924cec7d908615b82ffdd6 100644 (file)
@@ -18,7 +18,7 @@
  * long term mutex.  The handler must provide an an outfn() to accept packets
  * for queueing and must reinject all packets it receives, no matter what.
  */
-static const struct nf_queue_handler *queue_handler[NFPROTO_NUMPROTO] __read_mostly;
+static const struct nf_queue_handler __rcu *queue_handler[NFPROTO_NUMPROTO] __read_mostly;
 
 static DEFINE_MUTEX(queue_handler_mutex);
 
index 0cb6053f02fdf04723254bfe90d8ca9bff29edfc..782e51986a6f670ce6c033c1a1d99e5a26d46885 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/skbuff.h>
-#include <linux/selinux.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
 #include <linux/netfilter_ipv6/ip6_tables.h>
 #include <linux/netfilter/x_tables.h>
index 23b2d6c486b573927dcefd00b575546b35376bfa..9faf5e050b796186b3204a02ece181726a26cb1a 100644 (file)
@@ -14,8 +14,8 @@
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include <linux/module.h>
+#include <linux/security.h>
 #include <linux/skbuff.h>
-#include <linux/selinux.h>
 #include <linux/netfilter/x_tables.h>
 #include <linux/netfilter/xt_SECMARK.h>
 
@@ -39,9 +39,8 @@ secmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
 
        switch (mode) {
        case SECMARK_MODE_SEL:
-               secmark = info->u.sel.selsid;
+               secmark = info->secid;
                break;
-
        default:
                BUG();
        }
@@ -50,33 +49,33 @@ secmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
        return XT_CONTINUE;
 }
 
-static int checkentry_selinux(struct xt_secmark_target_info *info)
+static int checkentry_lsm(struct xt_secmark_target_info *info)
 {
        int err;
-       struct xt_secmark_target_selinux_info *sel = &info->u.sel;
 
-       sel->selctx[SECMARK_SELCTX_MAX - 1] = '\0';
+       info->secctx[SECMARK_SECCTX_MAX - 1] = '\0';
+       info->secid = 0;
 
-       err = selinux_string_to_sid(sel->selctx, &sel->selsid);
+       err = security_secctx_to_secid(info->secctx, strlen(info->secctx),
+                                      &info->secid);
        if (err) {
                if (err == -EINVAL)
-                       pr_info("invalid SELinux context \'%s\'\n",
-                               sel->selctx);
+                       pr_info("invalid security context \'%s\'\n", info->secctx);
                return err;
        }
 
-       if (!sel->selsid) {
-               pr_info("unable to map SELinux context \'%s\'\n", sel->selctx);
+       if (!info->secid) {
+               pr_info("unable to map security context \'%s\'\n", info->secctx);
                return -ENOENT;
        }
 
-       err = selinux_secmark_relabel_packet_permission(sel->selsid);
+       err = security_secmark_relabel_packet(info->secid);
        if (err) {
                pr_info("unable to obtain relabeling permission\n");
                return err;
        }
 
-       selinux_secmark_refcount_inc();
+       security_secmark_refcount_inc();
        return 0;
 }
 
@@ -100,16 +99,16 @@ static int secmark_tg_check(const struct xt_tgchk_param *par)
 
        switch (info->mode) {
        case SECMARK_MODE_SEL:
-               err = checkentry_selinux(info);
-               if (err <= 0)
-                       return err;
                break;
-
        default:
                pr_info("invalid mode: %hu\n", info->mode);
                return -EINVAL;
        }
 
+       err = checkentry_lsm(info);
+       if (err)
+               return err;
+
        if (!mode)
                mode = info->mode;
        return 0;
@@ -119,7 +118,7 @@ static void secmark_tg_destroy(const struct xt_tgdtor_param *par)
 {
        switch (mode) {
        case SECMARK_MODE_SEL:
-               selinux_secmark_refcount_dec();
+               security_secmark_refcount_dec();
        }
 }
 
index 78ef2c5e130ba9224512dd3872d86226b36306f3..37dff78e9cb17c6fcf35e5302d57b84dd5e9f5f9 100644 (file)
@@ -123,7 +123,7 @@ static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp,
         * calls by looking at the number of nested bh disable calls because
         * softirqs always disables bh.
         */
-       if (softirq_count() != SOFTIRQ_OFFSET) {
+       if (in_serving_softirq()) {
                /* If there is an sk_classid we'll use that. */
                if (!skb->sk)
                        return -1;
index 842dbc2d5aeda0af27ce18af9914deea370dc329..2e088109fbd5238f3e4f6d293848606d0ac95a58 100644 (file)
@@ -11,6 +11,7 @@ hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
 hostprogs-$(CONFIG_LOGO)         += pnmtologo
 hostprogs-$(CONFIG_VT)           += conmakehash
 hostprogs-$(CONFIG_IKCONFIG)     += bin2c
+hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
 
 always         := $(hostprogs-y) $(hostprogs-m)
 
index a1a5cf95a68d73bd5179474e07b274f77eb5efaf..5ad25e17b6cb2782a2101b59ad7cfd442a8af2ea 100644 (file)
@@ -209,12 +209,23 @@ cmd_modversions =                                                         \
 endif
 
 ifdef CONFIG_FTRACE_MCOUNT_RECORD
+ifdef BUILD_C_RECORDMCOUNT
+# Due to recursion, we must skip empty.o.
+# The empty.o file is created in the make process in order to determine
+#  the target endianness and word size. It is made before all other C
+#  files, including recordmcount.
+cmd_record_mcount = if [ $(@) != "scripts/mod/empty.o" ]; then                 \
+                       $(objtree)/scripts/recordmcount "$(@)";                 \
+                   fi;
+else
 cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \
        "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \
        "$(if $(CONFIG_64BIT),64,32)" \
-       "$(OBJDUMP)" "$(OBJCOPY)" "$(CC)" "$(LD)" "$(NM)" "$(RM)" "$(MV)" \
+       "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \
+       "$(LD)" "$(NM)" "$(RM)" "$(MV)" \
        "$(if $(part-of-module),1,0)" "$(@)";
 endif
+endif
 
 define rule_cc_o_c
        $(call echo-cmd,checksrc) $(cmd_checksrc)                         \
index 54fd1b700131e1e1fcb0ddd13d89ee3a06983ecb..7bfcf1a09ac599be43a125ddb5cabf17d3a37e65 100644 (file)
@@ -101,14 +101,6 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))"
 modname_flags  = $(if $(filter 1,$(words $(modname))),\
                  -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))")
 
-#hash values
-ifdef CONFIG_DYNAMIC_DEBUG
-debug_flags = -D"DEBUG_HASH=$(shell ./scripts/basic/hash djb2 $(@D)$(modname))"\
-              -D"DEBUG_HASH2=$(shell ./scripts/basic/hash r5 $(@D)$(modname))"
-else
-debug_flags =
-endif
-
 orig_c_flags   = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
                  $(ccflags-y) $(CFLAGS_$(basetarget).o)
 _c_flags       = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
@@ -152,8 +144,7 @@ endif
 
 c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
                 $(__c_flags) $(modkern_cflags)                           \
-                -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) \
-                 $(debug_flags)
+                -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)
 
 a_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
                 $(__a_flags) $(modkern_aflags)
index 09559951df1208e00f5a51efa1208145a87efe14..4c324a1f1e0efb8668b4d64e05b56e8e0f64f25b 100644 (file)
@@ -9,7 +9,7 @@
 # fixdep:       Used to generate dependency information during build process
 # docproc:      Used in Documentation/DocBook
 
-hostprogs-y    := fixdep docproc hash
+hostprogs-y    := fixdep docproc
 always         := $(hostprogs-y)
 
 # fixdep is needed to compile other host programs
diff --git a/scripts/basic/hash.c b/scripts/basic/hash.c
deleted file mode 100644 (file)
index 2ef5d3f..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2008 Red Hat, Inc., Jason Baron <jbaron@redhat.com>
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define DYNAMIC_DEBUG_HASH_BITS 6
-
-static const char *program;
-
-static void usage(void)
-{
-       printf("Usage: %s <djb2|r5> <modname>\n", program);
-       exit(1);
-}
-
-/* djb2 hashing algorithm by Dan Bernstein. From:
- * http://www.cse.yorku.ca/~oz/hash.html
- */
-
-static unsigned int djb2_hash(char *str)
-{
-       unsigned long hash = 5381;
-       int c;
-
-       c = *str;
-       while (c) {
-               hash = ((hash << 5) + hash) + c;
-               c = *++str;
-       }
-       return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
-}
-
-static unsigned int r5_hash(char *str)
-{
-       unsigned long hash = 0;
-       int c;
-
-       c = *str;
-       while (c) {
-               hash = (hash + (c << 4) + (c >> 4)) * 11;
-               c = *++str;
-       }
-       return (unsigned int)(hash & ((1 << DYNAMIC_DEBUG_HASH_BITS) - 1));
-}
-
-int main(int argc, char *argv[])
-{
-       program = argv[0];
-
-       if (argc != 3)
-               usage();
-       if (!strcmp(argv[1], "djb2"))
-               printf("%d\n", djb2_hash(argv[2]));
-       else if (!strcmp(argv[1], "r5"))
-               printf("%d\n", r5_hash(argv[2]));
-       else
-               usage();
-       exit(0);
-}
-
diff --git a/scripts/gcc-goto.sh b/scripts/gcc-goto.sh
new file mode 100644 (file)
index 0000000..520d16b
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+# Test for gcc 'asm goto' suport
+# Copyright (C) 2010, Jason Baron <jbaron@redhat.com>
+
+echo "int main(void) { entry: asm goto (\"\"::::entry); return 0; }" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y"
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
new file mode 100644 (file)
index 0000000..26e1271
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * recordmcount.c: construct a table of the locations of calls to 'mcount'
+ * so that ftrace can find them quickly.
+ * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
+ * Licensed under the GNU General Public License, version 2 (GPLv2).
+ *
+ * Restructured to fit Linux format, as well as other updates:
+ *  Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+ */
+
+/*
+ * Strategy: alter the .o file in-place.
+ *
+ * Append a new STRTAB that has the new section names, followed by a new array
+ * ElfXX_Shdr[] that has the new section headers, followed by the section
+ * contents for __mcount_loc and its relocations.  The old shstrtab strings,
+ * and the old ElfXX_Shdr[] array, remain as "garbage" (commonly, a couple
+ * kilobytes.)  Subsequent processing by /bin/ld (or the kernel module loader)
+ * will ignore the garbage regions, because they are not designated by the
+ * new .e_shoff nor the new ElfXX_Shdr[].  [In order to remove the garbage,
+ * then use "ld -r" to create a new file that omits the garbage.]
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <elf.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int fd_map;     /* File descriptor for file being modified. */
+static int mmap_failed; /* Boolean flag. */
+static void *ehdr_curr; /* current ElfXX_Ehdr *  for resource cleanup */
+static char gpfx;      /* prefix for global symbol name (sometimes '_') */
+static struct stat sb; /* Remember .st_size, etc. */
+static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
+
+/* setjmp() return values */
+enum {
+       SJ_SETJMP = 0,  /* hardwired first return */
+       SJ_FAIL,
+       SJ_SUCCEED
+};
+
+/* Per-file resource cleanup when multiple files. */
+static void
+cleanup(void)
+{
+       if (!mmap_failed)
+               munmap(ehdr_curr, sb.st_size);
+       else
+               free(ehdr_curr);
+       close(fd_map);
+}
+
+static void __attribute__((noreturn))
+fail_file(void)
+{
+       cleanup();
+       longjmp(jmpenv, SJ_FAIL);
+}
+
+static void __attribute__((noreturn))
+succeed_file(void)
+{
+       cleanup();
+       longjmp(jmpenv, SJ_SUCCEED);
+}
+
+/* ulseek, uread, ...:  Check return value for errors. */
+
+static off_t
+ulseek(int const fd, off_t const offset, int const whence)
+{
+       off_t const w = lseek(fd, offset, whence);
+       if ((off_t)-1 == w) {
+               perror("lseek");
+               fail_file();
+       }
+       return w;
+}
+
+static size_t
+uread(int const fd, void *const buf, size_t const count)
+{
+       size_t const n = read(fd, buf, count);
+       if (n != count) {
+               perror("read");
+               fail_file();
+       }
+       return n;
+}
+
+static size_t
+uwrite(int const fd, void const *const buf, size_t const count)
+{
+       size_t const n = write(fd, buf, count);
+       if (n != count) {
+               perror("write");
+               fail_file();
+       }
+       return n;
+}
+
+static void *
+umalloc(size_t size)
+{
+       void *const addr = malloc(size);
+       if (0 == addr) {
+               fprintf(stderr, "malloc failed: %zu bytes\n", size);
+               fail_file();
+       }
+       return addr;
+}
+
+/*
+ * Get the whole file as a programming convenience in order to avoid
+ * malloc+lseek+read+free of many pieces.  If successful, then mmap
+ * avoids copying unused pieces; else just read the whole file.
+ * Open for both read and write; new info will be appended to the file.
+ * Use MAP_PRIVATE so that a few changes to the in-memory ElfXX_Ehdr
+ * do not propagate to the file until an explicit overwrite at the last.
+ * This preserves most aspects of consistency (all except .st_size)
+ * for simultaneous readers of the file while we are appending to it.
+ * However, multiple writers still are bad.  We choose not to use
+ * locking because it is expensive and the use case of kernel build
+ * makes multiple writers unlikely.
+ */
+static void *mmap_file(char const *fname)
+{
+       void *addr;
+
+       fd_map = open(fname, O_RDWR);
+       if (0 > fd_map || 0 > fstat(fd_map, &sb)) {
+               perror(fname);
+               fail_file();
+       }
+       if (!S_ISREG(sb.st_mode)) {
+               fprintf(stderr, "not a regular file: %s\n", fname);
+               fail_file();
+       }
+       addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
+                   fd_map, 0);
+       mmap_failed = 0;
+       if (MAP_FAILED == addr) {
+               mmap_failed = 1;
+               addr = umalloc(sb.st_size);
+               uread(fd_map, addr, sb.st_size);
+       }
+       return addr;
+}
+
+/* w8rev, w8nat, ...: Handle endianness. */
+
+static uint64_t w8rev(uint64_t const x)
+{
+       return   ((0xff & (x >> (0 * 8))) << (7 * 8))
+              | ((0xff & (x >> (1 * 8))) << (6 * 8))
+              | ((0xff & (x >> (2 * 8))) << (5 * 8))
+              | ((0xff & (x >> (3 * 8))) << (4 * 8))
+              | ((0xff & (x >> (4 * 8))) << (3 * 8))
+              | ((0xff & (x >> (5 * 8))) << (2 * 8))
+              | ((0xff & (x >> (6 * 8))) << (1 * 8))
+              | ((0xff & (x >> (7 * 8))) << (0 * 8));
+}
+
+static uint32_t w4rev(uint32_t const x)
+{
+       return   ((0xff & (x >> (0 * 8))) << (3 * 8))
+              | ((0xff & (x >> (1 * 8))) << (2 * 8))
+              | ((0xff & (x >> (2 * 8))) << (1 * 8))
+              | ((0xff & (x >> (3 * 8))) << (0 * 8));
+}
+
+static uint32_t w2rev(uint16_t const x)
+{
+       return   ((0xff & (x >> (0 * 8))) << (1 * 8))
+              | ((0xff & (x >> (1 * 8))) << (0 * 8));
+}
+
+static uint64_t w8nat(uint64_t const x)
+{
+       return x;
+}
+
+static uint32_t w4nat(uint32_t const x)
+{
+       return x;
+}
+
+static uint32_t w2nat(uint16_t const x)
+{
+       return x;
+}
+
+static uint64_t (*w8)(uint64_t);
+static uint32_t (*w)(uint32_t);
+static uint32_t (*w2)(uint16_t);
+
+/* Names of the sections that could contain calls to mcount. */
+static int
+is_mcounted_section_name(char const *const txtname)
+{
+       return 0 == strcmp(".text",          txtname) ||
+               0 == strcmp(".sched.text",    txtname) ||
+               0 == strcmp(".spinlock.text", txtname) ||
+               0 == strcmp(".irqentry.text", txtname) ||
+               0 == strcmp(".text.unlikely", txtname);
+}
+
+/* 32 bit and 64 bit are very similar */
+#include "recordmcount.h"
+#define RECORD_MCOUNT_64
+#include "recordmcount.h"
+
+static void
+do_file(char const *const fname)
+{
+       Elf32_Ehdr *const ehdr = mmap_file(fname);
+       unsigned int reltype = 0;
+
+       ehdr_curr = ehdr;
+       w = w4nat;
+       w2 = w2nat;
+       w8 = w8nat;
+       switch (ehdr->e_ident[EI_DATA]) {
+               static unsigned int const endian = 1;
+       default: {
+               fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
+                       ehdr->e_ident[EI_DATA], fname);
+               fail_file();
+       } break;
+       case ELFDATA2LSB: {
+               if (1 != *(unsigned char const *)&endian) {
+                       /* main() is big endian, file.o is little endian. */
+                       w = w4rev;
+                       w2 = w2rev;
+                       w8 = w8rev;
+               }
+       } break;
+       case ELFDATA2MSB: {
+               if (0 != *(unsigned char const *)&endian) {
+                       /* main() is little endian, file.o is big endian. */
+                       w = w4rev;
+                       w2 = w2rev;
+                       w8 = w8rev;
+               }
+       } break;
+       }  /* end switch */
+       if (0 != memcmp(ELFMAG, ehdr->e_ident, SELFMAG)
+       ||  ET_REL != w2(ehdr->e_type)
+       ||  EV_CURRENT != ehdr->e_ident[EI_VERSION]) {
+               fprintf(stderr, "unrecognized ET_REL file %s\n", fname);
+               fail_file();
+       }
+
+       gpfx = 0;
+       switch (w2(ehdr->e_machine)) {
+       default: {
+               fprintf(stderr, "unrecognized e_machine %d %s\n",
+                       w2(ehdr->e_machine), fname);
+               fail_file();
+       } break;
+       case EM_386:     reltype = R_386_32;                   break;
+       case EM_ARM:     reltype = R_ARM_ABS32;                break;
+       case EM_IA_64:   reltype = R_IA64_IMM64;   gpfx = '_'; break;
+       case EM_PPC:     reltype = R_PPC_ADDR32;   gpfx = '_'; break;
+       case EM_PPC64:   reltype = R_PPC64_ADDR64; gpfx = '_'; break;
+       case EM_S390:    /* reltype: e_class    */ gpfx = '_'; break;
+       case EM_SH:      reltype = R_SH_DIR32;                 break;
+       case EM_SPARCV9: reltype = R_SPARC_64;     gpfx = '_'; break;
+       case EM_X86_64:  reltype = R_X86_64_64;                break;
+       }  /* end switch */
+
+       switch (ehdr->e_ident[EI_CLASS]) {
+       default: {
+               fprintf(stderr, "unrecognized ELF class %d %s\n",
+                       ehdr->e_ident[EI_CLASS], fname);
+               fail_file();
+       } break;
+       case ELFCLASS32: {
+               if (sizeof(Elf32_Ehdr) != w2(ehdr->e_ehsize)
+               ||  sizeof(Elf32_Shdr) != w2(ehdr->e_shentsize)) {
+                       fprintf(stderr,
+                               "unrecognized ET_REL file: %s\n", fname);
+                       fail_file();
+               }
+               if (EM_S390 == w2(ehdr->e_machine))
+                       reltype = R_390_32;
+               do32(ehdr, fname, reltype);
+       } break;
+       case ELFCLASS64: {
+               Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
+               if (sizeof(Elf64_Ehdr) != w2(ghdr->e_ehsize)
+               ||  sizeof(Elf64_Shdr) != w2(ghdr->e_shentsize)) {
+                       fprintf(stderr,
+                               "unrecognized ET_REL file: %s\n", fname);
+                       fail_file();
+               }
+               if (EM_S390 == w2(ghdr->e_machine))
+                       reltype = R_390_64;
+               do64(ghdr, fname, reltype);
+       } break;
+       }  /* end switch */
+
+       cleanup();
+}
+
+int
+main(int argc, char const *argv[])
+{
+       const char ftrace[] = "kernel/trace/ftrace.o";
+       int ftrace_size = sizeof(ftrace) - 1;
+       int n_error = 0;  /* gcc-4.3.0 false positive complaint */
+
+       if (argc <= 1) {
+               fprintf(stderr, "usage: recordmcount file.o...\n");
+               return 0;
+       }
+
+       /* Process each file in turn, allowing deep failure. */
+       for (--argc, ++argv; 0 < argc; --argc, ++argv) {
+               int const sjval = setjmp(jmpenv);
+               int len;
+
+               /*
+                * The file kernel/trace/ftrace.o references the mcount
+                * function but does not call it. Since ftrace.o should
+                * not be traced anyway, we just skip it.
+                */
+               len = strlen(argv[0]);
+               if (len >= ftrace_size &&
+                   strcmp(argv[0] + (len - ftrace_size), ftrace) == 0)
+                       continue;
+
+               switch (sjval) {
+               default: {
+                       fprintf(stderr, "internal error: %s\n", argv[0]);
+                       exit(1);
+               } break;
+               case SJ_SETJMP: {  /* normal sequence */
+                       /* Avoid problems if early cleanup() */
+                       fd_map = -1;
+                       ehdr_curr = NULL;
+                       mmap_failed = 1;
+                       do_file(argv[0]);
+               } break;
+               case SJ_FAIL: {  /* error in do_file or below */
+                       ++n_error;
+               } break;
+               case SJ_SUCCEED: {  /* premature success */
+                       /* do nothing */
+               } break;
+               }  /* end switch */
+       }
+       return !!n_error;
+}
+
+
diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h
new file mode 100644 (file)
index 0000000..7f39d09
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * recordmcount.h
+ *
+ * This code was taken out of recordmcount.c written by
+ * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>.  All rights reserved.
+ *
+ * The original code had the same algorithms for both 32bit
+ * and 64bit ELF files, but the code was duplicated to support
+ * the difference in structures that were used. This
+ * file creates a macro of everything that is different between
+ * the 64 and 32 bit code, such that by including this header
+ * twice we can create both sets of functions by including this
+ * header once with RECORD_MCOUNT_64 undefined, and again with
+ * it defined.
+ *
+ * This conversion to macros was done by:
+ * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
+ *
+ * Licensed under the GNU General Public License, version 2 (GPLv2).
+ */
+#undef append_func
+#undef sift_rel_mcount
+#undef find_secsym_ndx
+#undef __has_rel_mcount
+#undef has_rel_mcount
+#undef tot_relsize
+#undef do_func
+#undef Elf_Ehdr
+#undef Elf_Shdr
+#undef Elf_Rel
+#undef Elf_Rela
+#undef Elf_Sym
+#undef ELF_R_SYM
+#undef ELF_R_INFO
+#undef ELF_ST_BIND
+#undef uint_t
+#undef _w
+#undef _align
+#undef _size
+
+#ifdef RECORD_MCOUNT_64
+# define append_func           append64
+# define sift_rel_mcount       sift64_rel_mcount
+# define find_secsym_ndx       find64_secsym_ndx
+# define __has_rel_mcount      __has64_rel_mcount
+# define has_rel_mcount                has64_rel_mcount
+# define tot_relsize           tot64_relsize
+# define do_func               do64
+# define Elf_Ehdr              Elf64_Ehdr
+# define Elf_Shdr              Elf64_Shdr
+# define Elf_Rel               Elf64_Rel
+# define Elf_Rela              Elf64_Rela
+# define Elf_Sym               Elf64_Sym
+# define ELF_R_SYM             ELF64_R_SYM
+# define ELF_R_INFO            ELF64_R_INFO
+# define ELF_ST_BIND           ELF64_ST_BIND
+# define uint_t                        uint64_t
+# define _w                    w8
+# define _align                        7u
+# define _size                 8
+#else
+# define append_func           append32
+# define sift_rel_mcount       sift32_rel_mcount
+# define find_secsym_ndx       find32_secsym_ndx
+# define __has_rel_mcount      __has32_rel_mcount
+# define has_rel_mcount                has32_rel_mcount
+# define tot_relsize           tot32_relsize
+# define do_func               do32
+# define Elf_Ehdr              Elf32_Ehdr
+# define Elf_Shdr              Elf32_Shdr
+# define Elf_Rel               Elf32_Rel
+# define Elf_Rela              Elf32_Rela
+# define Elf_Sym               Elf32_Sym
+# define ELF_R_SYM             ELF32_R_SYM
+# define ELF_R_INFO            ELF32_R_INFO
+# define ELF_ST_BIND           ELF32_ST_BIND
+# define uint_t                        uint32_t
+# define _w                    w
+# define _align                        3u
+# define _size                 4
+#endif
+
+/* Append the new shstrtab, Elf_Shdr[], __mcount_loc and its relocations. */
+static void append_func(Elf_Ehdr *const ehdr,
+                       Elf_Shdr *const shstr,
+                       uint_t const *const mloc0,
+                       uint_t const *const mlocp,
+                       Elf_Rel const *const mrel0,
+                       Elf_Rel const *const mrelp,
+                       unsigned int const rel_entsize,
+                       unsigned int const symsec_sh_link)
+{
+       /* Begin constructing output file */
+       Elf_Shdr mcsec;
+       char const *mc_name = (sizeof(Elf_Rela) == rel_entsize)
+               ? ".rela__mcount_loc"
+               :  ".rel__mcount_loc";
+       unsigned const old_shnum = w2(ehdr->e_shnum);
+       uint_t const old_shoff = _w(ehdr->e_shoff);
+       uint_t const old_shstr_sh_size   = _w(shstr->sh_size);
+       uint_t const old_shstr_sh_offset = _w(shstr->sh_offset);
+       uint_t t = 1 + strlen(mc_name) + _w(shstr->sh_size);
+       uint_t new_e_shoff;
+
+       shstr->sh_size = _w(t);
+       shstr->sh_offset = _w(sb.st_size);
+       t += sb.st_size;
+       t += (_align & -t);  /* word-byte align */
+       new_e_shoff = t;
+
+       /* body for new shstrtab */
+       ulseek(fd_map, sb.st_size, SEEK_SET);
+       uwrite(fd_map, old_shstr_sh_offset + (void *)ehdr, old_shstr_sh_size);
+       uwrite(fd_map, mc_name, 1 + strlen(mc_name));
+
+       /* old(modified) Elf_Shdr table, word-byte aligned */
+       ulseek(fd_map, t, SEEK_SET);
+       t += sizeof(Elf_Shdr) * old_shnum;
+       uwrite(fd_map, old_shoff + (void *)ehdr,
+              sizeof(Elf_Shdr) * old_shnum);
+
+       /* new sections __mcount_loc and .rel__mcount_loc */
+       t += 2*sizeof(mcsec);
+       mcsec.sh_name = w((sizeof(Elf_Rela) == rel_entsize) + strlen(".rel")
+               + old_shstr_sh_size);
+       mcsec.sh_type = w(SHT_PROGBITS);
+       mcsec.sh_flags = _w(SHF_ALLOC);
+       mcsec.sh_addr = 0;
+       mcsec.sh_offset = _w(t);
+       mcsec.sh_size = _w((void *)mlocp - (void *)mloc0);
+       mcsec.sh_link = 0;
+       mcsec.sh_info = 0;
+       mcsec.sh_addralign = _w(_size);
+       mcsec.sh_entsize = _w(_size);
+       uwrite(fd_map, &mcsec, sizeof(mcsec));
+
+       mcsec.sh_name = w(old_shstr_sh_size);
+       mcsec.sh_type = (sizeof(Elf_Rela) == rel_entsize)
+               ? w(SHT_RELA)
+               : w(SHT_REL);
+       mcsec.sh_flags = 0;
+       mcsec.sh_addr = 0;
+       mcsec.sh_offset = _w((void *)mlocp - (void *)mloc0 + t);
+       mcsec.sh_size   = _w((void *)mrelp - (void *)mrel0);
+       mcsec.sh_link = w(symsec_sh_link);
+       mcsec.sh_info = w(old_shnum);
+       mcsec.sh_addralign = _w(_size);
+       mcsec.sh_entsize = _w(rel_entsize);
+       uwrite(fd_map, &mcsec, sizeof(mcsec));
+
+       uwrite(fd_map, mloc0, (void *)mlocp - (void *)mloc0);
+       uwrite(fd_map, mrel0, (void *)mrelp - (void *)mrel0);
+
+       ehdr->e_shoff = _w(new_e_shoff);
+       ehdr->e_shnum = w2(2 + w2(ehdr->e_shnum));  /* {.rel,}__mcount_loc */
+       ulseek(fd_map, 0, SEEK_SET);
+       uwrite(fd_map, ehdr, sizeof(*ehdr));
+}
+
+
+/*
+ * Look at the relocations in order to find the calls to mcount.
+ * Accumulate the section offsets that are found, and their relocation info,
+ * onto the end of the existing arrays.
+ */
+static uint_t *sift_rel_mcount(uint_t *mlocp,
+                              unsigned const offbase,
+                              Elf_Rel **const mrelpp,
+                              Elf_Shdr const *const relhdr,
+                              Elf_Ehdr const *const ehdr,
+                              unsigned const recsym,
+                              uint_t const recval,
+                              unsigned const reltype)
+{
+       uint_t *const mloc0 = mlocp;
+       Elf_Rel *mrelp = *mrelpp;
+       Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
+               + (void *)ehdr);
+       unsigned const symsec_sh_link = w(relhdr->sh_link);
+       Elf_Shdr const *const symsec = &shdr0[symsec_sh_link];
+       Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symsec->sh_offset)
+               + (void *)ehdr);
+
+       Elf_Shdr const *const strsec = &shdr0[w(symsec->sh_link)];
+       char const *const str0 = (char const *)(_w(strsec->sh_offset)
+               + (void *)ehdr);
+
+       Elf_Rel const *const rel0 = (Elf_Rel const *)(_w(relhdr->sh_offset)
+               + (void *)ehdr);
+       unsigned rel_entsize = _w(relhdr->sh_entsize);
+       unsigned const nrel = _w(relhdr->sh_size) / rel_entsize;
+       Elf_Rel const *relp = rel0;
+
+       unsigned mcountsym = 0;
+       unsigned t;
+
+       for (t = nrel; t; --t) {
+               if (!mcountsym) {
+                       Elf_Sym const *const symp =
+                               &sym0[ELF_R_SYM(_w(relp->r_info))];
+                       char const *symname = &str0[w(symp->st_name)];
+
+                       if ('.' == symname[0])
+                               ++symname;  /* ppc64 hack */
+                       if (0 == strcmp((('_' == gpfx) ? "_mcount" : "mcount"),
+                                       symname))
+                               mcountsym = ELF_R_SYM(_w(relp->r_info));
+               }
+
+               if (mcountsym == ELF_R_SYM(_w(relp->r_info))) {
+                       uint_t const addend = _w(_w(relp->r_offset) - recval);
+
+                       mrelp->r_offset = _w(offbase
+                               + ((void *)mlocp - (void *)mloc0));
+                       mrelp->r_info = _w(ELF_R_INFO(recsym, reltype));
+                       if (sizeof(Elf_Rela) == rel_entsize) {
+                               ((Elf_Rela *)mrelp)->r_addend = addend;
+                               *mlocp++ = 0;
+                       } else
+                               *mlocp++ = addend;
+
+                       mrelp = (Elf_Rel *)(rel_entsize + (void *)mrelp);
+               }
+               relp = (Elf_Rel const *)(rel_entsize + (void *)relp);
+       }
+       *mrelpp = mrelp;
+       return mlocp;
+}
+
+
+/*
+ * Find a symbol in the given section, to be used as the base for relocating
+ * the table of offsets of calls to mcount.  A local or global symbol suffices,
+ * but avoid a Weak symbol because it may be overridden; the change in value
+ * would invalidate the relocations of the offsets of the calls to mcount.
+ * Often the found symbol will be the unnamed local symbol generated by
+ * GNU 'as' for the start of each section.  For example:
+ *    Num:    Value  Size Type    Bind   Vis      Ndx Name
+ *      2: 00000000     0 SECTION LOCAL  DEFAULT    1
+ */
+static unsigned find_secsym_ndx(unsigned const txtndx,
+                               char const *const txtname,
+                               uint_t *const recvalp,
+                               Elf_Shdr const *const symhdr,
+                               Elf_Ehdr const *const ehdr)
+{
+       Elf_Sym const *const sym0 = (Elf_Sym const *)(_w(symhdr->sh_offset)
+               + (void *)ehdr);
+       unsigned const nsym = _w(symhdr->sh_size) / _w(symhdr->sh_entsize);
+       Elf_Sym const *symp;
+       unsigned t;
+
+       for (symp = sym0, t = nsym; t; --t, ++symp) {
+               unsigned int const st_bind = ELF_ST_BIND(symp->st_info);
+
+               if (txtndx == w2(symp->st_shndx)
+                       /* avoid STB_WEAK */
+                   && (STB_LOCAL == st_bind || STB_GLOBAL == st_bind)) {
+                       *recvalp = _w(symp->st_value);
+                       return symp - sym0;
+               }
+       }
+       fprintf(stderr, "Cannot find symbol for section %d: %s.\n",
+               txtndx, txtname);
+       fail_file();
+}
+
+
+/* Evade ISO C restriction: no declaration after statement in has_rel_mcount. */
+static char const *
+__has_rel_mcount(Elf_Shdr const *const relhdr,  /* is SHT_REL or SHT_RELA */
+                Elf_Shdr const *const shdr0,
+                char const *const shstrtab,
+                char const *const fname)
+{
+       /* .sh_info depends on .sh_type == SHT_REL[,A] */
+       Elf_Shdr const *const txthdr = &shdr0[w(relhdr->sh_info)];
+       char const *const txtname = &shstrtab[w(txthdr->sh_name)];
+
+       if (0 == strcmp("__mcount_loc", txtname)) {
+               fprintf(stderr, "warning: __mcount_loc already exists: %s\n",
+                       fname);
+               succeed_file();
+       }
+       if (SHT_PROGBITS != w(txthdr->sh_type) ||
+           !is_mcounted_section_name(txtname))
+               return NULL;
+       return txtname;
+}
+
+static char const *has_rel_mcount(Elf_Shdr const *const relhdr,
+                                 Elf_Shdr const *const shdr0,
+                                 char const *const shstrtab,
+                                 char const *const fname)
+{
+       if (SHT_REL  != w(relhdr->sh_type) && SHT_RELA != w(relhdr->sh_type))
+               return NULL;
+       return __has_rel_mcount(relhdr, shdr0, shstrtab, fname);
+}
+
+
+static unsigned tot_relsize(Elf_Shdr const *const shdr0,
+                           unsigned nhdr,
+                           const char *const shstrtab,
+                           const char *const fname)
+{
+       unsigned totrelsz = 0;
+       Elf_Shdr const *shdrp = shdr0;
+
+       for (; nhdr; --nhdr, ++shdrp) {
+               if (has_rel_mcount(shdrp, shdr0, shstrtab, fname))
+                       totrelsz += _w(shdrp->sh_size);
+       }
+       return totrelsz;
+}
+
+
+/* Overall supervision for Elf32 ET_REL file. */
+static void
+do_func(Elf_Ehdr *const ehdr, char const *const fname, unsigned const reltype)
+{
+       Elf_Shdr *const shdr0 = (Elf_Shdr *)(_w(ehdr->e_shoff)
+               + (void *)ehdr);
+       unsigned const nhdr = w2(ehdr->e_shnum);
+       Elf_Shdr *const shstr = &shdr0[w2(ehdr->e_shstrndx)];
+       char const *const shstrtab = (char const *)(_w(shstr->sh_offset)
+               + (void *)ehdr);
+
+       Elf_Shdr const *relhdr;
+       unsigned k;
+
+       /* Upper bound on space: assume all relevant relocs are for mcount. */
+       unsigned const totrelsz = tot_relsize(shdr0, nhdr, shstrtab, fname);
+       Elf_Rel *const mrel0 = umalloc(totrelsz);
+       Elf_Rel *      mrelp = mrel0;
+
+       /* 2*sizeof(address) <= sizeof(Elf_Rel) */
+       uint_t *const mloc0 = umalloc(totrelsz>>1);
+       uint_t *      mlocp = mloc0;
+
+       unsigned rel_entsize = 0;
+       unsigned symsec_sh_link = 0;
+
+       for (relhdr = shdr0, k = nhdr; k; --k, ++relhdr) {
+               char const *const txtname = has_rel_mcount(relhdr, shdr0,
+                       shstrtab, fname);
+               if (txtname) {
+                       uint_t recval = 0;
+                       unsigned const recsym = find_secsym_ndx(
+                               w(relhdr->sh_info), txtname, &recval,
+                               &shdr0[symsec_sh_link = w(relhdr->sh_link)],
+                               ehdr);
+
+                       rel_entsize = _w(relhdr->sh_entsize);
+                       mlocp = sift_rel_mcount(mlocp,
+                               (void *)mlocp - (void *)mloc0, &mrelp,
+                               relhdr, ehdr, recsym, recval, reltype);
+               }
+       }
+       if (mloc0 != mlocp) {
+               append_func(ehdr, shstr, mloc0, mlocp, mrel0, mrelp,
+                           rel_entsize, symsec_sh_link);
+       }
+       free(mrel0);
+       free(mloc0);
+}
index e67f054860877d676fc4359ef2f670b5d7531479..1d7963f4ee79b853055337f3eed7ca80731dc667 100755 (executable)
@@ -270,6 +270,8 @@ if ($arch eq "x86_64") {
 } elsif ($arch eq "arm") {
     $alignment = 2;
     $section_type = '%progbits';
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_ARM_(CALL|PC24|THM_CALL)" .
+                       "\\s+(__gnu_mcount_nc|mcount)\$";
 
 } elsif ($arch eq "ia64") {
     $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
index 0a0a99f3b08331f78f7499c5e964929af20e96c9..4d995aeaebc0ad0a3232faebead627da4ebb40b9 100644 (file)
@@ -3,3 +3,4 @@
 #
 af_names.h
 capability_names.h
+rlim_names.h
index 7320331b44aba5bd52eac6b2a97302ad21a4ca5f..544ff5837cb640623dadd738fe8879d823574eda 100644 (file)
@@ -29,7 +29,7 @@
  * aa_simple_write_to_buffer - common routine for getting policy from user
  * @op: operation doing the user buffer copy
  * @userbuf: user buffer to copy data from  (NOT NULL)
- * @alloc_size: size of user buffer
+ * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size)
  * @copy_size: size of data to copy from user buffer
  * @pos: position write is at in the file (NOT NULL)
  *
@@ -42,6 +42,8 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
 {
        char *data;
 
+       BUG_ON(copy_size > alloc_size);
+
        if (*pos != 0)
                /* only writes from pos 0, that is complete writes */
                return ERR_PTR(-ESPIPE);
index 95a6599a37bb3ae0737779d16d9a0d811d5bfc82..30ae00fbecd591591acb55c1431d62a1bbbac427 100644 (file)
@@ -677,7 +677,18 @@ static void cap_inet_conn_established(struct sock *sk, struct sk_buff *skb)
 {
 }
 
+static int cap_secmark_relabel_packet(u32 secid)
+{
+       return 0;
+}
 
+static void cap_secmark_refcount_inc(void)
+{
+}
+
+static void cap_secmark_refcount_dec(void)
+{
+}
 
 static void cap_req_classify_flow(const struct request_sock *req,
                                  struct flowi *fl)
@@ -777,7 +788,8 @@ static int cap_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 
 static int cap_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
 {
-       return -EOPNOTSUPP;
+       *secid = 0;
+       return 0;
 }
 
 static void cap_release_secctx(char *secdata, u32 seclen)
@@ -1018,6 +1030,9 @@ void __init security_fixup_ops(struct security_operations *ops)
        set_to_cap_if_null(ops, inet_conn_request);
        set_to_cap_if_null(ops, inet_csk_clone);
        set_to_cap_if_null(ops, inet_conn_established);
+       set_to_cap_if_null(ops, secmark_relabel_packet);
+       set_to_cap_if_null(ops, secmark_refcount_inc);
+       set_to_cap_if_null(ops, secmark_refcount_dec);
        set_to_cap_if_null(ops, req_classify_flow);
        set_to_cap_if_null(ops, tun_dev_create);
        set_to_cap_if_null(ops, tun_dev_post_create);
index 9d172e6e330c9fd7906a8a2e5754713f80dfb433..5e632b4857e443d8031eaa17c0e2bd7e877b3d14 100644 (file)
@@ -719,14 +719,11 @@ static int cap_safe_nice(struct task_struct *p)
 /**
  * cap_task_setscheduler - Detemine if scheduler policy change is permitted
  * @p: The task to affect
- * @policy: The policy to effect
- * @lp: The parameters to the scheduling policy
  *
  * Detemine if the requested scheduler policy change is permitted for the
  * specified task, returning 0 if permission is granted, -ve if denied.
  */
-int cap_task_setscheduler(struct task_struct *p, int policy,
-                          struct sched_param *lp)
+int cap_task_setscheduler(struct task_struct *p)
 {
        return cap_safe_nice(p);
 }
index c53949f17d9e0dddc0601032576ef2922fb88f86..b50f472061a43c6ec7fb53781c084fb2cb487dcb 100644 (file)
@@ -89,20 +89,12 @@ __setup("security=", choose_lsm);
  * Return true if:
  *     -The passed LSM is the one chosen by user at boot time,
  *     -or the passed LSM is configured as the default and the user did not
- *      choose an alternate LSM at boot time,
- *     -or there is no default LSM set and the user didn't specify a
- *      specific LSM and we're the first to ask for registration permission,
- *     -or the passed LSM is currently loaded.
+ *      choose an alternate LSM at boot time.
  * Otherwise, return false.
  */
 int __init security_module_enable(struct security_operations *ops)
 {
-       if (!*chosen_lsm)
-               strncpy(chosen_lsm, ops->name, SECURITY_NAME_MAX);
-       else if (strncmp(ops->name, chosen_lsm, SECURITY_NAME_MAX))
-               return 0;
-
-       return 1;
+       return !strcmp(ops->name, chosen_lsm);
 }
 
 /**
@@ -786,10 +778,9 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource,
        return security_ops->task_setrlimit(p, resource, new_rlim);
 }
 
-int security_task_setscheduler(struct task_struct *p,
-                               int policy, struct sched_param *lp)
+int security_task_setscheduler(struct task_struct *p)
 {
-       return security_ops->task_setscheduler(p, policy, lp);
+       return security_ops->task_setscheduler(p);
 }
 
 int security_task_getscheduler(struct task_struct *p)
@@ -1145,6 +1136,24 @@ void security_inet_conn_established(struct sock *sk,
        security_ops->inet_conn_established(sk, skb);
 }
 
+int security_secmark_relabel_packet(u32 secid)
+{
+       return security_ops->secmark_relabel_packet(secid);
+}
+EXPORT_SYMBOL(security_secmark_relabel_packet);
+
+void security_secmark_refcount_inc(void)
+{
+       security_ops->secmark_refcount_inc();
+}
+EXPORT_SYMBOL(security_secmark_refcount_inc);
+
+void security_secmark_refcount_dec(void)
+{
+       security_ops->secmark_refcount_dec();
+}
+EXPORT_SYMBOL(security_secmark_refcount_dec);
+
 int security_tun_dev_create(void)
 {
        return security_ops->tun_dev_create();
index 58d80f3bd6f681f6d366f5b67becd7ff433ce2c7..ad5cd76ec231cd14f02b2fb15f07a3d8a069972f 100644 (file)
@@ -2,25 +2,20 @@
 # Makefile for building the SELinux module as part of the kernel tree.
 #
 
-obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/
-
-selinux-y := avc.o \
-            hooks.o \
-            selinuxfs.o \
-            netlink.o \
-            nlmsgtab.o \
-            netif.o \
-            netnode.o \
-            netport.o \
-            exports.o
+obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
+
+selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
+            netnode.o netport.o exports.o \
+            ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
+            ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o
 
 selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
 
 selinux-$(CONFIG_NETLABEL) += netlabel.o
 
-EXTRA_CFLAGS += -Isecurity/selinux -Isecurity/selinux/include
+ccflags-y := -Isecurity/selinux -Isecurity/selinux/include
 
-$(obj)/avc.o: $(obj)/flask.h
+$(addprefix $(obj)/,$(selinux-y)): $(obj)/flask.h
 
 quiet_cmd_flask = GEN     $(obj)/flask.h $(obj)/av_permissions.h
       cmd_flask = scripts/selinux/genheaders/genheaders $(obj)/flask.h $(obj)/av_permissions.h
index c0a454aee1e03cb0e3825a2c5f965c941636c4d9..90664385dead0df01f6eec2b7479c83f4f021160 100644 (file)
  * it under the terms of the GNU General Public License version 2,
  * as published by the Free Software Foundation.
  */
-#include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/selinux.h>
-#include <linux/fs.h>
-#include <linux/ipc.h>
-#include <asm/atomic.h>
 
 #include "security.h"
-#include "objsec.h"
-
-/* SECMARK reference count */
-extern atomic_t selinux_secmark_refcount;
-
-int selinux_string_to_sid(char *str, u32 *sid)
-{
-       if (selinux_enabled)
-               return security_context_to_sid(str, strlen(str), sid);
-       else {
-               *sid = 0;
-               return 0;
-       }
-}
-EXPORT_SYMBOL_GPL(selinux_string_to_sid);
-
-int selinux_secmark_relabel_packet_permission(u32 sid)
-{
-       if (selinux_enabled) {
-               const struct task_security_struct *__tsec;
-               u32 tsid;
-
-               __tsec = current_security();
-               tsid = __tsec->sid;
-
-               return avc_has_perm(tsid, sid, SECCLASS_PACKET,
-                                   PACKET__RELABELTO, NULL);
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(selinux_secmark_relabel_packet_permission);
-
-void selinux_secmark_refcount_inc(void)
-{
-       atomic_inc(&selinux_secmark_refcount);
-}
-EXPORT_SYMBOL_GPL(selinux_secmark_refcount_inc);
-
-void selinux_secmark_refcount_dec(void)
-{
-       atomic_dec(&selinux_secmark_refcount);
-}
-EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec);
 
 bool selinux_is_enabled(void)
 {
index 4796ddd4e721ae454a02563d713aa235870ece02..d9154cf90ae19cd4eb5f40d65882abb60781da3d 100644 (file)
@@ -3354,11 +3354,11 @@ static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
        return 0;
 }
 
-static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp)
+static int selinux_task_setscheduler(struct task_struct *p)
 {
        int rc;
 
-       rc = cap_task_setscheduler(p, policy, lp);
+       rc = cap_task_setscheduler(p);
        if (rc)
                return rc;
 
@@ -4279,6 +4279,27 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
        selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
 }
 
+static int selinux_secmark_relabel_packet(u32 sid)
+{
+       const struct task_security_struct *__tsec;
+       u32 tsid;
+
+       __tsec = current_security();
+       tsid = __tsec->sid;
+
+       return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, NULL);
+}
+
+static void selinux_secmark_refcount_inc(void)
+{
+       atomic_inc(&selinux_secmark_refcount);
+}
+
+static void selinux_secmark_refcount_dec(void)
+{
+       atomic_dec(&selinux_secmark_refcount);
+}
+
 static void selinux_req_classify_flow(const struct request_sock *req,
                                      struct flowi *fl)
 {
@@ -5533,6 +5554,9 @@ static struct security_operations selinux_ops = {
        .inet_conn_request =            selinux_inet_conn_request,
        .inet_csk_clone =               selinux_inet_csk_clone,
        .inet_conn_established =        selinux_inet_conn_established,
+       .secmark_relabel_packet =       selinux_secmark_relabel_packet,
+       .secmark_refcount_inc =         selinux_secmark_refcount_inc,
+       .secmark_refcount_dec =         selinux_secmark_refcount_dec,
        .req_classify_flow =            selinux_req_classify_flow,
        .tun_dev_create =               selinux_tun_dev_create,
        .tun_dev_post_create =          selinux_tun_dev_post_create,
index b4c9eb4bd6f9127a506e2a4483c592362c8fcafa..8858d2b2d4b6ad1dd1b005b20a06afa4a3505d03 100644 (file)
@@ -17,7 +17,7 @@ struct security_class_mapping secclass_map[] = {
          { "compute_av", "compute_create", "compute_member",
            "check_context", "load_policy", "compute_relabel",
            "compute_user", "setenforce", "setbool", "setsecparam",
-           "setcheckreqprot", NULL } },
+           "setcheckreqprot", "read_policy", NULL } },
        { "process",
          { "fork", "transition", "sigchld", "sigkill",
            "sigstop", "signull", "signal", "ptrace", "getsched", "setsched",
index 1f7c2491d3dccbc54769a6ccaf509d50255cfe3f..671273eb1115c4e7f05983af071069aea7535650 100644 (file)
@@ -9,6 +9,7 @@
 #define _SELINUX_SECURITY_H_
 
 #include <linux/magic.h>
+#include <linux/types.h>
 #include "flask.h"
 
 #define SECSID_NULL                    0x00000000 /* unspecified SID */
@@ -82,6 +83,8 @@ extern int selinux_policycap_openperm;
 int security_mls_enabled(void);
 
 int security_load_policy(void *data, size_t len);
+int security_read_policy(void **data, ssize_t *len);
+size_t security_policydb_len(void);
 
 int security_policycap_supported(unsigned int req_cap);
 
@@ -191,5 +194,25 @@ static inline int security_netlbl_sid_to_secattr(u32 sid,
 
 const char *security_get_initial_sid_context(u32 sid);
 
+/*
+ * status notifier using mmap interface
+ */
+extern struct page *selinux_kernel_status_page(void);
+
+#define SELINUX_KERNEL_STATUS_VERSION  1
+struct selinux_kernel_status {
+       u32     version;        /* version number of thie structure */
+       u32     sequence;       /* sequence number of seqlock logic */
+       u32     enforcing;      /* current setting of enforcing mode */
+       u32     policyload;     /* times of policy reloaded */
+       u32     deny_unknown;   /* current setting of deny_unknown */
+       /*
+        * The version > 0 supports above members.
+        */
+} __attribute__((packed));
+
+extern void selinux_status_update_setenforce(int enforcing);
+extern void selinux_status_update_policyload(int seqno);
+
 #endif /* _SELINUX_SECURITY_H_ */
 
index 79a1bb635662fbc7f65a306e10b5b67e534fcf1c..87e0556bae70ff977ea290b3cdfcc2c308d8edf5 100644 (file)
@@ -68,6 +68,8 @@ static int *bool_pending_values;
 static struct dentry *class_dir;
 static unsigned long last_class_ino;
 
+static char policy_opened;
+
 /* global data for policy capabilities */
 static struct dentry *policycap_dir;
 
@@ -110,6 +112,8 @@ enum sel_inos {
        SEL_COMPAT_NET, /* whether to use old compat network packet controls */
        SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
        SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
+       SEL_STATUS,     /* export current status using mmap() */
+       SEL_POLICY,     /* allow userspace to read the in kernel policy */
        SEL_INO_NEXT,   /* The next inode number to use */
 };
 
@@ -171,6 +175,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
                if (selinux_enforcing)
                        avc_ss_reset(0);
                selnl_notify_setenforce(selinux_enforcing);
+               selinux_status_update_setenforce(selinux_enforcing);
        }
        length = count;
 out:
@@ -205,6 +210,59 @@ static const struct file_operations sel_handle_unknown_ops = {
        .llseek         = generic_file_llseek,
 };
 
+static int sel_open_handle_status(struct inode *inode, struct file *filp)
+{
+       struct page    *status = selinux_kernel_status_page();
+
+       if (!status)
+               return -ENOMEM;
+
+       filp->private_data = status;
+
+       return 0;
+}
+
+static ssize_t sel_read_handle_status(struct file *filp, char __user *buf,
+                                     size_t count, loff_t *ppos)
+{
+       struct page    *status = filp->private_data;
+
+       BUG_ON(!status);
+
+       return simple_read_from_buffer(buf, count, ppos,
+                                      page_address(status),
+                                      sizeof(struct selinux_kernel_status));
+}
+
+static int sel_mmap_handle_status(struct file *filp,
+                                 struct vm_area_struct *vma)
+{
+       struct page    *status = filp->private_data;
+       unsigned long   size = vma->vm_end - vma->vm_start;
+
+       BUG_ON(!status);
+
+       /* only allows one page from the head */
+       if (vma->vm_pgoff > 0 || size != PAGE_SIZE)
+               return -EIO;
+       /* disallow writable mapping */
+       if (vma->vm_flags & VM_WRITE)
+               return -EPERM;
+       /* disallow mprotect() turns it into writable */
+       vma->vm_flags &= ~VM_MAYWRITE;
+
+       return remap_pfn_range(vma, vma->vm_start,
+                              page_to_pfn(status),
+                              size, vma->vm_page_prot);
+}
+
+static const struct file_operations sel_handle_status_ops = {
+       .open           = sel_open_handle_status,
+       .read           = sel_read_handle_status,
+       .mmap           = sel_mmap_handle_status,
+       .llseek         = generic_file_llseek,
+};
+
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 static ssize_t sel_write_disable(struct file *file, const char __user *buf,
                                 size_t count, loff_t *ppos)
@@ -296,6 +354,141 @@ static const struct file_operations sel_mls_ops = {
        .llseek         = generic_file_llseek,
 };
 
+struct policy_load_memory {
+       size_t len;
+       void *data;
+};
+
+static int sel_open_policy(struct inode *inode, struct file *filp)
+{
+       struct policy_load_memory *plm = NULL;
+       int rc;
+
+       BUG_ON(filp->private_data);
+
+       mutex_lock(&sel_mutex);
+
+       rc = task_has_security(current, SECURITY__READ_POLICY);
+       if (rc)
+               goto err;
+
+       rc = -EBUSY;
+       if (policy_opened)
+               goto err;
+
+       rc = -ENOMEM;
+       plm = kzalloc(sizeof(*plm), GFP_KERNEL);
+       if (!plm)
+               goto err;
+
+       if (i_size_read(inode) != security_policydb_len()) {
+               mutex_lock(&inode->i_mutex);
+               i_size_write(inode, security_policydb_len());
+               mutex_unlock(&inode->i_mutex);
+       }
+
+       rc = security_read_policy(&plm->data, &plm->len);
+       if (rc)
+               goto err;
+
+       policy_opened = 1;
+
+       filp->private_data = plm;
+
+       mutex_unlock(&sel_mutex);
+
+       return 0;
+err:
+       mutex_unlock(&sel_mutex);
+
+       if (plm)
+               vfree(plm->data);
+       kfree(plm);
+       return rc;
+}
+
+static int sel_release_policy(struct inode *inode, struct file *filp)
+{
+       struct policy_load_memory *plm = filp->private_data;
+
+       BUG_ON(!plm);
+
+       policy_opened = 0;
+
+       vfree(plm->data);
+       kfree(plm);
+
+       return 0;
+}
+
+static ssize_t sel_read_policy(struct file *filp, char __user *buf,
+                              size_t count, loff_t *ppos)
+{
+       struct policy_load_memory *plm = filp->private_data;
+       int ret;
+
+       mutex_lock(&sel_mutex);
+
+       ret = task_has_security(current, SECURITY__READ_POLICY);
+       if (ret)
+               goto out;
+
+       ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
+out:
+       mutex_unlock(&sel_mutex);
+       return ret;
+}
+
+static int sel_mmap_policy_fault(struct vm_area_struct *vma,
+                                struct vm_fault *vmf)
+{
+       struct policy_load_memory *plm = vma->vm_file->private_data;
+       unsigned long offset;
+       struct page *page;
+
+       if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE))
+               return VM_FAULT_SIGBUS;
+
+       offset = vmf->pgoff << PAGE_SHIFT;
+       if (offset >= roundup(plm->len, PAGE_SIZE))
+               return VM_FAULT_SIGBUS;
+
+       page = vmalloc_to_page(plm->data + offset);
+       get_page(page);
+
+       vmf->page = page;
+
+       return 0;
+}
+
+static struct vm_operations_struct sel_mmap_policy_ops = {
+       .fault = sel_mmap_policy_fault,
+       .page_mkwrite = sel_mmap_policy_fault,
+};
+
+int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma)
+{
+       if (vma->vm_flags & VM_SHARED) {
+               /* do not allow mprotect to make mapping writable */
+               vma->vm_flags &= ~VM_MAYWRITE;
+
+               if (vma->vm_flags & VM_WRITE)
+                       return -EACCES;
+       }
+
+       vma->vm_flags |= VM_RESERVED;
+       vma->vm_ops = &sel_mmap_policy_ops;
+
+       return 0;
+}
+
+static const struct file_operations sel_policy_ops = {
+       .open           = sel_open_policy,
+       .read           = sel_read_policy,
+       .mmap           = sel_mmap_policy,
+       .release        = sel_release_policy,
+};
+
 static ssize_t sel_write_load(struct file *file, const char __user *buf,
                              size_t count, loff_t *ppos)
 
@@ -1612,6 +1805,8 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
                [SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
                [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
                [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
+               [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
+               [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR},
                /* last one */ {""}
        };
        ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
diff --git a/security/selinux/ss/Makefile b/security/selinux/ss/Makefile
deleted file mode 100644 (file)
index 15d4e62..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for building the SELinux security server as part of the kernel tree.
-#
-
-EXTRA_CFLAGS += -Isecurity/selinux -Isecurity/selinux/include
-obj-y := ss.o
-
-ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o
-
index 929480c6c4306e874eff82db107045b944cdd33b..a3dd9faa19c01eda269b13f7cfcd7ab6da6aa098 100644 (file)
@@ -266,8 +266,8 @@ int avtab_alloc(struct avtab *h, u32 nrules)
        if (shift > 2)
                shift = shift - 2;
        nslot = 1 << shift;
-       if (nslot > MAX_AVTAB_SIZE)
-               nslot = MAX_AVTAB_SIZE;
+       if (nslot > MAX_AVTAB_HASH_BUCKETS)
+               nslot = MAX_AVTAB_HASH_BUCKETS;
        mask = nslot - 1;
 
        h->htable = kcalloc(nslot, sizeof(*(h->htable)), GFP_KERNEL);
@@ -501,6 +501,48 @@ bad:
        goto out;
 }
 
+int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp)
+{
+       __le16 buf16[4];
+       __le32 buf32[1];
+       int rc;
+
+       buf16[0] = cpu_to_le16(cur->key.source_type);
+       buf16[1] = cpu_to_le16(cur->key.target_type);
+       buf16[2] = cpu_to_le16(cur->key.target_class);
+       buf16[3] = cpu_to_le16(cur->key.specified);
+       rc = put_entry(buf16, sizeof(u16), 4, fp);
+       if (rc)
+               return rc;
+       buf32[0] = cpu_to_le32(cur->datum.data);
+       rc = put_entry(buf32, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+       return 0;
+}
+
+int avtab_write(struct policydb *p, struct avtab *a, void *fp)
+{
+       unsigned int i;
+       int rc = 0;
+       struct avtab_node *cur;
+       __le32 buf[1];
+
+       buf[0] = cpu_to_le32(a->nel);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < a->nslot; i++) {
+               for (cur = a->htable[i]; cur; cur = cur->next) {
+                       rc = avtab_write_item(p, cur, fp);
+                       if (rc)
+                               return rc;
+               }
+       }
+
+       return rc;
+}
 void avtab_cache_init(void)
 {
        avtab_node_cachep = kmem_cache_create("avtab_node",
index cd4f734e27499cf2f9e203f0edb2557cf02bc24c..dff0c75345c1642fd2b3181a6677035947834951 100644 (file)
@@ -71,6 +71,8 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol,
                    void *p);
 
 int avtab_read(struct avtab *a, void *fp, struct policydb *pol);
+int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp);
+int avtab_write(struct policydb *p, struct avtab *a, void *fp);
 
 struct avtab_node *avtab_insert_nonunique(struct avtab *h, struct avtab_key *key,
                                          struct avtab_datum *datum);
@@ -85,7 +87,6 @@ void avtab_cache_destroy(void);
 #define MAX_AVTAB_HASH_BITS 11
 #define MAX_AVTAB_HASH_BUCKETS (1 << MAX_AVTAB_HASH_BITS)
 #define MAX_AVTAB_HASH_MASK (MAX_AVTAB_HASH_BUCKETS-1)
-#define MAX_AVTAB_SIZE MAX_AVTAB_HASH_BUCKETS
 
 #endif /* _SS_AVTAB_H_ */
 
index c91e150c3087d78127eb8ca6cc6faccf04e9cd32..655fe1c6cc69dccd862b3142a37e41b6fb4010a7 100644 (file)
@@ -490,6 +490,129 @@ err:
        return rc;
 }
 
+int cond_write_bool(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct cond_bool_datum *booldatum = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       __le32 buf[3];
+       u32 len;
+       int rc;
+
+       len = strlen(key);
+       buf[0] = cpu_to_le32(booldatum->value);
+       buf[1] = cpu_to_le32(booldatum->state);
+       buf[2] = cpu_to_le32(len);
+       rc = put_entry(buf, sizeof(u32), 3, fp);
+       if (rc)
+               return rc;
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+       return 0;
+}
+
+/*
+ * cond_write_cond_av_list doesn't write out the av_list nodes.
+ * Instead it writes out the key/value pairs from the avtab. This
+ * is necessary because there is no way to uniquely identifying rules
+ * in the avtab so it is not possible to associate individual rules
+ * in the avtab with a conditional without saving them as part of
+ * the conditional. This means that the avtab with the conditional
+ * rules will not be saved but will be rebuilt on policy load.
+ */
+static int cond_write_av_list(struct policydb *p,
+                             struct cond_av_list *list, struct policy_file *fp)
+{
+       __le32 buf[1];
+       struct cond_av_list *cur_list;
+       u32 len;
+       int rc;
+
+       len = 0;
+       for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
+               len++;
+
+       buf[0] = cpu_to_le32(len);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       if (len == 0)
+               return 0;
+
+       for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
+               rc = avtab_write_item(p, cur_list->node, fp);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+int cond_write_node(struct policydb *p, struct cond_node *node,
+                   struct policy_file *fp)
+{
+       struct cond_expr *cur_expr;
+       __le32 buf[2];
+       int rc;
+       u32 len = 0;
+
+       buf[0] = cpu_to_le32(node->cur_state);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
+               len++;
+
+       buf[0] = cpu_to_le32(len);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
+               buf[0] = cpu_to_le32(cur_expr->expr_type);
+               buf[1] = cpu_to_le32(cur_expr->bool);
+               rc = put_entry(buf, sizeof(u32), 2, fp);
+               if (rc)
+                       return rc;
+       }
+
+       rc = cond_write_av_list(p, node->true_list, fp);
+       if (rc)
+               return rc;
+       rc = cond_write_av_list(p, node->false_list, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
+{
+       struct cond_node *cur;
+       u32 len;
+       __le32 buf[1];
+       int rc;
+
+       len = 0;
+       for (cur = list; cur != NULL; cur = cur->next)
+               len++;
+       buf[0] = cpu_to_le32(len);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       for (cur = list; cur != NULL; cur = cur->next) {
+               rc = cond_write_node(p, cur, fp);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
 /* Determine whether additional permissions are granted by the conditional
  * av table, and if so, add them to the result
  */
index 53ddb013ae573f8bb053da9fa9416fbcf5ee9701..3f209c635295681f026874e332573577e743dea4 100644 (file)
@@ -69,6 +69,8 @@ int cond_index_bool(void *key, void *datum, void *datap);
 
 int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
 int cond_read_list(struct policydb *p, void *fp);
+int cond_write_bool(void *key, void *datum, void *ptr);
+int cond_write_list(struct policydb *p, struct cond_node *list, void *fp);
 
 void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd);
 
index 04b6145d767f96093423d5f733e6fe1b6a4e5687..d42951fcbe877355b08c16d5a63526c729f4355c 100644 (file)
@@ -22,6 +22,8 @@
 #include "ebitmap.h"
 #include "policydb.h"
 
+#define BITS_PER_U64   (sizeof(u64) * 8)
+
 int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2)
 {
        struct ebitmap_node *n1, *n2;
@@ -363,10 +365,10 @@ int ebitmap_read(struct ebitmap *e, void *fp)
        e->highbit = le32_to_cpu(buf[1]);
        count = le32_to_cpu(buf[2]);
 
-       if (mapunit != sizeof(u64) * 8) {
+       if (mapunit != BITS_PER_U64) {
                printk(KERN_ERR "SELinux: ebitmap: map size %u does not "
                       "match my size %Zd (high bit was %d)\n",
-                      mapunit, sizeof(u64) * 8, e->highbit);
+                      mapunit, BITS_PER_U64, e->highbit);
                goto bad;
        }
 
@@ -446,3 +448,78 @@ bad:
        ebitmap_destroy(e);
        goto out;
 }
+
+int ebitmap_write(struct ebitmap *e, void *fp)
+{
+       struct ebitmap_node *n;
+       u32 count;
+       __le32 buf[3];
+       u64 map;
+       int bit, last_bit, last_startbit, rc;
+
+       buf[0] = cpu_to_le32(BITS_PER_U64);
+
+       count = 0;
+       last_bit = 0;
+       last_startbit = -1;
+       ebitmap_for_each_positive_bit(e, n, bit) {
+               if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) {
+                       count++;
+                       last_startbit = rounddown(bit, BITS_PER_U64);
+               }
+               last_bit = roundup(bit + 1, BITS_PER_U64);
+       }
+       buf[1] = cpu_to_le32(last_bit);
+       buf[2] = cpu_to_le32(count);
+
+       rc = put_entry(buf, sizeof(u32), 3, fp);
+       if (rc)
+               return rc;
+
+       map = 0;
+       last_startbit = INT_MIN;
+       ebitmap_for_each_positive_bit(e, n, bit) {
+               if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) {
+                       __le64 buf64[1];
+
+                       /* this is the very first bit */
+                       if (!map) {
+                               last_startbit = rounddown(bit, BITS_PER_U64);
+                               map = (u64)1 << (bit - last_startbit);
+                               continue;
+                       }
+
+                       /* write the last node */
+                       buf[0] = cpu_to_le32(last_startbit);
+                       rc = put_entry(buf, sizeof(u32), 1, fp);
+                       if (rc)
+                               return rc;
+
+                       buf64[0] = cpu_to_le64(map);
+                       rc = put_entry(buf64, sizeof(u64), 1, fp);
+                       if (rc)
+                               return rc;
+
+                       /* set up for the next node */
+                       map = 0;
+                       last_startbit = rounddown(bit, BITS_PER_U64);
+               }
+               map |= (u64)1 << (bit - last_startbit);
+       }
+       /* write the last node */
+       if (map) {
+               __le64 buf64[1];
+
+               /* write the last node */
+               buf[0] = cpu_to_le32(last_startbit);
+               rc = put_entry(buf, sizeof(u32), 1, fp);
+               if (rc)
+                       return rc;
+
+               buf64[0] = cpu_to_le64(map);
+               rc = put_entry(buf64, sizeof(u64), 1, fp);
+               if (rc)
+                       return rc;
+       }
+       return 0;
+}
index f283b4367f54d640e6a3b6fedb8f3180786883c3..1f4e93c2ae8695430c4a9ff33cfd31e7d36cec36 100644 (file)
@@ -123,6 +123,7 @@ int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
 int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
 void ebitmap_destroy(struct ebitmap *e);
 int ebitmap_read(struct ebitmap *e, void *fp);
+int ebitmap_write(struct ebitmap *e, void *fp);
 
 #ifdef CONFIG_NETLABEL
 int ebitmap_netlbl_export(struct ebitmap *ebmap,
index 3a29704be8ce10f4409dd0a3d4f0bea8bb0d1086..94f630d93a5c5d0964a51e030646d26652619ee6 100644 (file)
@@ -37,6 +37,7 @@
 #include "policydb.h"
 #include "conditional.h"
 #include "mls.h"
+#include "services.h"
 
 #define _DEBUG_HASHES
 
@@ -185,9 +186,19 @@ static u32 rangetr_hash(struct hashtab *h, const void *k)
 static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
 {
        const struct range_trans *key1 = k1, *key2 = k2;
-       return (key1->source_type != key2->source_type ||
-               key1->target_type != key2->target_type ||
-               key1->target_class != key2->target_class);
+       int v;
+
+       v = key1->source_type - key2->source_type;
+       if (v)
+               return v;
+
+       v = key1->target_type - key2->target_type;
+       if (v)
+               return v;
+
+       v = key1->target_class - key2->target_class;
+
+       return v;
 }
 
 /*
@@ -1624,11 +1635,11 @@ static int role_bounds_sanity_check(void *key, void *datum, void *datap)
 
 static int type_bounds_sanity_check(void *key, void *datum, void *datap)
 {
-       struct type_datum *upper, *type;
+       struct type_datum *upper;
        struct policydb *p = datap;
        int depth = 0;
 
-       upper = type = datum;
+       upper = datum;
        while (upper->bounds) {
                if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
                        printk(KERN_ERR "SELinux: type %s: "
@@ -2306,3 +2317,843 @@ bad:
        policydb_destroy(p);
        goto out;
 }
+
+/*
+ * Write a MLS level structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_level(struct mls_level *l, void *fp)
+{
+       __le32 buf[1];
+       int rc;
+
+       buf[0] = cpu_to_le32(l->sens);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       rc = ebitmap_write(&l->cat, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+/*
+ * Write a MLS range structure to a policydb binary
+ * representation file.
+ */
+static int mls_write_range_helper(struct mls_range *r, void *fp)
+{
+       __le32 buf[3];
+       size_t items;
+       int rc, eq;
+
+       eq = mls_level_eq(&r->level[1], &r->level[0]);
+
+       if (eq)
+               items = 2;
+       else
+               items = 3;
+       buf[0] = cpu_to_le32(items-1);
+       buf[1] = cpu_to_le32(r->level[0].sens);
+       if (!eq)
+               buf[2] = cpu_to_le32(r->level[1].sens);
+
+       BUG_ON(items > (sizeof(buf)/sizeof(buf[0])));
+
+       rc = put_entry(buf, sizeof(u32), items, fp);
+       if (rc)
+               return rc;
+
+       rc = ebitmap_write(&r->level[0].cat, fp);
+       if (rc)
+               return rc;
+       if (!eq) {
+               rc = ebitmap_write(&r->level[1].cat, fp);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static int sens_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct level_datum *levdatum = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       __le32 buf[2];
+       size_t len;
+       int rc;
+
+       len = strlen(key);
+       buf[0] = cpu_to_le32(len);
+       buf[1] = cpu_to_le32(levdatum->isalias);
+       rc = put_entry(buf, sizeof(u32), 2, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       rc = mls_write_level(levdatum->level, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int cat_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct cat_datum *catdatum = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       __le32 buf[3];
+       size_t len;
+       int rc;
+
+       len = strlen(key);
+       buf[0] = cpu_to_le32(len);
+       buf[1] = cpu_to_le32(catdatum->value);
+       buf[2] = cpu_to_le32(catdatum->isalias);
+       rc = put_entry(buf, sizeof(u32), 3, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int role_trans_write(struct role_trans *r, void *fp)
+{
+       struct role_trans *tr;
+       u32 buf[3];
+       size_t nel;
+       int rc;
+
+       nel = 0;
+       for (tr = r; tr; tr = tr->next)
+               nel++;
+       buf[0] = cpu_to_le32(nel);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+       for (tr = r; tr; tr = tr->next) {
+               buf[0] = cpu_to_le32(tr->role);
+               buf[1] = cpu_to_le32(tr->type);
+               buf[2] = cpu_to_le32(tr->new_role);
+               rc = put_entry(buf, sizeof(u32), 3, fp);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
+
+static int role_allow_write(struct role_allow *r, void *fp)
+{
+       struct role_allow *ra;
+       u32 buf[2];
+       size_t nel;
+       int rc;
+
+       nel = 0;
+       for (ra = r; ra; ra = ra->next)
+               nel++;
+       buf[0] = cpu_to_le32(nel);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+       for (ra = r; ra; ra = ra->next) {
+               buf[0] = cpu_to_le32(ra->role);
+               buf[1] = cpu_to_le32(ra->new_role);
+               rc = put_entry(buf, sizeof(u32), 2, fp);
+               if (rc)
+                       return rc;
+       }
+       return 0;
+}
+
+/*
+ * Write a security context structure
+ * to a policydb binary representation file.
+ */
+static int context_write(struct policydb *p, struct context *c,
+                        void *fp)
+{
+       int rc;
+       __le32 buf[3];
+
+       buf[0] = cpu_to_le32(c->user);
+       buf[1] = cpu_to_le32(c->role);
+       buf[2] = cpu_to_le32(c->type);
+
+       rc = put_entry(buf, sizeof(u32), 3, fp);
+       if (rc)
+               return rc;
+
+       rc = mls_write_range_helper(&c->range, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+/*
+ * The following *_write functions are used to
+ * write the symbol data to a policy database
+ * binary representation file.
+ */
+
+static int perm_write(void *vkey, void *datum, void *fp)
+{
+       char *key = vkey;
+       struct perm_datum *perdatum = datum;
+       __le32 buf[2];
+       size_t len;
+       int rc;
+
+       len = strlen(key);
+       buf[0] = cpu_to_le32(len);
+       buf[1] = cpu_to_le32(perdatum->value);
+       rc = put_entry(buf, sizeof(u32), 2, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int common_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct common_datum *comdatum = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       __le32 buf[4];
+       size_t len;
+       int rc;
+
+       len = strlen(key);
+       buf[0] = cpu_to_le32(len);
+       buf[1] = cpu_to_le32(comdatum->value);
+       buf[2] = cpu_to_le32(comdatum->permissions.nprim);
+       buf[3] = cpu_to_le32(comdatum->permissions.table->nel);
+       rc = put_entry(buf, sizeof(u32), 4, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       rc = hashtab_map(comdatum->permissions.table, perm_write, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int write_cons_helper(struct policydb *p, struct constraint_node *node,
+                            void *fp)
+{
+       struct constraint_node *c;
+       struct constraint_expr *e;
+       __le32 buf[3];
+       u32 nel;
+       int rc;
+
+       for (c = node; c; c = c->next) {
+               nel = 0;
+               for (e = c->expr; e; e = e->next)
+                       nel++;
+               buf[0] = cpu_to_le32(c->permissions);
+               buf[1] = cpu_to_le32(nel);
+               rc = put_entry(buf, sizeof(u32), 2, fp);
+               if (rc)
+                       return rc;
+               for (e = c->expr; e; e = e->next) {
+                       buf[0] = cpu_to_le32(e->expr_type);
+                       buf[1] = cpu_to_le32(e->attr);
+                       buf[2] = cpu_to_le32(e->op);
+                       rc = put_entry(buf, sizeof(u32), 3, fp);
+                       if (rc)
+                               return rc;
+
+                       switch (e->expr_type) {
+                       case CEXPR_NAMES:
+                               rc = ebitmap_write(&e->names, fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int class_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct class_datum *cladatum = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       struct policydb *p = pd->p;
+       struct constraint_node *c;
+       __le32 buf[6];
+       u32 ncons;
+       size_t len, len2;
+       int rc;
+
+       len = strlen(key);
+       if (cladatum->comkey)
+               len2 = strlen(cladatum->comkey);
+       else
+               len2 = 0;
+
+       ncons = 0;
+       for (c = cladatum->constraints; c; c = c->next)
+               ncons++;
+
+       buf[0] = cpu_to_le32(len);
+       buf[1] = cpu_to_le32(len2);
+       buf[2] = cpu_to_le32(cladatum->value);
+       buf[3] = cpu_to_le32(cladatum->permissions.nprim);
+       if (cladatum->permissions.table)
+               buf[4] = cpu_to_le32(cladatum->permissions.table->nel);
+       else
+               buf[4] = 0;
+       buf[5] = cpu_to_le32(ncons);
+       rc = put_entry(buf, sizeof(u32), 6, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       if (cladatum->comkey) {
+               rc = put_entry(cladatum->comkey, 1, len2, fp);
+               if (rc)
+                       return rc;
+       }
+
+       rc = hashtab_map(cladatum->permissions.table, perm_write, fp);
+       if (rc)
+               return rc;
+
+       rc = write_cons_helper(p, cladatum->constraints, fp);
+       if (rc)
+               return rc;
+
+       /* write out the validatetrans rule */
+       ncons = 0;
+       for (c = cladatum->validatetrans; c; c = c->next)
+               ncons++;
+
+       buf[0] = cpu_to_le32(ncons);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       rc = write_cons_helper(p, cladatum->validatetrans, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int role_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct role_datum *role = datum;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       struct policydb *p = pd->p;
+       __le32 buf[3];
+       size_t items, len;
+       int rc;
+
+       len = strlen(key);
+       items = 0;
+       buf[items++] = cpu_to_le32(len);
+       buf[items++] = cpu_to_le32(role->value);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+               buf[items++] = cpu_to_le32(role->bounds);
+
+       BUG_ON(items > (sizeof(buf)/sizeof(buf[0])));
+
+       rc = put_entry(buf, sizeof(u32), items, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       rc = ebitmap_write(&role->dominates, fp);
+       if (rc)
+               return rc;
+
+       rc = ebitmap_write(&role->types, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int type_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct type_datum *typdatum = datum;
+       struct policy_data *pd = ptr;
+       struct policydb *p = pd->p;
+       void *fp = pd->fp;
+       __le32 buf[4];
+       int rc;
+       size_t items, len;
+
+       len = strlen(key);
+       items = 0;
+       buf[items++] = cpu_to_le32(len);
+       buf[items++] = cpu_to_le32(typdatum->value);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
+               u32 properties = 0;
+
+               if (typdatum->primary)
+                       properties |= TYPEDATUM_PROPERTY_PRIMARY;
+
+               if (typdatum->attribute)
+                       properties |= TYPEDATUM_PROPERTY_ATTRIBUTE;
+
+               buf[items++] = cpu_to_le32(properties);
+               buf[items++] = cpu_to_le32(typdatum->bounds);
+       } else {
+               buf[items++] = cpu_to_le32(typdatum->primary);
+       }
+       BUG_ON(items > (sizeof(buf) / sizeof(buf[0])));
+       rc = put_entry(buf, sizeof(u32), items, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int user_write(void *vkey, void *datum, void *ptr)
+{
+       char *key = vkey;
+       struct user_datum *usrdatum = datum;
+       struct policy_data *pd = ptr;
+       struct policydb *p = pd->p;
+       void *fp = pd->fp;
+       __le32 buf[3];
+       size_t items, len;
+       int rc;
+
+       len = strlen(key);
+       items = 0;
+       buf[items++] = cpu_to_le32(len);
+       buf[items++] = cpu_to_le32(usrdatum->value);
+       if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+               buf[items++] = cpu_to_le32(usrdatum->bounds);
+       BUG_ON(items > (sizeof(buf) / sizeof(buf[0])));
+       rc = put_entry(buf, sizeof(u32), items, fp);
+       if (rc)
+               return rc;
+
+       rc = put_entry(key, 1, len, fp);
+       if (rc)
+               return rc;
+
+       rc = ebitmap_write(&usrdatum->roles, fp);
+       if (rc)
+               return rc;
+
+       rc = mls_write_range_helper(&usrdatum->range, fp);
+       if (rc)
+               return rc;
+
+       rc = mls_write_level(&usrdatum->dfltlevel, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int (*write_f[SYM_NUM]) (void *key, void *datum,
+                               void *datap) =
+{
+       common_write,
+       class_write,
+       role_write,
+       type_write,
+       user_write,
+       cond_write_bool,
+       sens_write,
+       cat_write,
+};
+
+static int ocontext_write(struct policydb *p, struct policydb_compat_info *info,
+                         void *fp)
+{
+       unsigned int i, j, rc;
+       size_t nel, len;
+       __le32 buf[3];
+       u32 nodebuf[8];
+       struct ocontext *c;
+       for (i = 0; i < info->ocon_num; i++) {
+               nel = 0;
+               for (c = p->ocontexts[i]; c; c = c->next)
+                       nel++;
+               buf[0] = cpu_to_le32(nel);
+               rc = put_entry(buf, sizeof(u32), 1, fp);
+               if (rc)
+                       return rc;
+               for (c = p->ocontexts[i]; c; c = c->next) {
+                       switch (i) {
+                       case OCON_ISID:
+                               buf[0] = cpu_to_le32(c->sid[0]);
+                               rc = put_entry(buf, sizeof(u32), 1, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       case OCON_FS:
+                       case OCON_NETIF:
+                               len = strlen(c->u.name);
+                               buf[0] = cpu_to_le32(len);
+                               rc = put_entry(buf, sizeof(u32), 1, fp);
+                               if (rc)
+                                       return rc;
+                               rc = put_entry(c->u.name, 1, len, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[1], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       case OCON_PORT:
+                               buf[0] = cpu_to_le32(c->u.port.protocol);
+                               buf[1] = cpu_to_le32(c->u.port.low_port);
+                               buf[2] = cpu_to_le32(c->u.port.high_port);
+                               rc = put_entry(buf, sizeof(u32), 3, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       case OCON_NODE:
+                               nodebuf[0] = c->u.node.addr; /* network order */
+                               nodebuf[1] = c->u.node.mask; /* network order */
+                               rc = put_entry(nodebuf, sizeof(u32), 2, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       case OCON_FSUSE:
+                               buf[0] = cpu_to_le32(c->v.behavior);
+                               len = strlen(c->u.name);
+                               buf[1] = cpu_to_le32(len);
+                               rc = put_entry(buf, sizeof(u32), 2, fp);
+                               if (rc)
+                                       return rc;
+                               rc = put_entry(c->u.name, 1, len, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       case OCON_NODE6:
+                               for (j = 0; j < 4; j++)
+                                       nodebuf[j] = c->u.node6.addr[j]; /* network order */
+                               for (j = 0; j < 4; j++)
+                                       nodebuf[j + 4] = c->u.node6.mask[j]; /* network order */
+                               rc = put_entry(nodebuf, sizeof(u32), 8, fp);
+                               if (rc)
+                                       return rc;
+                               rc = context_write(p, &c->context[0], fp);
+                               if (rc)
+                                       return rc;
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int genfs_write(struct policydb *p, void *fp)
+{
+       struct genfs *genfs;
+       struct ocontext *c;
+       size_t len;
+       __le32 buf[1];
+       int rc;
+
+       len = 0;
+       for (genfs = p->genfs; genfs; genfs = genfs->next)
+               len++;
+       buf[0] = cpu_to_le32(len);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+       for (genfs = p->genfs; genfs; genfs = genfs->next) {
+               len = strlen(genfs->fstype);
+               buf[0] = cpu_to_le32(len);
+               rc = put_entry(buf, sizeof(u32), 1, fp);
+               if (rc)
+                       return rc;
+               rc = put_entry(genfs->fstype, 1, len, fp);
+               if (rc)
+                       return rc;
+               len = 0;
+               for (c = genfs->head; c; c = c->next)
+                       len++;
+               buf[0] = cpu_to_le32(len);
+               rc = put_entry(buf, sizeof(u32), 1, fp);
+               if (rc)
+                       return rc;
+               for (c = genfs->head; c; c = c->next) {
+                       len = strlen(c->u.name);
+                       buf[0] = cpu_to_le32(len);
+                       rc = put_entry(buf, sizeof(u32), 1, fp);
+                       if (rc)
+                               return rc;
+                       rc = put_entry(c->u.name, 1, len, fp);
+                       if (rc)
+                               return rc;
+                       buf[0] = cpu_to_le32(c->v.sclass);
+                       rc = put_entry(buf, sizeof(u32), 1, fp);
+                       if (rc)
+                               return rc;
+                       rc = context_write(p, &c->context[0], fp);
+                       if (rc)
+                               return rc;
+               }
+       }
+       return 0;
+}
+
+static int range_count(void *key, void *data, void *ptr)
+{
+       int *cnt = ptr;
+       *cnt = *cnt + 1;
+
+       return 0;
+}
+
+static int range_write_helper(void *key, void *data, void *ptr)
+{
+       __le32 buf[2];
+       struct range_trans *rt = key;
+       struct mls_range *r = data;
+       struct policy_data *pd = ptr;
+       void *fp = pd->fp;
+       struct policydb *p = pd->p;
+       int rc;
+
+       buf[0] = cpu_to_le32(rt->source_type);
+       buf[1] = cpu_to_le32(rt->target_type);
+       rc = put_entry(buf, sizeof(u32), 2, fp);
+       if (rc)
+               return rc;
+       if (p->policyvers >= POLICYDB_VERSION_RANGETRANS) {
+               buf[0] = cpu_to_le32(rt->target_class);
+               rc = put_entry(buf, sizeof(u32), 1, fp);
+               if (rc)
+                       return rc;
+       }
+       rc = mls_write_range_helper(r, fp);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+static int range_write(struct policydb *p, void *fp)
+{
+       size_t nel;
+       __le32 buf[1];
+       int rc;
+       struct policy_data pd;
+
+       pd.p = p;
+       pd.fp = fp;
+
+       /* count the number of entries in the hashtab */
+       nel = 0;
+       rc = hashtab_map(p->range_tr, range_count, &nel);
+       if (rc)
+               return rc;
+
+       buf[0] = cpu_to_le32(nel);
+       rc = put_entry(buf, sizeof(u32), 1, fp);
+       if (rc)
+               return rc;
+
+       /* actually write all of the entries */
+       rc = hashtab_map(p->range_tr, range_write_helper, &pd);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+/*
+ * Write the configuration data in a policy database
+ * structure to a policy database binary representation
+ * file.
+ */
+int policydb_write(struct policydb *p, void *fp)
+{
+       unsigned int i, num_syms;
+       int rc;
+       __le32 buf[4];
+       u32 config;
+       size_t len;
+       struct policydb_compat_info *info;
+
+       /*
+        * refuse to write policy older than compressed avtab
+        * to simplify the writer.  There are other tests dropped
+        * since we assume this throughout the writer code.  Be
+        * careful if you ever try to remove this restriction
+        */
+       if (p->policyvers < POLICYDB_VERSION_AVTAB) {
+               printk(KERN_ERR "SELinux: refusing to write policy version %d."
+                      "  Because it is less than version %d\n", p->policyvers,
+                      POLICYDB_VERSION_AVTAB);
+               return -EINVAL;
+       }
+
+       config = 0;
+       if (p->mls_enabled)
+               config |= POLICYDB_CONFIG_MLS;
+
+       if (p->reject_unknown)
+               config |= REJECT_UNKNOWN;
+       if (p->allow_unknown)
+               config |= ALLOW_UNKNOWN;
+
+       /* Write the magic number and string identifiers. */
+       buf[0] = cpu_to_le32(POLICYDB_MAGIC);
+       len = strlen(POLICYDB_STRING);
+       buf[1] = cpu_to_le32(len);
+       rc = put_entry(buf, sizeof(u32), 2, fp);
+       if (rc)
+               return rc;
+       rc = put_entry(POLICYDB_STRING, 1, len, fp);
+       if (rc)
+               return rc;
+
+       /* Write the version, config, and table sizes. */
+       info = policydb_lookup_compat(p->policyvers);
+       if (!info) {
+               printk(KERN_ERR "SELinux: compatibility lookup failed for policy "
+                   "version %d", p->policyvers);
+               return rc;
+       }
+
+       buf[0] = cpu_to_le32(p->policyvers);
+       buf[1] = cpu_to_le32(config);
+       buf[2] = cpu_to_le32(info->sym_num);
+       buf[3] = cpu_to_le32(info->ocon_num);
+
+       rc = put_entry(buf, sizeof(u32), 4, fp);
+       if (rc)
+               return rc;
+
+       if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
+               rc = ebitmap_write(&p->policycaps, fp);
+               if (rc)
+                       return rc;
+       }
+
+       if (p->policyvers >= POLICYDB_VERSION_PERMISSIVE) {
+               rc = ebitmap_write(&p->permissive_map, fp);
+               if (rc)
+                       return rc;
+       }
+
+       num_syms = info->sym_num;
+       for (i = 0; i < num_syms; i++) {
+               struct policy_data pd;
+
+               pd.fp = fp;
+               pd.p = p;
+
+               buf[0] = cpu_to_le32(p->symtab[i].nprim);
+               buf[1] = cpu_to_le32(p->symtab[i].table->nel);
+
+               rc = put_entry(buf, sizeof(u32), 2, fp);
+               if (rc)
+                       return rc;
+               rc = hashtab_map(p->symtab[i].table, write_f[i], &pd);
+               if (rc)
+                       return rc;
+       }
+
+       rc = avtab_write(p, &p->te_avtab, fp);
+       if (rc)
+               return rc;
+
+       rc = cond_write_list(p, p->cond_list, fp);
+       if (rc)
+               return rc;
+
+       rc = role_trans_write(p->role_tr, fp);
+       if (rc)
+               return rc;
+
+       rc = role_allow_write(p->role_allow, fp);
+       if (rc)
+               return rc;
+
+       rc = ocontext_write(p, info, fp);
+       if (rc)
+               return rc;
+
+       rc = genfs_write(p, fp);
+       if (rc)
+               return rc;
+
+       rc = range_write(p, fp);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < p->p_types.nprim; i++) {
+               struct ebitmap *e = flex_array_get(p->type_attr_map_array, i);
+
+               BUG_ON(!e);
+               rc = ebitmap_write(e, fp);
+               if (rc)
+                       return rc;
+       }
+
+       return 0;
+}
index 310e94442cb8b3535a8774b952de45ba0180794e..95d3d7de361e628adcc53b974533cafb384ef851 100644 (file)
@@ -254,6 +254,9 @@ struct policydb {
 
        struct ebitmap permissive_map;
 
+       /* length of this policy when it was loaded */
+       size_t len;
+
        unsigned int policyvers;
 
        unsigned int reject_unknown : 1;
@@ -270,6 +273,7 @@ extern int policydb_class_isvalid(struct policydb *p, unsigned int class);
 extern int policydb_type_isvalid(struct policydb *p, unsigned int type);
 extern int policydb_role_isvalid(struct policydb *p, unsigned int role);
 extern int policydb_read(struct policydb *p, void *fp);
+extern int policydb_write(struct policydb *p, void *fp);
 
 #define PERM_SYMTAB_SIZE 32
 
@@ -290,6 +294,11 @@ struct policy_file {
        size_t len;
 };
 
+struct policy_data {
+       struct policydb *p;
+       void *fp;
+};
+
 static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
 {
        if (bytes > fp->len)
@@ -301,6 +310,17 @@ static inline int next_entry(void *buf, struct policy_file *fp, size_t bytes)
        return 0;
 }
 
+static inline int put_entry(void *buf, size_t bytes, int num, struct policy_file *fp)
+{
+       size_t len = bytes * num;
+
+       memcpy(fp->data, buf, len);
+       fp->data += len;
+       fp->len -= len;
+
+       return 0;
+}
+
 extern u16 string_to_security_class(struct policydb *p, const char *name);
 extern u32 string_to_av_perm(struct policydb *p, u16 tclass, const char *name);
 
index 9ea2feca3cd4f7b572361543fdf1b265002cecfb..223c1ff6ef2324488eca915d2ba87bc4f6e27fa9 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/mutex.h>
 #include <linux/selinux.h>
 #include <linux/flex_array.h>
+#include <linux/vmalloc.h>
 #include <net/netlabel.h>
 
 #include "flask.h"
@@ -991,7 +992,8 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
 {
        char *scontextp;
 
-       *scontext = NULL;
+       if (scontext)
+               *scontext = NULL;
        *scontext_len = 0;
 
        if (context->len) {
@@ -1008,6 +1010,9 @@ static int context_struct_to_string(struct context *context, char **scontext, u3
        *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
        *scontext_len += mls_compute_context_len(context);
 
+       if (!scontext)
+               return 0;
+
        /* Allocate space for the context; caller must free this space. */
        scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
        if (!scontextp)
@@ -1047,7 +1052,8 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
        struct context *context;
        int rc = 0;
 
-       *scontext = NULL;
+       if (scontext)
+               *scontext = NULL;
        *scontext_len  = 0;
 
        if (!ss_initialized) {
@@ -1055,6 +1061,8 @@ static int security_sid_to_context_core(u32 sid, char **scontext,
                        char *scontextp;
 
                        *scontext_len = strlen(initial_sid_to_string[sid]) + 1;
+                       if (!scontext)
+                               goto out;
                        scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
                        if (!scontextp) {
                                rc = -ENOMEM;
@@ -1769,6 +1777,7 @@ int security_load_policy(void *data, size_t len)
                        return rc;
                }
 
+               policydb.len = len;
                rc = selinux_set_mapping(&policydb, secclass_map,
                                         &current_mapping,
                                         &current_mapping_size);
@@ -1791,6 +1800,7 @@ int security_load_policy(void *data, size_t len)
                selinux_complete_init();
                avc_ss_reset(seqno);
                selnl_notify_policyload(seqno);
+               selinux_status_update_policyload(seqno);
                selinux_netlbl_cache_invalidate();
                selinux_xfrm_notify_policyload();
                return 0;
@@ -1804,6 +1814,7 @@ int security_load_policy(void *data, size_t len)
        if (rc)
                return rc;
 
+       newpolicydb.len = len;
        /* If switching between different policy types, log MLS status */
        if (policydb.mls_enabled && !newpolicydb.mls_enabled)
                printk(KERN_INFO "SELinux: Disabling MLS support...\n");
@@ -1870,6 +1881,7 @@ int security_load_policy(void *data, size_t len)
 
        avc_ss_reset(seqno);
        selnl_notify_policyload(seqno);
+       selinux_status_update_policyload(seqno);
        selinux_netlbl_cache_invalidate();
        selinux_xfrm_notify_policyload();
 
@@ -1883,6 +1895,17 @@ err:
 
 }
 
+size_t security_policydb_len(void)
+{
+       size_t len;
+
+       read_lock(&policy_rwlock);
+       len = policydb.len;
+       read_unlock(&policy_rwlock);
+
+       return len;
+}
+
 /**
  * security_port_sid - Obtain the SID for a port.
  * @protocol: protocol number
@@ -2374,6 +2397,7 @@ out:
        if (!rc) {
                avc_ss_reset(seqno);
                selnl_notify_policyload(seqno);
+               selinux_status_update_policyload(seqno);
                selinux_xfrm_notify_policyload();
        }
        return rc;
@@ -3129,3 +3153,38 @@ netlbl_sid_to_secattr_failure:
        return rc;
 }
 #endif /* CONFIG_NETLABEL */
+
+/**
+ * security_read_policy - read the policy.
+ * @data: binary policy data
+ * @len: length of data in bytes
+ *
+ */
+int security_read_policy(void **data, ssize_t *len)
+{
+       int rc;
+       struct policy_file fp;
+
+       if (!ss_initialized)
+               return -EINVAL;
+
+       *len = security_policydb_len();
+
+       *data = vmalloc_user(*len);
+       if (!*data)
+               return -ENOMEM;
+
+       fp.data = *data;
+       fp.len = *len;
+
+       read_lock(&policy_rwlock);
+       rc = policydb_write(&policydb, &fp);
+       read_unlock(&policy_rwlock);
+
+       if (rc)
+               return rc;
+
+       *len = (unsigned long)fp.data - (unsigned long)*data;
+       return 0;
+
+}
diff --git a/security/selinux/ss/status.c b/security/selinux/ss/status.c
new file mode 100644 (file)
index 0000000..d982365
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * mmap based event notifications for SELinux
+ *
+ * Author: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ * Copyright (C) 2010 NEC 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.
+ */
+#include <linux/kernel.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include "avc.h"
+#include "services.h"
+
+/*
+ * The selinux_status_page shall be exposed to userspace applications
+ * using mmap interface on /selinux/status.
+ * It enables to notify applications a few events that will cause reset
+ * of userspace access vector without context switching.
+ *
+ * The selinux_kernel_status structure on the head of status page is
+ * protected from concurrent accesses using seqlock logic, so userspace
+ * application should reference the status page according to the seqlock
+ * logic.
+ *
+ * Typically, application checks status->sequence at the head of access
+ * control routine. If it is odd-number, kernel is updating the status,
+ * so please wait for a moment. If it is changed from the last sequence
+ * number, it means something happen, so application will reset userspace
+ * avc, if needed.
+ * In most cases, application shall confirm the kernel status is not
+ * changed without any system call invocations.
+ */
+static struct page *selinux_status_page;
+static DEFINE_MUTEX(selinux_status_lock);
+
+/*
+ * selinux_kernel_status_page
+ *
+ * It returns a reference to selinux_status_page. If the status page is
+ * not allocated yet, it also tries to allocate it at the first time.
+ */
+struct page *selinux_kernel_status_page(void)
+{
+       struct selinux_kernel_status   *status;
+       struct page                    *result = NULL;
+
+       mutex_lock(&selinux_status_lock);
+       if (!selinux_status_page) {
+               selinux_status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
+
+               if (selinux_status_page) {
+                       status = page_address(selinux_status_page);
+
+                       status->version = SELINUX_KERNEL_STATUS_VERSION;
+                       status->sequence = 0;
+                       status->enforcing = selinux_enforcing;
+                       /*
+                        * NOTE: the next policyload event shall set
+                        * a positive value on the status->policyload,
+                        * although it may not be 1, but never zero.
+                        * So, application can know it was updated.
+                        */
+                       status->policyload = 0;
+                       status->deny_unknown = !security_get_allow_unknown();
+               }
+       }
+       result = selinux_status_page;
+       mutex_unlock(&selinux_status_lock);
+
+       return result;
+}
+
+/*
+ * selinux_status_update_setenforce
+ *
+ * It updates status of the current enforcing/permissive mode.
+ */
+void selinux_status_update_setenforce(int enforcing)
+{
+       struct selinux_kernel_status   *status;
+
+       mutex_lock(&selinux_status_lock);
+       if (selinux_status_page) {
+               status = page_address(selinux_status_page);
+
+               status->sequence++;
+               smp_wmb();
+
+               status->enforcing = enforcing;
+
+               smp_wmb();
+               status->sequence++;
+       }
+       mutex_unlock(&selinux_status_lock);
+}
+
+/*
+ * selinux_status_update_policyload
+ *
+ * It updates status of the times of policy reloaded, and current
+ * setting of deny_unknown.
+ */
+void selinux_status_update_policyload(int seqno)
+{
+       struct selinux_kernel_status   *status;
+
+       mutex_lock(&selinux_status_lock);
+       if (selinux_status_page) {
+               status = page_address(selinux_status_page);
+
+               status->sequence++;
+               smp_wmb();
+
+               status->policyload = seqno;
+               status->deny_unknown = !security_get_allow_unknown();
+
+               smp_wmb();
+               status->sequence++;
+       }
+       mutex_unlock(&selinux_status_lock);
+}
index c448d57ae2b7721f72f17c5cf42e88f3f1bcba5e..bc39f4067af668874312af4187ad6f21dbdbb113 100644 (file)
@@ -1281,12 +1281,11 @@ static int smack_task_getioprio(struct task_struct *p)
  *
  * Return 0 if read access is permitted
  */
-static int smack_task_setscheduler(struct task_struct *p, int policy,
-                                  struct sched_param *lp)
+static int smack_task_setscheduler(struct task_struct *p)
 {
        int rc;
 
-       rc = cap_task_setscheduler(p, policy, lp);
+       rc = cap_task_setscheduler(p);
        if (rc == 0)
                rc = smk_curacc_on_task(p, MAY_WRITE);
        return rc;
@@ -3005,7 +3004,8 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
 {
        char *sp = smack_from_secid(secid);
 
-       *secdata = sp;
+       if (secdata)
+               *secdata = sp;
        *seclen = strlen(sp);
        return 0;
 }
index c668b447c72594494417f6be50795f3b49f860bf..7556315c197823e0baedcf15d0f0930c74345429 100644 (file)
@@ -768,8 +768,10 @@ static bool tomoyo_select_one(struct tomoyo_io_buffer *head, const char *data)
                return true; /* Do nothing if open(O_WRONLY). */
        memset(&head->r, 0, sizeof(head->r));
        head->r.print_this_domain_only = true;
-       head->r.eof = !domain;
-       head->r.domain = &domain->list;
+       if (domain)
+               head->r.domain = &domain->list;
+       else
+               head->r.eof = 1;
        tomoyo_io_printf(head, "# select %s\n", data);
        if (domain && domain->is_deleted)
                tomoyo_io_printf(head, "# This is a deleted domain.\n");
@@ -2051,13 +2053,22 @@ void tomoyo_check_profile(void)
                const u8 profile = domain->profile;
                if (tomoyo_profile_ptr[profile])
                        continue;
+               printk(KERN_ERR "You need to define profile %u before using it.\n",
+                      profile);
+               printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ "
+                      "for more information.\n");
                panic("Profile %u (used by '%s') not defined.\n",
                      profile, domain->domainname->name);
        }
        tomoyo_read_unlock(idx);
-       if (tomoyo_profile_version != 20090903)
+       if (tomoyo_profile_version != 20090903) {
+               printk(KERN_ERR "You need to install userland programs for "
+                      "TOMOYO 2.3 and initialize policy configuration.\n");
+               printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.3/ "
+                      "for more information.\n");
                panic("Profile version %u is not supported.\n",
                      tomoyo_profile_version);
+       }
        printk(KERN_INFO "TOMOYO: 2.3.0\n");
        printk(KERN_INFO "Mandatory Access Control activated.\n");
 }
index 7ab9174a8a841b4a924474deb3c238a003180188..8cc4733698a0f02d7de84de2cf4aec3b8c683584 100644 (file)
@@ -142,10 +142,9 @@ static int snd_pdacf_probe(struct pcmcia_device *link)
        link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
        link->resource[0]->end = 16;
 
-       link->conf.Attributes = CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-       link->conf.ConfigIndex = 1;
-       link->conf.Present = PRESENT_OPTION;
+       link->config_flags = CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
+       link->config_index = 1;
+       link->config_regs = PRESENT_OPTION;
 
        return pdacf_config(link);
 }
@@ -217,7 +216,8 @@ static int pdacf_config(struct pcmcia_device *link)
        int ret;
 
        snd_printdd(KERN_DEBUG "pdacf_config called\n");
-       link->conf.ConfigIndex = 0x5;
+       link->config_index = 0x5;
+       link->config_flags |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ;
 
        ret = pcmcia_request_io(link);
        if (ret)
@@ -227,7 +227,7 @@ static int pdacf_config(struct pcmcia_device *link)
        if (ret)
                goto failed;
 
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
@@ -287,9 +287,7 @@ MODULE_DEVICE_TABLE(pcmcia, snd_pdacf_ids);
 
 static struct pcmcia_driver pdacf_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "snd-pdaudiocf",
-       },
+       .name           = "snd-pdaudiocf",
        .probe          = snd_pdacf_probe,
        .remove         = snd_pdacf_detach,
        .id_table       = snd_pdacf_ids,
index 5cc3e45730747fc62e505e965b3bfe7d4d2054eb..bd26e092aead47c7f1385017973145b326cf6ffd 100644 (file)
@@ -24,7 +24,6 @@
 #include <sound/pcm.h>
 #include <asm/io.h>
 #include <linux/interrupt.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
index a6edfc3be29a59b018d6b268f9a01255b08451db..80000d631f88366deeeaae70588dec5d3c960830 100644 (file)
@@ -2,7 +2,7 @@
  * Driver for Digigram VXpocket V2/440 soundcards
  *
  * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.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
@@ -162,10 +162,9 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl,
        link->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
        link->resource[0]->end = 16;
 
-       link->conf.Attributes = CONF_ENABLE_IRQ;
-       link->conf.IntType = INT_MEMORY_AND_IO;
-       link->conf.ConfigIndex = 1;
-       link->conf.Present = PRESENT_OPTION;
+       link->config_flags |= CONF_ENABLE_IRQ;
+       link->config_index = 1;
+       link->config_regs = PRESENT_OPTION;
 
        *chip_ret = vxp;
        return 0;
@@ -234,7 +233,7 @@ static int vxpocket_config(struct pcmcia_device *link)
        if (ret)
                goto failed;
 
-       ret = pcmcia_request_configuration(link, &link->conf);
+       ret = pcmcia_enable_device(link);
        if (ret)
                goto failed;
 
@@ -359,9 +358,7 @@ MODULE_DEVICE_TABLE(pcmcia, vxp_ids);
 
 static struct pcmcia_driver vxp_cs_driver = {
        .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "snd-vxpocket",
-       },
+       .name           = "snd-vxpocket",
        .probe          = vxpocket_probe,
        .remove         = vxpocket_detach,
        .id_table       = vxp_ids,
index d9110669d0425cd6f4bc652073335bacac6ab8b1..13d658c1a2167b9b62f3ebedf1249f2f7405a2f8 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <sound/vx_core.h>
 
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 
index 5164a655c39f60b578c8642f2caabe8af66fa016..b2c63309a65165b471822e99268c828bbdb07777 100644 (file)
@@ -8,7 +8,7 @@ perf-annotate - Read perf.data (created by perf record) and display annotated co
 SYNOPSIS
 --------
 [verse]
-'perf annotate' [-i <file> | --input=file] symbol_name
+'perf annotate' [-i <file> | --input=file] [symbol_name]
 
 DESCRIPTION
 -----------
@@ -24,6 +24,13 @@ OPTIONS
 --input=::
         Input file name. (default: perf.data)
 
+--stdio:: Use the stdio interface.
+
+--tui:: Use the TUI interface Use of --tui requires a tty, if one is not
+       present, as when piping to other commands, the stdio interface is
+       used. This interfaces starts by centering on the line with more
+       samples, TAB/UNTAB cycles thru the lines with more samples.
+
 SEE ALSO
 --------
-linkperf:perf-record[1]
+linkperf:perf-record[1], linkperf:perf-report[1]
index 43e3dd284b90f73bc76d28e6fa738ff295482f41..399751befeed923eec1ed9e3d937d755f776a559 100644 (file)
@@ -15,6 +15,23 @@ DESCRIPTION
 This command displays the symbolic event types which can be selected in the
 various perf commands with the -e option.
 
+EVENT MODIFIERS
+---------------
+
+Events can optionally have a modifer by appending a colon and one or
+more modifiers.  Modifiers allow the user to restrict when events are
+counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor.
+
+The 'p' modifier can be used for specifying how precise the instruction
+address should be. The 'p' modifier is currently only implemented for
+Intel PEBS and can be specified multiple times:
+  0 - SAMPLE_IP can have arbitrary skid
+  1 - SAMPLE_IP must have constant skid
+  2 - SAMPLE_IP requested to have 0 skid
+  3 - SAMPLE_IP must have 0 skid
+
+The PEBS implementation now supports up to 2.
+
 RAW HARDWARE EVENT DESCRIPTOR
 -----------------------------
 Even when an event is not available in a symbolic form within perf right now,
index 27d52dae5a43aa842234ba6d6596ca7ce89e9e1e..62de1b7f4e760367337042c52760e7a49ded50c7 100644 (file)
@@ -16,7 +16,9 @@ or
 or
 'perf probe' --list
 or
-'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
+'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
+or
+'perf probe' [options] --vars='PROBEPOINT'
 
 DESCRIPTION
 -----------
@@ -31,6 +33,11 @@ OPTIONS
 --vmlinux=PATH::
        Specify vmlinux path which has debuginfo (Dwarf binary).
 
+-m::
+--module=MODNAME::
+       Specify module name in which perf-probe searches probe points
+       or lines.
+
 -s::
 --source=PATH::
        Specify path to kernel source.
@@ -57,6 +64,15 @@ OPTIONS
        Show source code lines which can be probed. This needs an argument
        which specifies a range of the source code. (see LINE SYNTAX for detail)
 
+-V::
+--vars=::
+       Show available local variables at given probe point. The argument
+       syntax is same as PROBE SYNTAX, but NO ARGs.
+
+--externs::
+       (Only for --vars) Show external defined variables in addition to local
+       variables.
+
 -f::
 --force::
        Forcibly add events with existing name.
index abfabe9147a4f2a48b6fd47bfdb758de2a3f3eea..12052c9ed0babfc3a1c93cc01758ec3b7747ee10 100644 (file)
@@ -65,6 +65,13 @@ OPTIONS
                 the tree is considered as a new profiled object. +
        Default: fractal,0.5.
 
+--stdio:: Use the stdio interface.
+
+--tui:: Use the TUI interface, that is integrated with annotate and allows
+        zooming into DSOs or threads, among other features. Use of --tui
+       requires a tty, if one is not present, as when piping to other
+       commands, the stdio interface is used.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1]
index 1950e19af1cf6b23be56f0250bcf8cbb52b3d9f3..d1db0f676a4bf14850fa0264e78fe3d482d376dc 100644 (file)
@@ -313,6 +313,9 @@ TEST_PROGRAMS =
 
 SCRIPT_SH += perf-archive.sh
 
+grep-libs = $(filter -l%,$(1))
+strip-libs = $(filter-out -l%,$(1))
+
 #
 # No Perl scripts right now:
 #
@@ -588,14 +591,17 @@ endif
 ifdef NO_LIBPERL
        BASIC_CFLAGS += -DNO_LIBPERL
 else
-       PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
+       PERL_EMBED_LDOPTS = $(shell perl -MExtUtils::Embed -e ldopts 2>/dev/null)
+       PERL_EMBED_LDFLAGS = $(call strip-libs,$(PERL_EMBED_LDOPTS))
+       PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
        PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
        FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 
        ifneq ($(call try-cc,$(SOURCE_PERL_EMBED),$(FLAGS_PERL_EMBED)),y)
                BASIC_CFLAGS += -DNO_LIBPERL
        else
-               ALL_LDFLAGS += $(PERL_EMBED_LDOPTS)
+               ALL_LDFLAGS += $(PERL_EMBED_LDFLAGS)
+               EXTLIBS += $(PERL_EMBED_LIBADD)
                LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-perl.o
                LIB_OBJS += $(OUTPUT)scripts/perl/Perf-Trace-Util/Context.o
        endif
@@ -604,13 +610,16 @@ endif
 ifdef NO_LIBPYTHON
        BASIC_CFLAGS += -DNO_LIBPYTHON
 else
-       PYTHON_EMBED_LDOPTS = `python-config --ldflags 2>/dev/null`
+       PYTHON_EMBED_LDOPTS = $(shell python-config --ldflags 2>/dev/null)
+       PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
+       PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
        PYTHON_EMBED_CCOPTS = `python-config --cflags 2>/dev/null`
        FLAGS_PYTHON_EMBED=$(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
        ifneq ($(call try-cc,$(SOURCE_PYTHON_EMBED),$(FLAGS_PYTHON_EMBED)),y)
                BASIC_CFLAGS += -DNO_LIBPYTHON
        else
-               ALL_LDFLAGS += $(PYTHON_EMBED_LDOPTS)
+               ALL_LDFLAGS += $(PYTHON_EMBED_LDFLAGS)
+               EXTLIBS += $(PYTHON_EMBED_LIBADD)
                LIB_OBJS += $(OUTPUT)util/scripting-engines/trace-event-python.o
                LIB_OBJS += $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o
        endif
@@ -653,6 +662,15 @@ else
        endif
 endif
 
+
+ifdef NO_STRLCPY
+       BASIC_CFLAGS += -DNO_STRLCPY
+else
+       ifneq ($(call try-cc,$(SOURCE_STRLCPY),),y)
+               BASIC_CFLAGS += -DNO_STRLCPY
+       endif
+endif
+
 ifndef CC_LD_DYNPATH
        ifdef NO_R_TO_GCC_LINKER
                # Some gcc does not accept and pass -R to the linker to specify
@@ -910,8 +928,8 @@ $(OUTPUT)perf.o: perf.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
                $(ALL_CFLAGS) -c $(filter %.c,$^) -o $@
 
 $(OUTPUT)perf$X: $(OUTPUT)perf.o $(BUILTIN_OBJS) $(PERFLIBS)
-       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(OUTPUT)perf.o \
-               $(BUILTIN_OBJS) $(ALL_LDFLAGS) $(LIBS)
+       $(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) $(OUTPUT)perf.o \
+               $(BUILTIN_OBJS) $(LIBS) -o $@
 
 $(OUTPUT)builtin-help.o: builtin-help.c $(OUTPUT)common-cmds.h $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) \
index 1478dc64bf157fc0f226cba51eef80ec8646c15f..6d5604d8df9599acb55d87017f5d58e19d906395 100644 (file)
@@ -28,7 +28,7 @@
 
 static char            const *input_name = "perf.data";
 
-static bool            force;
+static bool            force, use_tui, use_stdio;
 
 static bool            full_paths;
 
@@ -321,7 +321,7 @@ static int hist_entry__tty_annotate(struct hist_entry *he)
 
 static void hists__find_annotations(struct hists *self)
 {
-       struct rb_node *first = rb_first(&self->entries), *nd = first;
+       struct rb_node *nd = rb_first(&self->entries), *next;
        int key = KEY_RIGHT;
 
        while (nd) {
@@ -343,20 +343,19 @@ find_next:
 
                if (use_browser > 0) {
                        key = hist_entry__tui_annotate(he);
-                       if (is_exit_key(key))
-                               break;
                        switch (key) {
                        case KEY_RIGHT:
-                       case '\t':
-                               nd = rb_next(nd);
+                               next = rb_next(nd);
                                break;
                        case KEY_LEFT:
-                               if (nd == first)
-                                       continue;
-                               nd = rb_prev(nd);
-                       default:
+                               next = rb_prev(nd);
                                break;
+                       default:
+                               return;
                        }
+
+                       if (next != NULL)
+                               nd = next;
                } else {
                        hist_entry__tty_annotate(he);
                        nd = rb_next(nd);
@@ -428,6 +427,8 @@ static const struct option options[] = {
                    "be more verbose (show symbol address, etc)"),
        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
                    "dump raw trace in ASCII"),
+       OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
+       OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
                   "file", "vmlinux pathname"),
        OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
@@ -443,6 +444,11 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
 {
        argc = parse_options(argc, argv, options, annotate_usage, 0);
 
+       if (use_stdio)
+               use_browser = 0;
+       else if (use_tui)
+               use_browser = 1;
+
        setup_browser();
 
        symbol_conf.priv_size = sizeof(struct sym_priv);
index 199d5e19554f62fcfc3d6c960c115edb6f7c0535..2e000c068cc5a377d87923bb302a383abafd3a33 100644 (file)
@@ -50,14 +50,17 @@ static struct {
        bool list_events;
        bool force_add;
        bool show_lines;
+       bool show_vars;
+       bool show_ext_vars;
+       bool mod_events;
        int nevents;
        struct perf_probe_event events[MAX_PROBES];
        struct strlist *dellist;
        struct line_range line_range;
+       const char *target_module;
        int max_probe_points;
 } params;
 
-
 /* Parse an event definition. Note that any error must die. */
 static int parse_probe_event(const char *str)
 {
@@ -92,6 +95,7 @@ static int parse_probe_event_argv(int argc, const char **argv)
        len = 0;
        for (i = 0; i < argc; i++)
                len += sprintf(&buf[len], "%s ", argv[i]);
+       params.mod_events = true;
        ret = parse_probe_event(buf);
        free(buf);
        return ret;
@@ -100,9 +104,10 @@ static int parse_probe_event_argv(int argc, const char **argv)
 static int opt_add_probe_event(const struct option *opt __used,
                              const char *str, int unset __used)
 {
-       if (str)
+       if (str) {
+               params.mod_events = true;
                return parse_probe_event(str);
-       else
+       else
                return 0;
 }
 
@@ -110,6 +115,7 @@ static int opt_del_probe_event(const struct option *opt __used,
                               const char *str, int unset __used)
 {
        if (str) {
+               params.mod_events = true;
                if (!params.dellist)
                        params.dellist = strlist__new(true, NULL);
                strlist__add(params.dellist, str);
@@ -130,6 +136,25 @@ static int opt_show_lines(const struct option *opt __used,
 
        return ret;
 }
+
+static int opt_show_vars(const struct option *opt __used,
+                        const char *str, int unset __used)
+{
+       struct perf_probe_event *pev = &params.events[params.nevents];
+       int ret;
+
+       if (!str)
+               return 0;
+
+       ret = parse_probe_event(str);
+       if (!ret && pev->nargs != 0) {
+               pr_err("  Error: '--vars' doesn't accept arguments.\n");
+               return -EINVAL;
+       }
+       params.show_vars = true;
+
+       return ret;
+}
 #endif
 
 static const char * const probe_usage[] = {
@@ -138,7 +163,8 @@ static const char * const probe_usage[] = {
        "perf probe [<options>] --del '[GROUP:]EVENT' ...",
        "perf probe --list",
 #ifdef DWARF_SUPPORT
-       "perf probe --line 'LINEDESC'",
+       "perf probe [<options>] --line 'LINEDESC'",
+       "perf probe [<options>] --vars 'PROBEPOINT'",
 #endif
        NULL
 };
@@ -180,10 +206,17 @@ static const struct option options[] = {
        OPT_CALLBACK('L', "line", NULL,
                     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
                     "Show source code lines.", opt_show_lines),
+       OPT_CALLBACK('V', "vars", NULL,
+                    "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
+                    "Show accessible variables on PROBEDEF", opt_show_vars),
+       OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
+                   "Show external variables too (with --vars only)"),
        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
                   "file", "vmlinux pathname"),
        OPT_STRING('s', "source", &symbol_conf.source_prefix,
                   "directory", "path to kernel source"),
+       OPT_STRING('m', "module", &params.target_module,
+                  "modname", "target module name"),
 #endif
        OPT__DRY_RUN(&probe_event_dry_run),
        OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
@@ -217,7 +250,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
                usage_with_options(probe_usage, options);
 
        if (params.list_events) {
-               if (params.nevents != 0 || params.dellist) {
+               if (params.mod_events) {
                        pr_err("  Error: Don't use --list with --add/--del.\n");
                        usage_with_options(probe_usage, options);
                }
@@ -225,6 +258,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
                        pr_err("  Error: Don't use --list with --line.\n");
                        usage_with_options(probe_usage, options);
                }
+               if (params.show_vars) {
+                       pr_err(" Error: Don't use --list with --vars.\n");
+                       usage_with_options(probe_usage, options);
+               }
                ret = show_perf_probe_events();
                if (ret < 0)
                        pr_err("  Error: Failed to show event list. (%d)\n",
@@ -234,17 +271,35 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 
 #ifdef DWARF_SUPPORT
        if (params.show_lines) {
-               if (params.nevents != 0 || params.dellist) {
-                       pr_warning("  Error: Don't use --line with"
-                                  " --add/--del.\n");
+               if (params.mod_events) {
+                       pr_err("  Error: Don't use --line with"
+                              " --add/--del.\n");
+                       usage_with_options(probe_usage, options);
+               }
+               if (params.show_vars) {
+                       pr_err(" Error: Don't use --line with --vars.\n");
                        usage_with_options(probe_usage, options);
                }
 
-               ret = show_line_range(&params.line_range);
+               ret = show_line_range(&params.line_range, params.target_module);
                if (ret < 0)
                        pr_err("  Error: Failed to show lines. (%d)\n", ret);
                return ret;
        }
+       if (params.show_vars) {
+               if (params.mod_events) {
+                       pr_err("  Error: Don't use --vars with"
+                              " --add/--del.\n");
+                       usage_with_options(probe_usage, options);
+               }
+               ret = show_available_vars(params.events, params.nevents,
+                                         params.max_probe_points,
+                                         params.target_module,
+                                         params.show_ext_vars);
+               if (ret < 0)
+                       pr_err("  Error: Failed to show vars. (%d)\n", ret);
+               return ret;
+       }
 #endif
 
        if (params.dellist) {
@@ -258,8 +313,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
 
        if (params.nevents) {
                ret = add_perf_probe_events(params.events, params.nevents,
-                                           params.force_add,
-                                           params.max_probe_points);
+                                           params.max_probe_points,
+                                           params.target_module,
+                                           params.force_add);
                if (ret < 0) {
                        pr_err("  Error: Failed to add events. (%d)\n", ret);
                        return ret;
index 55fc1f46892a6a920411db7dc91226bcbe6a7f82..5de405d452300318541338293563d8ebc41ccb87 100644 (file)
@@ -32,7 +32,7 @@
 
 static char            const *input_name = "perf.data";
 
-static bool            force;
+static bool            force, use_tui, use_stdio;
 static bool            hide_unresolved;
 static bool            dont_use_callchains;
 
@@ -107,7 +107,8 @@ static int perf_session__add_hist_entry(struct perf_session *self,
                goto out_free_syms;
        err = 0;
        if (symbol_conf.use_callchain) {
-               err = append_chain(he->callchain, data->callchain, syms, data->period);
+               err = callchain_append(he->callchain, data->callchain, syms,
+                                      data->period);
                if (err)
                        goto out_free_syms;
        }
@@ -450,6 +451,8 @@ static const struct option options[] = {
                    "Show per-thread event counters"),
        OPT_STRING(0, "pretty", &pretty_printing_style, "key",
                   "pretty printing style key: normal raw"),
+       OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"),
+       OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"),
        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
                   "sort by key(s): pid, comm, dso, symbol, parent"),
        OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
@@ -482,8 +485,15 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
 {
        argc = parse_options(argc, argv, options, report_usage, 0);
 
+       if (use_stdio)
+               use_browser = 0;
+       else if (use_tui)
+               use_browser = 1;
+
        if (strcmp(input_name, "-") != 0)
                setup_browser();
+       else
+               use_browser = 0;
        /*
         * Only in the newt browser we are doing integrated annotation,
         * so don't allocate extra space that won't be used in the stdio
index 40a6a2992d15b286a883ebbbb0f5dd4c10d0e6c5..deda1a93131e35640e24ab9d138ac84485cf207b 100644 (file)
@@ -46,9 +46,6 @@ static struct scripting_ops   *scripting_ops;
 
 static void setup_scripting(void)
 {
-       /* make sure PERF_EXEC_PATH is set for scripts */
-       perf_set_argv_exec_path(perf_exec_path());
-
        setup_perl_scripting();
        setup_python_scripting();
 
@@ -285,7 +282,7 @@ static int parse_scriptname(const struct option *opt __used,
                script++;
        } else {
                script = str;
-               ext = strchr(script, '.');
+               ext = strrchr(script, '.');
                if (!ext) {
                        fprintf(stderr, "invalid script extension");
                        return -1;
@@ -593,6 +590,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
                suffix = REPORT_SUFFIX;
        }
 
+       /* make sure PERF_EXEC_PATH is set for scripts */
+       perf_set_argv_exec_path(perf_exec_path());
+
        if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) {
                char *record_script_path, *report_script_path;
                int live_pipe[2];
index 7a7b6085905382c791834b0c0f35ed5f39658e26..b253db634f04b7e8ddfddd1cc33bb3ce8343a49a 100644 (file)
@@ -110,6 +110,17 @@ int main(void)
 }
 endef
 
+define SOURCE_STRLCPY
+#include <stdlib.h>
+extern size_t strlcpy(char *dest, const char *src, size_t size);
+
+int main(void)
+{
+       strlcpy(NULL, NULL, 0);
+       return 0;
+}
+endef
+
 # try-cc
 # Usage: option = $(call try-cc, source-to-build, cc-options)
 try-cc = $(shell sh -c                                           \
index e3a5e55d54ff6706f620e9517d1a33f4b991364c..4028d92dc4ae6602927d3c82c02f3973506d995e 100644 (file)
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
        shift
     fi
 fi
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/failed-syscalls.pl $comm
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/failed-syscalls.pl $comm
index d83070b7eeb536d2afa455601d6e8533bbd5694a..ba25f4d41fb02a1d40303ebcdb8ba8f17ff8470d 100644 (file)
@@ -7,7 +7,7 @@ if [ $# -lt 1 ] ; then
 fi
 comm=$1
 shift
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-file.pl $comm
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-file.pl $comm
 
 
 
index 7ef46983f62f471145f924a6901b5c1e75a68572..641a3f5d085c6148e9437e10704f6953d7d1eca5 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/bash
 # description: system-wide r/w activity
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/rw-by-pid.pl
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/rw-by-pid.pl
 
 
 
index 93e698cd3f382e79b93ffc90db7aac8162dbc529..4918dba77021e676fdfeaf6c7d3e90105979ccc8 100644 (file)
@@ -17,7 +17,7 @@ if [ "$n_args" -gt 0 ] ; then
     interval=$1
     shift
 fi
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/rwtop.pl $interval
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/rwtop.pl $interval
 
 
 
index a0d898f9ca1d2c87c0a46e475483dc58101f4305..49052ebcb6326d8aa13ea309994d965ca045f58b 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/bash
 # description: system-wide min/max/avg wakeup latency
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/wakeup-latency.pl
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/wakeup-latency.pl
 
 
 
index 35081132ef97551f7bc352180a75037ccb927dab..df0c65f4ca93de35b07bbe9e24f5a966d8b75ea8 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/bash
 # description: workqueue stats (ins/exe/create/destroy)
-perf trace $@ -s ~/libexec/perf-core/scripts/perl/workqueue-stats.pl
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/perl/workqueue-stats.pl
 
 
 
index 9689bc0acd9f2d934050c71231c3d4635a2af7b2..99ff1b7a0d2c5d3e6fd585350464f7f6cd969249 100644 (file)
@@ -6,6 +6,8 @@
 # Public License ("GPL") version 2 as published by the Free Software
 # Foundation.
 
+import errno, os
+
 NSECS_PER_SEC    = 1000000000
 
 def avg(total, n):
@@ -26,3 +28,41 @@ def nsecs_str(nsecs):
 
 def clear_term():
     print("\x1b[H\x1b[2J")
+
+audit_package_warned = False
+
+try:
+       import audit
+       machine_to_id = {
+               'x86_64': audit.MACH_86_64,
+               'alpha' : audit.MACH_ALPHA,
+               'ia64'  : audit.MACH_IA64,
+               'ppc'   : audit.MACH_PPC,
+               'ppc64' : audit.MACH_PPC64,
+               's390'  : audit.MACH_S390,
+               's390x' : audit.MACH_S390X,
+               'i386'  : audit.MACH_X86,
+               'i586'  : audit.MACH_X86,
+               'i686'  : audit.MACH_X86,
+       }
+       try:
+               machine_to_id['armeb'] = audit.MACH_ARMEB
+       except:
+               pass
+       machine_id = machine_to_id[os.uname()[4]]
+except:
+       if not audit_package_warned:
+               audit_package_warned = True
+               print "Install the audit-libs-python package to get syscall names"
+
+def syscall_name(id):
+       try:
+               return audit.audit_syscall_to_name(id, machine_id)
+       except:
+               return str(id)
+
+def strerror(nr):
+       try:
+               return errno.errorcode[abs(nr)]
+       except:
+               return "Unknown %d errno" % nr
index 30293545fcc2864f0f577669ed88a40353c1f4a9..03587021463d4ef6c7d25b4d0a852178fded5a86 100644 (file)
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
        shift
     fi
 fi
-perf trace $@ -s ~/libexec/perf-core/scripts/python/failed-syscalls-by-pid.py $comm
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/failed-syscalls-by-pid.py $comm
diff --git a/tools/perf/scripts/python/bin/netdev-times-record b/tools/perf/scripts/python/bin/netdev-times-record
new file mode 100644 (file)
index 0000000..d931a82
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+perf record -a -e net:net_dev_xmit -e net:net_dev_queue                \
+               -e net:netif_receive_skb -e net:netif_rx                \
+               -e skb:consume_skb -e skb:kfree_skb                     \
+               -e skb:skb_copy_datagram_iovec -e napi:napi_poll        \
+               -e irq:irq_handler_entry -e irq:irq_handler_exit        \
+               -e irq:softirq_entry -e irq:softirq_exit                \
+               -e irq:softirq_raise $@
diff --git a/tools/perf/scripts/python/bin/netdev-times-report b/tools/perf/scripts/python/bin/netdev-times-report
new file mode 100644 (file)
index 0000000..4ad361b
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash
+# description: display a process of packet and processing time
+# args: [tx] [rx] [dev=] [debug]
+
+perf trace -s "$PERF_EXEC_PATH"/scripts/python/netdev-times.py $@
index 61d05f72e4431518127b156505ec549a481aed0f..df1791f07c24233c638e445d48ff3ab52955889c 100644 (file)
@@ -1,3 +1,3 @@
 #!/bin/bash
 # description: sched migration overview
-perf trace $@ -s ~/libexec/perf-core/scripts/python/sched-migration.py
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/sched-migration.py
index b01c842ae7b40aef8a77c5863991969d3c09c939..36b409c05e50ac5e6f80f7b82189aaa0d2ba096a 100644 (file)
@@ -21,4 +21,4 @@ elif [ "$n_args" -gt 0 ] ; then
     interval=$1
     shift
 fi
-perf trace $@ -s ~/libexec/perf-core/scripts/python/sctop.py $comm $interval
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/sctop.py $comm $interval
index 9e9d8ddd72ced9d6b652c5c130070b86ecdc1cfe..4eb88c9fc83ce7e99e14e8b004f71930b422d89a 100644 (file)
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
        shift
     fi
 fi
-perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts-by-pid.py $comm
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/syscall-counts-by-pid.py $comm
index dc076b618796fa999b3024540c9c747a2da4553a..cb2f9c5cf17e825972870c5c934500672e8bd15e 100644 (file)
@@ -7,4 +7,4 @@ if [ $# -gt 0 ] ; then
        shift
     fi
 fi
-perf trace $@ -s ~/libexec/perf-core/scripts/python/syscall-counts.py $comm
+perf trace $@ -s "$PERF_EXEC_PATH"/scripts/python/syscall-counts.py $comm
index 0ca02278fe69ab7af792c4c708864ea9a1ce8138..acd7848717b35ea7c0c46ae61dc01241673f936d 100644 (file)
@@ -13,21 +13,26 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
 
 from perf_trace_context import *
 from Core import *
+from Util import *
 
-usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
+usage = "perf trace -s syscall-counts-by-pid.py [comm|pid]\n";
 
 for_comm = None
+for_pid = None
 
 if len(sys.argv) > 2:
        sys.exit(usage)
 
 if len(sys.argv) > 1:
-       for_comm = sys.argv[1]
+       try:
+               for_pid = int(sys.argv[1])
+       except:
+               for_comm = sys.argv[1]
 
 syscalls = autodict()
 
 def trace_begin():
-       pass
+       print "Press control+C to stop and show the summary"
 
 def trace_end():
        print_error_totals()
@@ -35,9 +40,9 @@ def trace_end():
 def raw_syscalls__sys_exit(event_name, context, common_cpu,
        common_secs, common_nsecs, common_pid, common_comm,
        id, ret):
-       if for_comm is not None:
-               if common_comm != for_comm:
-                       return
+       if (for_comm and common_comm != for_comm) or \
+          (for_pid  and common_pid  != for_pid ):
+               return
 
        if ret < 0:
                try:
@@ -62,7 +67,7 @@ def print_error_totals():
                    print "\n%s [%d]\n" % (comm, pid),
                    id_keys = syscalls[comm][pid].keys()
                    for id in id_keys:
-                           print "  syscall: %-16d\n" % (id),
+                           print "  syscall: %-16s\n" % syscall_name(id),
                            ret_keys = syscalls[comm][pid][id].keys()
                            for ret, val in sorted(syscalls[comm][pid][id].iteritems(), key = lambda(k, v): (v, k),  reverse = True):
-                                   print "    err = %-20d  %10d\n" % (ret, val),
+                                   print "    err = %-20s  %10d\n" % (strerror(ret), val),
diff --git a/tools/perf/scripts/python/netdev-times.py b/tools/perf/scripts/python/netdev-times.py
new file mode 100644 (file)
index 0000000..9aa0a32
--- /dev/null
@@ -0,0 +1,464 @@
+# Display a process of packets and processed time.
+# It helps us to investigate networking or network device.
+#
+# options
+# tx: show only tx chart
+# rx: show only rx chart
+# dev=: show only thing related to specified device
+# debug: work with debug mode. It shows buffer status.
+
+import os
+import sys
+
+sys.path.append(os.environ['PERF_EXEC_PATH'] + \
+       '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
+
+from perf_trace_context import *
+from Core import *
+from Util import *
+
+all_event_list = []; # insert all tracepoint event related with this script
+irq_dic = {}; # key is cpu and value is a list which stacks irqs
+              # which raise NET_RX softirq
+net_rx_dic = {}; # key is cpu and value include time of NET_RX softirq-entry
+                # and a list which stacks receive
+receive_hunk_list = []; # a list which include a sequence of receive events
+rx_skb_list = []; # received packet list for matching
+                      # skb_copy_datagram_iovec
+
+buffer_budget = 65536; # the budget of rx_skb_list, tx_queue_list and
+                      # tx_xmit_list
+of_count_rx_skb_list = 0; # overflow count
+
+tx_queue_list = []; # list of packets which pass through dev_queue_xmit
+of_count_tx_queue_list = 0; # overflow count
+
+tx_xmit_list = [];  # list of packets which pass through dev_hard_start_xmit
+of_count_tx_xmit_list = 0; # overflow count
+
+tx_free_list = [];  # list of packets which is freed
+
+# options
+show_tx = 0;
+show_rx = 0;
+dev = 0; # store a name of device specified by option "dev="
+debug = 0;
+
+# indices of event_info tuple
+EINFO_IDX_NAME=   0
+EINFO_IDX_CONTEXT=1
+EINFO_IDX_CPU=    2
+EINFO_IDX_TIME=   3
+EINFO_IDX_PID=    4
+EINFO_IDX_COMM=   5
+
+# Calculate a time interval(msec) from src(nsec) to dst(nsec)
+def diff_msec(src, dst):
+       return (dst - src) / 1000000.0
+
+# Display a process of transmitting a packet
+def print_transmit(hunk):
+       if dev != 0 and hunk['dev'].find(dev) < 0:
+               return
+       print "%7s %5d %6d.%06dsec %12.3fmsec      %12.3fmsec" % \
+               (hunk['dev'], hunk['len'],
+               nsecs_secs(hunk['queue_t']),
+               nsecs_nsecs(hunk['queue_t'])/1000,
+               diff_msec(hunk['queue_t'], hunk['xmit_t']),
+               diff_msec(hunk['xmit_t'], hunk['free_t']))
+
+# Format for displaying rx packet processing
+PF_IRQ_ENTRY= "  irq_entry(+%.3fmsec irq=%d:%s)"
+PF_SOFT_ENTRY="  softirq_entry(+%.3fmsec)"
+PF_NAPI_POLL= "  napi_poll_exit(+%.3fmsec %s)"
+PF_JOINT=     "         |"
+PF_WJOINT=    "         |            |"
+PF_NET_RECV=  "         |---netif_receive_skb(+%.3fmsec skb=%x len=%d)"
+PF_NET_RX=    "         |---netif_rx(+%.3fmsec skb=%x)"
+PF_CPY_DGRAM= "         |      skb_copy_datagram_iovec(+%.3fmsec %d:%s)"
+PF_KFREE_SKB= "         |      kfree_skb(+%.3fmsec location=%x)"
+PF_CONS_SKB=  "         |      consume_skb(+%.3fmsec)"
+
+# Display a process of received packets and interrputs associated with
+# a NET_RX softirq
+def print_receive(hunk):
+       show_hunk = 0
+       irq_list = hunk['irq_list']
+       cpu = irq_list[0]['cpu']
+       base_t = irq_list[0]['irq_ent_t']
+       # check if this hunk should be showed
+       if dev != 0:
+               for i in range(len(irq_list)):
+                       if irq_list[i]['name'].find(dev) >= 0:
+                               show_hunk = 1
+                               break
+       else:
+               show_hunk = 1
+       if show_hunk == 0:
+               return
+
+       print "%d.%06dsec cpu=%d" % \
+               (nsecs_secs(base_t), nsecs_nsecs(base_t)/1000, cpu)
+       for i in range(len(irq_list)):
+               print PF_IRQ_ENTRY % \
+                       (diff_msec(base_t, irq_list[i]['irq_ent_t']),
+                       irq_list[i]['irq'], irq_list[i]['name'])
+               print PF_JOINT
+               irq_event_list = irq_list[i]['event_list']
+               for j in range(len(irq_event_list)):
+                       irq_event = irq_event_list[j]
+                       if irq_event['event'] == 'netif_rx':
+                               print PF_NET_RX % \
+                                       (diff_msec(base_t, irq_event['time']),
+                                       irq_event['skbaddr'])
+                               print PF_JOINT
+       print PF_SOFT_ENTRY % \
+               diff_msec(base_t, hunk['sirq_ent_t'])
+       print PF_JOINT
+       event_list = hunk['event_list']
+       for i in range(len(event_list)):
+               event = event_list[i]
+               if event['event_name'] == 'napi_poll':
+                       print PF_NAPI_POLL % \
+                           (diff_msec(base_t, event['event_t']), event['dev'])
+                       if i == len(event_list) - 1:
+                               print ""
+                       else:
+                               print PF_JOINT
+               else:
+                       print PF_NET_RECV % \
+                           (diff_msec(base_t, event['event_t']), event['skbaddr'],
+                               event['len'])
+                       if 'comm' in event.keys():
+                               print PF_WJOINT
+                               print PF_CPY_DGRAM % \
+                                       (diff_msec(base_t, event['comm_t']),
+                                       event['pid'], event['comm'])
+                       elif 'handle' in event.keys():
+                               print PF_WJOINT
+                               if event['handle'] == "kfree_skb":
+                                       print PF_KFREE_SKB % \
+                                               (diff_msec(base_t,
+                                               event['comm_t']),
+                                               event['location'])
+                               elif event['handle'] == "consume_skb":
+                                       print PF_CONS_SKB % \
+                                               diff_msec(base_t,
+                                                       event['comm_t'])
+                       print PF_JOINT
+
+def trace_begin():
+       global show_tx
+       global show_rx
+       global dev
+       global debug
+
+       for i in range(len(sys.argv)):
+               if i == 0:
+                       continue
+               arg = sys.argv[i]
+               if arg == 'tx':
+                       show_tx = 1
+               elif arg =='rx':
+                       show_rx = 1
+               elif arg.find('dev=',0, 4) >= 0:
+                       dev = arg[4:]
+               elif arg == 'debug':
+                       debug = 1
+       if show_tx == 0  and show_rx == 0:
+               show_tx = 1
+               show_rx = 1
+
+def trace_end():
+       # order all events in time
+       all_event_list.sort(lambda a,b :cmp(a[EINFO_IDX_TIME],
+                                           b[EINFO_IDX_TIME]))
+       # process all events
+       for i in range(len(all_event_list)):
+               event_info = all_event_list[i]
+               name = event_info[EINFO_IDX_NAME]
+               if name == 'irq__softirq_exit':
+                       handle_irq_softirq_exit(event_info)
+               elif name == 'irq__softirq_entry':
+                       handle_irq_softirq_entry(event_info)
+               elif name == 'irq__softirq_raise':
+                       handle_irq_softirq_raise(event_info)
+               elif name == 'irq__irq_handler_entry':
+                       handle_irq_handler_entry(event_info)
+               elif name == 'irq__irq_handler_exit':
+                       handle_irq_handler_exit(event_info)
+               elif name == 'napi__napi_poll':
+                       handle_napi_poll(event_info)
+               elif name == 'net__netif_receive_skb':
+                       handle_netif_receive_skb(event_info)
+               elif name == 'net__netif_rx':
+                       handle_netif_rx(event_info)
+               elif name == 'skb__skb_copy_datagram_iovec':
+                       handle_skb_copy_datagram_iovec(event_info)
+               elif name == 'net__net_dev_queue':
+                       handle_net_dev_queue(event_info)
+               elif name == 'net__net_dev_xmit':
+                       handle_net_dev_xmit(event_info)
+               elif name == 'skb__kfree_skb':
+                       handle_kfree_skb(event_info)
+               elif name == 'skb__consume_skb':
+                       handle_consume_skb(event_info)
+       # display receive hunks
+       if show_rx:
+               for i in range(len(receive_hunk_list)):
+                       print_receive(receive_hunk_list[i])
+       # display transmit hunks
+       if show_tx:
+               print "   dev    len      Qdisc        " \
+                       "       netdevice             free"
+               for i in range(len(tx_free_list)):
+                       print_transmit(tx_free_list[i])
+       if debug:
+               print "debug buffer status"
+               print "----------------------------"
+               print "xmit Qdisc:remain:%d overflow:%d" % \
+                       (len(tx_queue_list), of_count_tx_queue_list)
+               print "xmit netdevice:remain:%d overflow:%d" % \
+                       (len(tx_xmit_list), of_count_tx_xmit_list)
+               print "receive:remain:%d overflow:%d" % \
+                       (len(rx_skb_list), of_count_rx_skb_list)
+
+# called from perf, when it finds a correspoinding event
+def irq__softirq_entry(name, context, cpu, sec, nsec, pid, comm, vec):
+       if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
+               return
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
+       all_event_list.append(event_info)
+
+def irq__softirq_exit(name, context, cpu, sec, nsec, pid, comm, vec):
+       if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
+               return
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
+       all_event_list.append(event_info)
+
+def irq__softirq_raise(name, context, cpu, sec, nsec, pid, comm, vec):
+       if symbol_str("irq__softirq_entry", "vec", vec) != "NET_RX":
+               return
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, vec)
+       all_event_list.append(event_info)
+
+def irq__irq_handler_entry(name, context, cpu, sec, nsec, pid, comm,
+                       irq, irq_name):
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
+                       irq, irq_name)
+       all_event_list.append(event_info)
+
+def irq__irq_handler_exit(name, context, cpu, sec, nsec, pid, comm, irq, ret):
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm, irq, ret)
+       all_event_list.append(event_info)
+
+def napi__napi_poll(name, context, cpu, sec, nsec, pid, comm, napi, dev_name):
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
+                       napi, dev_name)
+       all_event_list.append(event_info)
+
+def net__netif_receive_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr,
+                       skblen, dev_name):
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
+                       skbaddr, skblen, dev_name)
+       all_event_list.append(event_info)
+
+def net__netif_rx(name, context, cpu, sec, nsec, pid, comm, skbaddr,
+                       skblen, dev_name):
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
+                       skbaddr, skblen, dev_name)
+       all_event_list.append(event_info)
+
+def net__net_dev_queue(name, context, cpu, sec, nsec, pid, comm,
+                       skbaddr, skblen, dev_name):
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
+                       skbaddr, skblen, dev_name)
+       all_event_list.append(event_info)
+
+def net__net_dev_xmit(name, context, cpu, sec, nsec, pid, comm,
+                       skbaddr, skblen, rc, dev_name):
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
+                       skbaddr, skblen, rc ,dev_name)
+       all_event_list.append(event_info)
+
+def skb__kfree_skb(name, context, cpu, sec, nsec, pid, comm,
+                       skbaddr, protocol, location):
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
+                       skbaddr, protocol, location)
+       all_event_list.append(event_info)
+
+def skb__consume_skb(name, context, cpu, sec, nsec, pid, comm, skbaddr):
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
+                       skbaddr)
+       all_event_list.append(event_info)
+
+def skb__skb_copy_datagram_iovec(name, context, cpu, sec, nsec, pid, comm,
+       skbaddr, skblen):
+       event_info = (name, context, cpu, nsecs(sec, nsec), pid, comm,
+                       skbaddr, skblen)
+       all_event_list.append(event_info)
+
+def handle_irq_handler_entry(event_info):
+       (name, context, cpu, time, pid, comm, irq, irq_name) = event_info
+       if cpu not in irq_dic.keys():
+               irq_dic[cpu] = []
+       irq_record = {'irq':irq, 'name':irq_name, 'cpu':cpu, 'irq_ent_t':time}
+       irq_dic[cpu].append(irq_record)
+
+def handle_irq_handler_exit(event_info):
+       (name, context, cpu, time, pid, comm, irq, ret) = event_info
+       if cpu not in irq_dic.keys():
+               return
+       irq_record = irq_dic[cpu].pop()
+       if irq != irq_record['irq']:
+               return
+       irq_record.update({'irq_ext_t':time})
+       # if an irq doesn't include NET_RX softirq, drop.
+       if 'event_list' in irq_record.keys():
+               irq_dic[cpu].append(irq_record)
+
+def handle_irq_softirq_raise(event_info):
+       (name, context, cpu, time, pid, comm, vec) = event_info
+       if cpu not in irq_dic.keys() \
+       or len(irq_dic[cpu]) == 0:
+               return
+       irq_record = irq_dic[cpu].pop()
+       if 'event_list' in irq_record.keys():
+               irq_event_list = irq_record['event_list']
+       else:
+               irq_event_list = []
+       irq_event_list.append({'time':time, 'event':'sirq_raise'})
+       irq_record.update({'event_list':irq_event_list})
+       irq_dic[cpu].append(irq_record)
+
+def handle_irq_softirq_entry(event_info):
+       (name, context, cpu, time, pid, comm, vec) = event_info
+       net_rx_dic[cpu] = {'sirq_ent_t':time, 'event_list':[]}
+
+def handle_irq_softirq_exit(event_info):
+       (name, context, cpu, time, pid, comm, vec) = event_info
+       irq_list = []
+       event_list = 0
+       if cpu in irq_dic.keys():
+               irq_list = irq_dic[cpu]
+               del irq_dic[cpu]
+       if cpu in net_rx_dic.keys():
+               sirq_ent_t = net_rx_dic[cpu]['sirq_ent_t']
+               event_list = net_rx_dic[cpu]['event_list']
+               del net_rx_dic[cpu]
+       if irq_list == [] or event_list == 0:
+               return
+       rec_data = {'sirq_ent_t':sirq_ent_t, 'sirq_ext_t':time,
+                   'irq_list':irq_list, 'event_list':event_list}
+       # merge information realted to a NET_RX softirq
+       receive_hunk_list.append(rec_data)
+
+def handle_napi_poll(event_info):
+       (name, context, cpu, time, pid, comm, napi, dev_name) = event_info
+       if cpu in net_rx_dic.keys():
+               event_list = net_rx_dic[cpu]['event_list']
+               rec_data = {'event_name':'napi_poll',
+                               'dev':dev_name, 'event_t':time}
+               event_list.append(rec_data)
+
+def handle_netif_rx(event_info):
+       (name, context, cpu, time, pid, comm,
+               skbaddr, skblen, dev_name) = event_info
+       if cpu not in irq_dic.keys() \
+       or len(irq_dic[cpu]) == 0:
+               return
+       irq_record = irq_dic[cpu].pop()
+       if 'event_list' in irq_record.keys():
+               irq_event_list = irq_record['event_list']
+       else:
+               irq_event_list = []
+       irq_event_list.append({'time':time, 'event':'netif_rx',
+               'skbaddr':skbaddr, 'skblen':skblen, 'dev_name':dev_name})
+       irq_record.update({'event_list':irq_event_list})
+       irq_dic[cpu].append(irq_record)
+
+def handle_netif_receive_skb(event_info):
+       global of_count_rx_skb_list
+
+       (name, context, cpu, time, pid, comm,
+               skbaddr, skblen, dev_name) = event_info
+       if cpu in net_rx_dic.keys():
+               rec_data = {'event_name':'netif_receive_skb',
+                           'event_t':time, 'skbaddr':skbaddr, 'len':skblen}
+               event_list = net_rx_dic[cpu]['event_list']
+               event_list.append(rec_data)
+               rx_skb_list.insert(0, rec_data)
+               if len(rx_skb_list) > buffer_budget:
+                       rx_skb_list.pop()
+                       of_count_rx_skb_list += 1
+
+def handle_net_dev_queue(event_info):
+       global of_count_tx_queue_list
+
+       (name, context, cpu, time, pid, comm,
+               skbaddr, skblen, dev_name) = event_info
+       skb = {'dev':dev_name, 'skbaddr':skbaddr, 'len':skblen, 'queue_t':time}
+       tx_queue_list.insert(0, skb)
+       if len(tx_queue_list) > buffer_budget:
+               tx_queue_list.pop()
+               of_count_tx_queue_list += 1
+
+def handle_net_dev_xmit(event_info):
+       global of_count_tx_xmit_list
+
+       (name, context, cpu, time, pid, comm,
+               skbaddr, skblen, rc, dev_name) = event_info
+       if rc == 0: # NETDEV_TX_OK
+               for i in range(len(tx_queue_list)):
+                       skb = tx_queue_list[i]
+                       if skb['skbaddr'] == skbaddr:
+                               skb['xmit_t'] = time
+                               tx_xmit_list.insert(0, skb)
+                               del tx_queue_list[i]
+                               if len(tx_xmit_list) > buffer_budget:
+                                       tx_xmit_list.pop()
+                                       of_count_tx_xmit_list += 1
+                               return
+
+def handle_kfree_skb(event_info):
+       (name, context, cpu, time, pid, comm,
+               skbaddr, protocol, location) = event_info
+       for i in range(len(tx_queue_list)):
+               skb = tx_queue_list[i]
+               if skb['skbaddr'] == skbaddr:
+                       del tx_queue_list[i]
+                       return
+       for i in range(len(tx_xmit_list)):
+               skb = tx_xmit_list[i]
+               if skb['skbaddr'] == skbaddr:
+                       skb['free_t'] = time
+                       tx_free_list.append(skb)
+                       del tx_xmit_list[i]
+                       return
+       for i in range(len(rx_skb_list)):
+               rec_data = rx_skb_list[i]
+               if rec_data['skbaddr'] == skbaddr:
+                       rec_data.update({'handle':"kfree_skb",
+                                       'comm':comm, 'pid':pid, 'comm_t':time})
+                       del rx_skb_list[i]
+                       return
+
+def handle_consume_skb(event_info):
+       (name, context, cpu, time, pid, comm, skbaddr) = event_info
+       for i in range(len(tx_xmit_list)):
+               skb = tx_xmit_list[i]
+               if skb['skbaddr'] == skbaddr:
+                       skb['free_t'] = time
+                       tx_free_list.append(skb)
+                       del tx_xmit_list[i]
+                       return
+
+def handle_skb_copy_datagram_iovec(event_info):
+       (name, context, cpu, time, pid, comm, skbaddr, skblen) = event_info
+       for i in range(len(rx_skb_list)):
+               rec_data = rx_skb_list[i]
+               if skbaddr == rec_data['skbaddr']:
+                       rec_data.update({'handle':"skb_copy_datagram_iovec",
+                                       'comm':comm, 'pid':pid, 'comm_t':time})
+                       del rx_skb_list[i]
+                       return
index 6cafad40c2962930bcb027564d7967e5c91aeb62..547cbe99de687903331039a6449cf869938a8bd8 100644 (file)
@@ -8,10 +8,7 @@
 # will be refreshed every [interval] seconds.  The default interval is
 # 3 seconds.
 
-import thread
-import time
-import os
-import sys
+import os, sys, thread, time
 
 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
        '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
@@ -71,7 +68,7 @@ def print_syscall_totals(interval):
                for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
                                              reverse = True):
                        try:
-                               print "%-40d  %10d\n" % (id, val),
+                               print "%-40s  %10d\n" % (syscall_name(id), val),
                        except TypeError:
                                pass
                syscalls.clear()
index af722d6a4b3f1c8fa1cf585a0c9608d0524a185f..d1ee3ec10cf2b911776df81df7a5d4d66a5f5fc1 100644 (file)
@@ -5,29 +5,33 @@
 # Displays system-wide system call totals, broken down by syscall.
 # If a [comm] arg is specified, only syscalls called by [comm] are displayed.
 
-import os
-import sys
+import os, sys
 
 sys.path.append(os.environ['PERF_EXEC_PATH'] + \
        '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
 
 from perf_trace_context import *
 from Core import *
+from Util import syscall_name
 
 usage = "perf trace -s syscall-counts-by-pid.py [comm]\n";
 
 for_comm = None
+for_pid = None
 
 if len(sys.argv) > 2:
        sys.exit(usage)
 
 if len(sys.argv) > 1:
-       for_comm = sys.argv[1]
+       try:
+               for_pid = int(sys.argv[1])
+       except:
+               for_comm = sys.argv[1]
 
 syscalls = autodict()
 
 def trace_begin():
-       pass
+       print "Press control+C to stop and show the summary"
 
 def trace_end():
        print_syscall_totals()
@@ -35,9 +39,10 @@ def trace_end():
 def raw_syscalls__sys_enter(event_name, context, common_cpu,
        common_secs, common_nsecs, common_pid, common_comm,
        id, args):
-       if for_comm is not None:
-               if common_comm != for_comm:
-                       return
+
+       if (for_comm and common_comm != for_comm) or \
+          (for_pid  and common_pid  != for_pid ):
+               return
        try:
                syscalls[common_comm][common_pid][id] += 1
        except TypeError:
@@ -61,4 +66,4 @@ def print_syscall_totals():
                    id_keys = syscalls[comm][pid].keys()
                    for id, val in sorted(syscalls[comm][pid].iteritems(), \
                                  key = lambda(k, v): (v, k),  reverse = True):
-                           print "  %-38d  %10d\n" % (id, val),
+                           print "  %-38s  %10d\n" % (syscall_name(id), val),
index f977e85ff04950cef3cc5550dcdca79a5d688568..ea183dc82d29e54a005f28648201a2219feac224 100644 (file)
@@ -13,6 +13,7 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \
 
 from perf_trace_context import *
 from Core import *
+from Util import syscall_name
 
 usage = "perf trace -s syscall-counts.py [comm]\n";
 
@@ -27,7 +28,7 @@ if len(sys.argv) > 1:
 syscalls = autodict()
 
 def trace_begin():
-       pass
+       print "Press control+C to stop and show the summary"
 
 def trace_end():
        print_syscall_totals()
@@ -55,4 +56,4 @@ def print_syscall_totals():
 
     for id, val in sorted(syscalls.iteritems(), key = lambda(k, v): (v, k), \
                                  reverse = True):
-           print "%-40d  %10d\n" % (id, val),
+           print "%-40s  %10d\n" % (syscall_name(id), val),
index 27e9ebe4076e0efbf4117a46f2dbbcc74a1dcc3e..a7729797fd96254bc35326077337a71f919c19b5 100644 (file)
@@ -82,6 +82,8 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
 extern char *perf_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
 
+#ifdef NO_STRLCPY
 extern size_t strlcpy(char *dest, const char *src, size_t size);
+#endif
 
 #endif /* __PERF_CACHE_H */
index f231f43424d27930a286cb52902c21cb4534a068..e12d539417b2cc4644e2d5a919cfb8a23e8ae163 100644 (file)
@@ -28,6 +28,9 @@ bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event)
 #define chain_for_each_child(child, parent)    \
        list_for_each_entry(child, &parent->children, brothers)
 
+#define chain_for_each_child_safe(child, next, parent) \
+       list_for_each_entry_safe(child, next, &parent->children, brothers)
+
 static void
 rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
                    enum chain_mode mode)
@@ -86,10 +89,10 @@ __sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
  * sort them by hit
  */
 static void
-sort_chain_flat(struct rb_root *rb_root, struct callchain_node *node,
+sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
                u64 min_hit, struct callchain_param *param __used)
 {
-       __sort_chain_flat(rb_root, node, min_hit);
+       __sort_chain_flat(rb_root, &root->node, min_hit);
 }
 
 static void __sort_chain_graph_abs(struct callchain_node *node,
@@ -108,11 +111,11 @@ static void __sort_chain_graph_abs(struct callchain_node *node,
 }
 
 static void
-sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_node *chain_root,
+sort_chain_graph_abs(struct rb_root *rb_root, struct callchain_root *chain_root,
                     u64 min_hit, struct callchain_param *param __used)
 {
-       __sort_chain_graph_abs(chain_root, min_hit);
-       rb_root->rb_node = chain_root->rb_root.rb_node;
+       __sort_chain_graph_abs(&chain_root->node, min_hit);
+       rb_root->rb_node = chain_root->node.rb_root.rb_node;
 }
 
 static void __sort_chain_graph_rel(struct callchain_node *node,
@@ -133,11 +136,11 @@ static void __sort_chain_graph_rel(struct callchain_node *node,
 }
 
 static void
-sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,
+sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_root *chain_root,
                     u64 min_hit __used, struct callchain_param *param)
 {
-       __sort_chain_graph_rel(chain_root, param->min_percent / 100.0);
-       rb_root->rb_node = chain_root->rb_root.rb_node;
+       __sort_chain_graph_rel(&chain_root->node, param->min_percent / 100.0);
+       rb_root->rb_node = chain_root->node.rb_root.rb_node;
 }
 
 int register_callchain_param(struct callchain_param *param)
@@ -284,19 +287,18 @@ split_add_child(struct callchain_node *parent, struct resolved_chain *chain,
 }
 
 static int
-__append_chain(struct callchain_node *root, struct resolved_chain *chain,
-              unsigned int start, u64 period);
+append_chain(struct callchain_node *root, struct resolved_chain *chain,
+            unsigned int start, u64 period);
 
 static void
-__append_chain_children(struct callchain_node *root,
-                       struct resolved_chain *chain,
-                       unsigned int start, u64 period)
+append_chain_children(struct callchain_node *root, struct resolved_chain *chain,
+                     unsigned int start, u64 period)
 {
        struct callchain_node *rnode;
 
        /* lookup in childrens */
        chain_for_each_child(rnode, root) {
-               unsigned int ret = __append_chain(rnode, chain, start, period);
+               unsigned int ret = append_chain(rnode, chain, start, period);
 
                if (!ret)
                        goto inc_children_hit;
@@ -309,8 +311,8 @@ inc_children_hit:
 }
 
 static int
-__append_chain(struct callchain_node *root, struct resolved_chain *chain,
-              unsigned int start, u64 period)
+append_chain(struct callchain_node *root, struct resolved_chain *chain,
+            unsigned int start, u64 period)
 {
        struct callchain_list *cnode;
        unsigned int i = start;
@@ -357,7 +359,7 @@ __append_chain(struct callchain_node *root, struct resolved_chain *chain,
        }
 
        /* We match the node and still have a part remaining */
-       __append_chain_children(root, chain, i, period);
+       append_chain_children(root, chain, i, period);
 
        return 0;
 }
@@ -380,8 +382,8 @@ static void filter_context(struct ip_callchain *old, struct resolved_chain *new,
 }
 
 
-int append_chain(struct callchain_node *root, struct ip_callchain *chain,
-                struct map_symbol *syms, u64 period)
+int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
+                    struct map_symbol *syms, u64 period)
 {
        struct resolved_chain *filtered;
 
@@ -398,9 +400,65 @@ int append_chain(struct callchain_node *root, struct ip_callchain *chain,
        if (!filtered->nr)
                goto end;
 
-       __append_chain_children(root, filtered, 0, period);
+       append_chain_children(&root->node, filtered, 0, period);
+
+       if (filtered->nr > root->max_depth)
+               root->max_depth = filtered->nr;
 end:
        free(filtered);
 
        return 0;
 }
+
+static int
+merge_chain_branch(struct callchain_node *dst, struct callchain_node *src,
+                  struct resolved_chain *chain)
+{
+       struct callchain_node *child, *next_child;
+       struct callchain_list *list, *next_list;
+       int old_pos = chain->nr;
+       int err = 0;
+
+       list_for_each_entry_safe(list, next_list, &src->val, list) {
+               chain->ips[chain->nr].ip = list->ip;
+               chain->ips[chain->nr].ms = list->ms;
+               chain->nr++;
+               list_del(&list->list);
+               free(list);
+       }
+
+       if (src->hit)
+               append_chain_children(dst, chain, 0, src->hit);
+
+       chain_for_each_child_safe(child, next_child, src) {
+               err = merge_chain_branch(dst, child, chain);
+               if (err)
+                       break;
+
+               list_del(&child->brothers);
+               free(child);
+       }
+
+       chain->nr = old_pos;
+
+       return err;
+}
+
+int callchain_merge(struct callchain_root *dst, struct callchain_root *src)
+{
+       struct resolved_chain *chain;
+       int err;
+
+       chain = malloc(sizeof(*chain) +
+                      src->max_depth * sizeof(struct resolved_ip));
+       if (!chain)
+               return -ENOMEM;
+
+       chain->nr = 0;
+
+       err = merge_chain_branch(&dst->node, &src->node, chain);
+
+       free(chain);
+
+       return err;
+}
index 6de4313924fb5c510f354cb3a8e2a73061e103f6..c15fb8c24ad2b87388e97cd6346cfdebaac11dd5 100644 (file)
@@ -26,9 +26,14 @@ struct callchain_node {
        u64                     children_hit;
 };
 
+struct callchain_root {
+       u64                     max_depth;
+       struct callchain_node   node;
+};
+
 struct callchain_param;
 
-typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_node *,
+typedef void (*sort_chain_func_t)(struct rb_root *, struct callchain_root *,
                                 u64, struct callchain_param *);
 
 struct callchain_param {
@@ -44,15 +49,16 @@ struct callchain_list {
        struct list_head        list;
 };
 
-static inline void callchain_init(struct callchain_node *node)
+static inline void callchain_init(struct callchain_root *root)
 {
-       INIT_LIST_HEAD(&node->brothers);
-       INIT_LIST_HEAD(&node->children);
-       INIT_LIST_HEAD(&node->val);
+       INIT_LIST_HEAD(&root->node.brothers);
+       INIT_LIST_HEAD(&root->node.children);
+       INIT_LIST_HEAD(&root->node.val);
 
-       node->children_hit = 0;
-       node->parent = NULL;
-       node->hit = 0;
+       root->node.parent = NULL;
+       root->node.hit = 0;
+       root->node.children_hit = 0;
+       root->max_depth = 0;
 }
 
 static inline u64 cumul_hits(struct callchain_node *node)
@@ -61,8 +67,9 @@ static inline u64 cumul_hits(struct callchain_node *node)
 }
 
 int register_callchain_param(struct callchain_param *param);
-int append_chain(struct callchain_node *root, struct ip_callchain *chain,
-                struct map_symbol *syms, u64 period);
+int callchain_append(struct callchain_root *root, struct ip_callchain *chain,
+                    struct map_symbol *syms, u64 period);
+int callchain_merge(struct callchain_root *dst, struct callchain_root *src);
 
 bool ip_callchain__valid(struct ip_callchain *chain, const event_t *event);
 #endif /* __PERF_CALLCHAIN_H */
index be22ae6ef0558009c0a1faaa4f55bcf2c5d828ca..2022e87409942ca4b0d133c3f889e41178a663d1 100644 (file)
@@ -87,7 +87,7 @@ static void hist_entry__add_cpumode_period(struct hist_entry *self,
 
 static struct hist_entry *hist_entry__new(struct hist_entry *template)
 {
-       size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_node) : 0;
+       size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
        struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
 
        if (self != NULL) {
@@ -226,6 +226,8 @@ static bool collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
 
                if (!cmp) {
                        iter->period += he->period;
+                       if (symbol_conf.use_callchain)
+                               callchain_merge(iter->callchain, he->callchain);
                        hist_entry__free(he);
                        return false;
                }
index 78575796d5f315bff5fa933c906821e610addfff..b397c038372813506092e09646c8d008e4dcf9b9 100644 (file)
@@ -215,6 +215,16 @@ struct symbol *map_groups__find_function_by_name(struct map_groups *self,
        return map_groups__find_symbol_by_name(self, MAP__FUNCTION, name, mapp, filter);
 }
 
+static inline
+struct symbol *machine__find_kernel_function_by_name(struct machine *self,
+                                                    const char *name,
+                                                    struct map **mapp,
+                                                    symbol_filter_t filter)
+{
+       return map_groups__find_function_by_name(&self->kmaps, name, mapp,
+                                                filter);
+}
+
 int map_groups__fixup_overlappings(struct map_groups *self, struct map *map,
                                   int verbose, FILE *fp);
 
index 58a470d036dd0917c16eda49fb8b1987703ca7b5..bd74977114242ff465af39a291d30aa7d463f3b2 100644 (file)
@@ -22,6 +22,7 @@ static const char *get_perf_dir(void)
        return ".";
 }
 
+#ifdef NO_STRLCPY
 size_t strlcpy(char *dest, const char *src, size_t size)
 {
        size_t ret = strlen(src);
@@ -33,7 +34,7 @@ size_t strlcpy(char *dest, const char *src, size_t size)
        }
        return ret;
 }
-
+#endif
 
 static char *get_pathname(void)
 {
index fcc16e4349df9f3353ac03f975d9c1be9938863a..3b6a5297bf16cd5a318273bc0a9bf198734a0cfe 100644 (file)
@@ -74,10 +74,9 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
 static char *synthesize_perf_probe_point(struct perf_probe_point *pp);
 static struct machine machine;
 
-/* Initialize symbol maps and path of vmlinux */
+/* Initialize symbol maps and path of vmlinux/modules */
 static int init_vmlinux(void)
 {
-       struct dso *kernel;
        int ret;
 
        symbol_conf.sort_by_name = true;
@@ -91,33 +90,61 @@ static int init_vmlinux(void)
                goto out;
        }
 
-       ret = machine__init(&machine, "/", 0);
+       ret = machine__init(&machine, "", HOST_KERNEL_ID);
        if (ret < 0)
                goto out;
 
-       kernel = dso__new_kernel(symbol_conf.vmlinux_name);
-       if (kernel == NULL)
-               die("Failed to create kernel dso.");
-
-       ret = __machine__create_kernel_maps(&machine, kernel);
-       if (ret < 0)
-               pr_debug("Failed to create kernel maps.\n");
-
+       if (machine__create_kernel_maps(&machine) < 0) {
+               pr_debug("machine__create_kernel_maps ");
+               goto out;
+       }
 out:
        if (ret < 0)
                pr_warning("Failed to init vmlinux path.\n");
        return ret;
 }
 
+static struct symbol *__find_kernel_function_by_name(const char *name,
+                                                    struct map **mapp)
+{
+       return machine__find_kernel_function_by_name(&machine, name, mapp,
+                                                    NULL);
+}
+
+const char *kernel_get_module_path(const char *module)
+{
+       struct dso *dso;
+
+       if (module) {
+               list_for_each_entry(dso, &machine.kernel_dsos, node) {
+                       if (strncmp(dso->short_name + 1, module,
+                                   dso->short_name_len - 2) == 0)
+                               goto found;
+               }
+               pr_debug("Failed to find module %s.\n", module);
+               return NULL;
+       } else {
+               dso = machine.vmlinux_maps[MAP__FUNCTION]->dso;
+               if (dso__load_vmlinux_path(dso,
+                        machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
+                       pr_debug("Failed to load kernel map.\n");
+                       return NULL;
+               }
+       }
+found:
+       return dso->long_name;
+}
+
 #ifdef DWARF_SUPPORT
-static int open_vmlinux(void)
+static int open_vmlinux(const char *module)
 {
-       if (map__load(machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) {
-               pr_debug("Failed to load kernel map.\n");
-               return -EINVAL;
+       const char *path = kernel_get_module_path(module);
+       if (!path) {
+               pr_err("Failed to find path of %s module", module ?: "kernel");
+               return -ENOENT;
        }
-       pr_debug("Try to open %s\n", machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name);
-       return open(machine.vmlinux_maps[MAP__FUNCTION]->dso->long_name, O_RDONLY);
+       pr_debug("Try to open %s\n", path);
+       return open(path, O_RDONLY);
 }
 
 /*
@@ -125,20 +152,19 @@ static int open_vmlinux(void)
  * Currently only handles kprobes.
  */
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-                                      struct perf_probe_point *pp)
+                                       struct perf_probe_point *pp)
 {
        struct symbol *sym;
-       int fd, ret = -ENOENT;
+       struct map *map;
+       u64 addr;
+       int ret = -ENOENT;
 
-       sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
-                                      tp->symbol, NULL);
+       sym = __find_kernel_function_by_name(tp->symbol, &map);
        if (sym) {
-               fd = open_vmlinux();
-               if (fd >= 0) {
-                       ret = find_perf_probe_point(fd,
-                                                sym->start + tp->offset, pp);
-                       close(fd);
-               }
+               addr = map->unmap_ip(map, sym->start + tp->offset);
+               pr_debug("try to find %s+%ld@%llx\n", tp->symbol,
+                        tp->offset, addr);
+               ret = find_perf_probe_point((unsigned long)addr, pp);
        }
        if (ret <= 0) {
                pr_debug("Failed to find corresponding probes from "
@@ -156,12 +182,12 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 /* Try to find perf_probe_event with debuginfo */
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
                                           struct probe_trace_event **tevs,
-                                          int max_tevs)
+                                          int max_tevs, const char *module)
 {
        bool need_dwarf = perf_probe_event_need_dwarf(pev);
        int fd, ntevs;
 
-       fd = open_vmlinux();
+       fd = open_vmlinux(module);
        if (fd < 0) {
                if (need_dwarf) {
                        pr_warning("Failed to open debuginfo file.\n");
@@ -300,7 +326,7 @@ error:
  * Show line-range always requires debuginfo to find source file and
  * line number.
  */
-int show_line_range(struct line_range *lr)
+int show_line_range(struct line_range *lr, const char *module)
 {
        int l = 1;
        struct line_node *ln;
@@ -313,7 +339,7 @@ int show_line_range(struct line_range *lr)
        if (ret < 0)
                return ret;
 
-       fd = open_vmlinux();
+       fd = open_vmlinux(module);
        if (fd < 0) {
                pr_warning("Failed to open debuginfo file.\n");
                return fd;
@@ -378,11 +404,84 @@ end:
        return ret;
 }
 
+static int show_available_vars_at(int fd, struct perf_probe_event *pev,
+                                 int max_vls, bool externs)
+{
+       char *buf;
+       int ret, i;
+       struct str_node *node;
+       struct variable_list *vls = NULL, *vl;
+
+       buf = synthesize_perf_probe_point(&pev->point);
+       if (!buf)
+               return -EINVAL;
+       pr_debug("Searching variables at %s\n", buf);
+
+       ret = find_available_vars_at(fd, pev, &vls, max_vls, externs);
+       if (ret > 0) {
+               /* Some variables were found */
+               fprintf(stdout, "Available variables at %s\n", buf);
+               for (i = 0; i < ret; i++) {
+                       vl = &vls[i];
+                       /*
+                        * A probe point might be converted to
+                        * several trace points.
+                        */
+                       fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
+                               vl->point.offset);
+                       free(vl->point.symbol);
+                       if (vl->vars) {
+                               strlist__for_each(node, vl->vars)
+                                       fprintf(stdout, "\t\t%s\n", node->s);
+                               strlist__delete(vl->vars);
+                       } else
+                               fprintf(stdout, "(No variables)\n");
+               }
+               free(vls);
+       } else
+               pr_err("Failed to find variables at %s (%d)\n", buf, ret);
+
+       free(buf);
+       return ret;
+}
+
+/* Show available variables on given probe point */
+int show_available_vars(struct perf_probe_event *pevs, int npevs,
+                       int max_vls, const char *module, bool externs)
+{
+       int i, fd, ret = 0;
+
+       ret = init_vmlinux();
+       if (ret < 0)
+               return ret;
+
+       fd = open_vmlinux(module);
+       if (fd < 0) {
+               pr_warning("Failed to open debuginfo file.\n");
+               return fd;
+       }
+
+       setup_pager();
+
+       for (i = 0; i < npevs && ret >= 0; i++)
+               ret = show_available_vars_at(fd, &pevs[i], max_vls, externs);
+
+       close(fd);
+       return ret;
+}
+
 #else  /* !DWARF_SUPPORT */
 
 static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
-                                      struct perf_probe_point *pp)
+                                       struct perf_probe_point *pp)
 {
+       struct symbol *sym;
+
+       sym = __find_kernel_function_by_name(tp->symbol, NULL);
+       if (!sym) {
+               pr_err("Failed to find symbol %s in kernel.\n", tp->symbol);
+               return -ENOENT;
+       }
        pp->function = strdup(tp->symbol);
        if (pp->function == NULL)
                return -ENOMEM;
@@ -394,7 +493,7 @@ static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
 
 static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
                                struct probe_trace_event **tevs __unused,
-                               int max_tevs __unused)
+                               int max_tevs __unused, const char *mod __unused)
 {
        if (perf_probe_event_need_dwarf(pev)) {
                pr_warning("Debuginfo-analysis is not supported.\n");
@@ -403,12 +502,19 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
        return 0;
 }
 
-int show_line_range(struct line_range *lr __unused)
+int show_line_range(struct line_range *lr __unused, const char *module __unused)
 {
        pr_warning("Debuginfo-analysis is not supported.\n");
        return -ENOSYS;
 }
 
+int show_available_vars(struct perf_probe_event *pevs __unused,
+                       int npevs __unused, int max_vls __unused,
+                       const char *module __unused, bool externs __unused)
+{
+       pr_warning("Debuginfo-analysis is not supported.\n");
+       return -ENOSYS;
+}
 #endif
 
 int parse_line_range_desc(const char *arg, struct line_range *lr)
@@ -1087,7 +1193,7 @@ error:
 }
 
 static int convert_to_perf_probe_event(struct probe_trace_event *tev,
-                               struct perf_probe_event *pev)
+                                      struct perf_probe_event *pev)
 {
        char buf[64] = "";
        int i, ret;
@@ -1516,14 +1622,14 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 
 static int convert_to_probe_trace_events(struct perf_probe_event *pev,
                                          struct probe_trace_event **tevs,
-                                         int max_tevs)
+                                         int max_tevs, const char *module)
 {
        struct symbol *sym;
        int ret = 0, i;
        struct probe_trace_event *tev;
 
        /* Convert perf_probe_event with debuginfo */
-       ret = try_to_find_probe_trace_events(pev, tevs, max_tevs);
+       ret = try_to_find_probe_trace_events(pev, tevs, max_tevs, module);
        if (ret != 0)
                return ret;
 
@@ -1572,8 +1678,7 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
        }
 
        /* Currently just checking function name from symbol map */
-       sym = map__find_symbol_by_name(machine.vmlinux_maps[MAP__FUNCTION],
-                                      tev->point.symbol, NULL);
+       sym = __find_kernel_function_by_name(tev->point.symbol, NULL);
        if (!sym) {
                pr_warning("Kernel symbol \'%s\' not found.\n",
                           tev->point.symbol);
@@ -1596,7 +1701,7 @@ struct __event_package {
 };
 
 int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-                         bool force_add, int max_tevs)
+                         int max_tevs, const char *module, bool force_add)
 {
        int i, j, ret;
        struct __event_package *pkgs;
@@ -1617,7 +1722,9 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
                pkgs[i].pev = &pevs[i];
                /* Convert with or without debuginfo */
                ret  = convert_to_probe_trace_events(pkgs[i].pev,
-                                                     &pkgs[i].tevs, max_tevs);
+                                                    &pkgs[i].tevs,
+                                                    max_tevs,
+                                                    module);
                if (ret < 0)
                        goto end;
                pkgs[i].ntevs = ret;
index 5af39243a25bd00975d6880f4524180edebb236a..5accbedfea372b6761727c0fc1c824e237f12c72 100644 (file)
@@ -90,6 +90,12 @@ struct line_range {
        struct list_head        line_list;      /* Visible lines */
 };
 
+/* List of variables */
+struct variable_list {
+       struct probe_trace_point        point;  /* Actual probepoint */
+       struct strlist                  *vars;  /* Available variables */
+};
+
 /* Command string to events */
 extern int parse_perf_probe_command(const char *cmd,
                                    struct perf_probe_event *pev);
@@ -109,12 +115,18 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
 /* Command string to line-range */
 extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
 
+/* Internal use: Return kernel/module path */
+extern const char *kernel_get_module_path(const char *module);
 
 extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
-                                bool force_add, int max_probe_points);
+                                int max_probe_points, const char *module,
+                                bool force_add);
 extern int del_perf_probe_events(struct strlist *dellist);
 extern int show_perf_probe_events(void);
-extern int show_line_range(struct line_range *lr);
+extern int show_line_range(struct line_range *lr, const char *module);
+extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
+                              int max_probe_points, const char *module,
+                              bool externs);
 
 
 /* Maximum index number of event-name postfix */
index 32b81f707ff5eb5d950a2d233d6c00c6b90fedb2..3991d73d1cff9164cb23fb4aae3169af97abfe77 100644 (file)
@@ -116,6 +116,101 @@ static void line_list__free(struct list_head *head)
        }
 }
 
+/* Dwarf FL wrappers */
+
+static int __linux_kernel_find_elf(Dwfl_Module *mod,
+                                  void **userdata,
+                                  const char *module_name,
+                                  Dwarf_Addr base,
+                                  char **file_name, Elf **elfp)
+{
+       int fd;
+       const char *path = kernel_get_module_path(module_name);
+
+       if (path) {
+               fd = open(path, O_RDONLY);
+               if (fd >= 0) {
+                       *file_name = strdup(path);
+                       return fd;
+               }
+       }
+       /* If failed, try to call standard method */
+       return dwfl_linux_kernel_find_elf(mod, userdata, module_name, base,
+                                         file_name, elfp);
+}
+
+static char *debuginfo_path;   /* Currently dummy */
+
+static const Dwfl_Callbacks offline_callbacks = {
+       .find_debuginfo = dwfl_standard_find_debuginfo,
+       .debuginfo_path = &debuginfo_path,
+
+       .section_address = dwfl_offline_section_address,
+
+       /* We use this table for core files too.  */
+       .find_elf = dwfl_build_id_find_elf,
+};
+
+static const Dwfl_Callbacks kernel_callbacks = {
+       .find_debuginfo = dwfl_standard_find_debuginfo,
+       .debuginfo_path = &debuginfo_path,
+
+       .find_elf = __linux_kernel_find_elf,
+       .section_address = dwfl_linux_kernel_module_section_address,
+};
+
+/* Get a Dwarf from offline image */
+static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias)
+{
+       Dwfl_Module *mod;
+       Dwarf *dbg = NULL;
+
+       if (!dwflp)
+               return NULL;
+
+       *dwflp = dwfl_begin(&offline_callbacks);
+       if (!*dwflp)
+               return NULL;
+
+       mod = dwfl_report_offline(*dwflp, "", "", fd);
+       if (!mod)
+               goto error;
+
+       dbg = dwfl_module_getdwarf(mod, bias);
+       if (!dbg) {
+error:
+               dwfl_end(*dwflp);
+               *dwflp = NULL;
+       }
+       return dbg;
+}
+
+/* Get a Dwarf from live kernel image */
+static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp,
+                                         Dwarf_Addr *bias)
+{
+       Dwarf *dbg;
+
+       if (!dwflp)
+               return NULL;
+
+       *dwflp = dwfl_begin(&kernel_callbacks);
+       if (!*dwflp)
+               return NULL;
+
+       /* Load the kernel dwarves: Don't care the result here */
+       dwfl_linux_kernel_report_kernel(*dwflp);
+       dwfl_linux_kernel_report_modules(*dwflp);
+
+       dbg = dwfl_addrdwarf(*dwflp, addr, bias);
+       /* Here, check whether we could get a real dwarf */
+       if (!dbg) {
+               dwfl_end(*dwflp);
+               *dwflp = NULL;
+       }
+       return dbg;
+}
+
 /* Dwarf wrappers */
 
 /* Find the realpath of the target file. */
@@ -160,26 +255,44 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
        return name ? (strcmp(tname, name) == 0) : false;
 }
 
-/* Get type die, but skip qualifiers and typedef */
-static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+/* Get type die */
+static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
 {
        Dwarf_Attribute attr;
+
+       if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
+           dwarf_formref_die(&attr, die_mem))
+               return die_mem;
+       else
+               return NULL;
+}
+
+/* Get a type die, but skip qualifiers */
+static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
        int tag;
 
        do {
-               if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL ||
-                   dwarf_formref_die(&attr, die_mem) == NULL)
-                       return NULL;
-
-               tag = dwarf_tag(die_mem);
-               vr_die = die_mem;
+               vr_die = die_get_type(vr_die, die_mem);
+               if (!vr_die)
+                       break;
+               tag = dwarf_tag(vr_die);
        } while (tag == DW_TAG_const_type ||
                 tag == DW_TAG_restrict_type ||
                 tag == DW_TAG_volatile_type ||
-                tag == DW_TAG_shared_type ||
-                tag == DW_TAG_typedef);
+                tag == DW_TAG_shared_type);
+
+       return vr_die;
+}
 
-       return die_mem;
+/* Get a type die, but skip qualifiers and typedef */
+static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
+{
+       do {
+               vr_die = __die_get_real_type(vr_die, die_mem);
+       } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
+
+       return vr_die;
 }
 
 static bool die_is_signed_type(Dwarf_Die *tp_die)
@@ -320,25 +433,35 @@ static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
        return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem);
 }
 
+struct __find_variable_param {
+       const char *name;
+       Dwarf_Addr addr;
+};
+
 static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
 {
-       const char *name = data;
+       struct __find_variable_param *fvp = data;
        int tag;
 
        tag = dwarf_tag(die_mem);
        if ((tag == DW_TAG_formal_parameter ||
             tag == DW_TAG_variable) &&
-           die_compare_name(die_mem, name))
+           die_compare_name(die_mem, fvp->name))
                return DIE_FIND_CB_FOUND;
 
-       return DIE_FIND_CB_CONTINUE;
+       if (dwarf_haspc(die_mem, fvp->addr))
+               return DIE_FIND_CB_CONTINUE;
+       else
+               return DIE_FIND_CB_SIBLING;
 }
 
-/* Find a variable called 'name' */
-static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
-                                   Dwarf_Die *die_mem)
+/* Find a variable called 'name' at given address */
+static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
+                                      Dwarf_Addr addr, Dwarf_Die *die_mem)
 {
-       return die_find_child(sp_die, __die_find_variable_cb, (void *)name,
+       struct __find_variable_param fvp = { .name = name, .addr = addr};
+
+       return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
                              die_mem);
 }
 
@@ -361,6 +484,60 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
                              die_mem);
 }
 
+/* Get the name of given variable DIE */
+static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
+{
+       Dwarf_Die type;
+       int tag, ret, ret2;
+       const char *tmp = "";
+
+       if (__die_get_real_type(vr_die, &type) == NULL)
+               return -ENOENT;
+
+       tag = dwarf_tag(&type);
+       if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
+               tmp = "*";
+       else if (tag == DW_TAG_subroutine_type) {
+               /* Function pointer */
+               ret = snprintf(buf, len, "(function_type)");
+               return (ret >= len) ? -E2BIG : ret;
+       } else {
+               if (!dwarf_diename(&type))
+                       return -ENOENT;
+               if (tag == DW_TAG_union_type)
+                       tmp = "union ";
+               else if (tag == DW_TAG_structure_type)
+                       tmp = "struct ";
+               /* Write a base name */
+               ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
+               return (ret >= len) ? -E2BIG : ret;
+       }
+       ret = die_get_typename(&type, buf, len);
+       if (ret > 0) {
+               ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
+               ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
+       }
+       return ret;
+}
+
+/* Get the name and type of given variable DIE, stored as "type\tname" */
+static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
+{
+       int ret, ret2;
+
+       ret = die_get_typename(vr_die, buf, len);
+       if (ret < 0) {
+               pr_debug("Failed to get type, make it unknown.\n");
+               ret = snprintf(buf, len, "(unknown_type)");
+       }
+       if (ret > 0) {
+               ret2 = snprintf(buf + ret, len - ret, "\t%s",
+                               dwarf_diename(vr_die));
+               ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
+       }
+       return ret;
+}
+
 /*
  * Probe finder related functions
  */
@@ -374,8 +551,13 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
        return ref;
 }
 
-/* Show a location */
-static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
+/*
+ * Convert a location into trace_arg.
+ * If tvar == NULL, this just checks variable can be converted.
+ */
+static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
+                                    Dwarf_Op *fb_ops,
+                                    struct probe_trace_arg *tvar)
 {
        Dwarf_Attribute attr;
        Dwarf_Op *op;
@@ -384,20 +566,23 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
        Dwarf_Word offs = 0;
        bool ref = false;
        const char *regs;
-       struct probe_trace_arg *tvar = pf->tvar;
        int ret;
 
+       if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
+               goto static_var;
+
        /* TODO: handle more than 1 exprs */
        if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
-           dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
+           dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
            nops == 0) {
                /* TODO: Support const_value */
-               pr_err("Failed to find the location of %s at this address.\n"
-                      " Perhaps, it has been optimized out.\n", pf->pvar->var);
                return -ENOENT;
        }
 
        if (op->atom == DW_OP_addr) {
+static_var:
+               if (!tvar)
+                       return 0;
                /* Static variables on memory (not stack), make @varname */
                ret = strlen(dwarf_diename(vr_die));
                tvar->value = zalloc(ret + 2);
@@ -412,14 +597,11 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
 
        /* If this is based on frame buffer, set the offset */
        if (op->atom == DW_OP_fbreg) {
-               if (pf->fb_ops == NULL) {
-                       pr_warning("The attribute of frame base is not "
-                                  "supported.\n");
+               if (fb_ops == NULL)
                        return -ENOTSUP;
-               }
                ref = true;
                offs = op->number;
-               op = &pf->fb_ops[0];
+               op = &fb_ops[0];
        }
 
        if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
@@ -435,13 +617,18 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
        } else if (op->atom == DW_OP_regx) {
                regn = op->number;
        } else {
-               pr_warning("DW_OP %x is not supported.\n", op->atom);
+               pr_debug("DW_OP %x is not supported.\n", op->atom);
                return -ENOTSUP;
        }
 
+       if (!tvar)
+               return 0;
+
        regs = get_arch_regstr(regn);
        if (!regs) {
-               pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn);
+               /* This should be a bug in DWARF or this tool */
+               pr_warning("Mapping for DWARF register number %u "
+                          "missing on this architecture.", regn);
                return -ERANGE;
        }
 
@@ -666,8 +853,14 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
        pr_debug("Converting variable %s into trace event.\n",
                 dwarf_diename(vr_die));
 
-       ret = convert_variable_location(vr_die, pf);
-       if (ret == 0 && pf->pvar->field) {
+       ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
+                                       pf->tvar);
+       if (ret == -ENOENT)
+               pr_err("Failed to find the location of %s at this address.\n"
+                      " Perhaps, it has been optimized out.\n", pf->pvar->var);
+       else if (ret == -ENOTSUP)
+               pr_err("Sorry, we don't support this variable location yet.\n");
+       else if (pf->pvar->field) {
                ret = convert_variable_fields(vr_die, pf->pvar->var,
                                              pf->pvar->field, &pf->tvar->ref,
                                              &die_mem);
@@ -722,56 +915,39 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
        pr_debug("Searching '%s' variable in context.\n",
                 pf->pvar->var);
        /* Search child die for local variables and parameters. */
-       if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
+       if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die))
                ret = convert_variable(&vr_die, pf);
        else {
                /* Search upper class */
                nscopes = dwarf_getscopes_die(sp_die, &scopes);
-               if (nscopes > 0) {
-                       ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
-                                               0, NULL, 0, 0, &vr_die);
-                       if (ret >= 0)
+               while (nscopes-- > 1) {
+                       pr_debug("Searching variables in %s\n",
+                                dwarf_diename(&scopes[nscopes]));
+                       /* We should check this scope, so give dummy address */
+                       if (die_find_variable_at(&scopes[nscopes],
+                                                pf->pvar->var, 0,
+                                                &vr_die)) {
                                ret = convert_variable(&vr_die, pf);
-                       else
-                               ret = -ENOENT;
+                               goto found;
+                       }
+               }
+               if (scopes)
                        free(scopes);
-               } else
-                       ret = -ENOENT;
+               ret = -ENOENT;
        }
+found:
        if (ret < 0)
                pr_warning("Failed to find '%s' in this function.\n",
                           pf->pvar->var);
        return ret;
 }
 
-/* Show a probe point to output buffer */
-static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
+/* Convert subprogram DIE to trace point */
+static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
+                                 bool retprobe, struct probe_trace_point *tp)
 {
-       struct probe_trace_event *tev;
        Dwarf_Addr eaddr;
-       Dwarf_Die die_mem;
        const char *name;
-       int ret, i;
-       Dwarf_Attribute fb_attr;
-       size_t nops;
-
-       if (pf->ntevs == pf->max_tevs) {
-               pr_warning("Too many( > %d) probe point found.\n",
-                          pf->max_tevs);
-               return -ERANGE;
-       }
-       tev = &pf->tevs[pf->ntevs++];
-
-       /* If no real subprogram, find a real one */
-       if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
-               sp_die = die_find_real_subprogram(&pf->cu_die,
-                                                pf->addr, &die_mem);
-               if (!sp_die) {
-                       pr_warning("Failed to find probe point in any "
-                                  "functions.\n");
-                       return -ENOENT;
-               }
-       }
 
        /* Copy the name of probe point */
        name = dwarf_diename(sp_die);
@@ -781,26 +957,45 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
                                   dwarf_diename(sp_die));
                        return -ENOENT;
                }
-               tev->point.symbol = strdup(name);
-               if (tev->point.symbol == NULL)
+               tp->symbol = strdup(name);
+               if (tp->symbol == NULL)
                        return -ENOMEM;
-               tev->point.offset = (unsigned long)(pf->addr - eaddr);
+               tp->offset = (unsigned long)(paddr - eaddr);
        } else
                /* This function has no name. */
-               tev->point.offset = (unsigned long)pf->addr;
+               tp->offset = (unsigned long)paddr;
 
        /* Return probe must be on the head of a subprogram */
-       if (pf->pev->point.retprobe) {
-               if (tev->point.offset != 0) {
+       if (retprobe) {
+               if (eaddr != paddr) {
                        pr_warning("Return probe must be on the head of"
                                   " a real function\n");
                        return -EINVAL;
                }
-               tev->point.retprobe = true;
+               tp->retprobe = true;
        }
 
-       pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
-                tev->point.offset);
+       return 0;
+}
+
+/* Call probe_finder callback with real subprogram DIE */
+static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+       Dwarf_Die die_mem;
+       Dwarf_Attribute fb_attr;
+       size_t nops;
+       int ret;
+
+       /* If no real subprogram, find a real one */
+       if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
+               sp_die = die_find_real_subprogram(&pf->cu_die,
+                                                 pf->addr, &die_mem);
+               if (!sp_die) {
+                       pr_warning("Failed to find probe point in any "
+                                  "functions.\n");
+                       return -ENOENT;
+               }
+       }
 
        /* Get the frame base attribute/ops */
        dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -820,22 +1015,13 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
 #endif
        }
 
-       /* Find each argument */
-       tev->nargs = pf->pev->nargs;
-       tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
-       if (tev->args == NULL)
-               return -ENOMEM;
-       for (i = 0; i < pf->pev->nargs; i++) {
-               pf->pvar = &pf->pev->args[i];
-               pf->tvar = &tev->args[i];
-               ret = find_variable(sp_die, pf);
-               if (ret != 0)
-                       return ret;
-       }
+       /* Call finder's callback handler */
+       ret = pf->callback(sp_die, pf);
 
        /* *pf->fb_ops will be cached in libdw. Don't free it. */
        pf->fb_ops = NULL;
-       return 0;
+
+       return ret;
 }
 
 /* Find probe point from its line number */
@@ -871,7 +1057,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
                         (int)i, lineno, (uintmax_t)addr);
                pf->addr = addr;
 
-               ret = convert_probe_point(NULL, pf);
+               ret = call_probe_finder(NULL, pf);
                /* Continuing, because target line might be inlined. */
        }
        return ret;
@@ -984,7 +1170,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
                         (int)i, lineno, (unsigned long long)addr);
                pf->addr = addr;
 
-               ret = convert_probe_point(sp_die, pf);
+               ret = call_probe_finder(sp_die, pf);
                /* Continuing, because target line might be inlined. */
        }
        /* TODO: deallocate lines, but how? */
@@ -1019,7 +1205,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
                pr_debug("found inline addr: 0x%jx\n",
                         (uintmax_t)pf->addr);
 
-               param->retval = convert_probe_point(in_die, pf);
+               param->retval = call_probe_finder(in_die, pf);
                if (param->retval < 0)
                        return DWARF_CB_ABORT;
        }
@@ -1057,7 +1243,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
                        }
                        pf->addr += pp->offset;
                        /* TODO: Check the address in this function */
-                       param->retval = convert_probe_point(sp_die, pf);
+                       param->retval = call_probe_finder(sp_die, pf);
                }
        } else {
                struct dwarf_callback_param _param = {.data = (void *)pf,
@@ -1079,90 +1265,276 @@ static int find_probe_point_by_func(struct probe_finder *pf)
        return _param.retval;
 }
 
-/* Find probe_trace_events specified by perf_probe_event from debuginfo */
-int find_probe_trace_events(int fd, struct perf_probe_event *pev,
-                            struct probe_trace_event **tevs, int max_tevs)
+/* Find probe points from debuginfo */
+static int find_probes(int fd, struct probe_finder *pf)
 {
-       struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs};
-       struct perf_probe_point *pp = &pev->point;
+       struct perf_probe_point *pp = &pf->pev->point;
        Dwarf_Off off, noff;
        size_t cuhl;
        Dwarf_Die *diep;
-       Dwarf *dbg;
+       Dwarf *dbg = NULL;
+       Dwfl *dwfl;
+       Dwarf_Addr bias;        /* Currently ignored */
        int ret = 0;
 
-       pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
-       if (pf.tevs == NULL)
-               return -ENOMEM;
-       *tevs = pf.tevs;
-       pf.ntevs = 0;
-
-       dbg = dwarf_begin(fd, DWARF_C_READ);
+       dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
        if (!dbg) {
                pr_warning("No dwarf info found in the vmlinux - "
                        "please rebuild with CONFIG_DEBUG_INFO=y.\n");
-               free(pf.tevs);
-               *tevs = NULL;
                return -EBADF;
        }
 
 #if _ELFUTILS_PREREQ(0, 142)
        /* Get the call frame information from this dwarf */
-       pf.cfi = dwarf_getcfi(dbg);
+       pf->cfi = dwarf_getcfi(dbg);
 #endif
 
        off = 0;
-       line_list__init(&pf.lcache);
+       line_list__init(&pf->lcache);
        /* Loop on CUs (Compilation Unit) */
        while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
               ret >= 0) {
                /* Get the DIE(Debugging Information Entry) of this CU */
-               diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
+               diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
                if (!diep)
                        continue;
 
                /* Check if target file is included. */
                if (pp->file)
-                       pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
+                       pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
                else
-                       pf.fname = NULL;
+                       pf->fname = NULL;
 
-               if (!pp->file || pf.fname) {
+               if (!pp->file || pf->fname) {
                        if (pp->function)
-                               ret = find_probe_point_by_func(&pf);
+                               ret = find_probe_point_by_func(pf);
                        else if (pp->lazy_line)
-                               ret = find_probe_point_lazy(NULL, &pf);
+                               ret = find_probe_point_lazy(NULL, pf);
                        else {
-                               pf.lno = pp->line;
-                               ret = find_probe_point_by_line(&pf);
+                               pf->lno = pp->line;
+                               ret = find_probe_point_by_line(pf);
                        }
                }
                off = noff;
        }
-       line_list__free(&pf.lcache);
-       dwarf_end(dbg);
+       line_list__free(&pf->lcache);
+       if (dwfl)
+               dwfl_end(dwfl);
 
-       return (ret < 0) ? ret : pf.ntevs;
+       return ret;
+}
+
+/* Add a found probe point into trace event list */
+static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+       struct trace_event_finder *tf =
+                       container_of(pf, struct trace_event_finder, pf);
+       struct probe_trace_event *tev;
+       int ret, i;
+
+       /* Check number of tevs */
+       if (tf->ntevs == tf->max_tevs) {
+               pr_warning("Too many( > %d) probe point found.\n",
+                          tf->max_tevs);
+               return -ERANGE;
+       }
+       tev = &tf->tevs[tf->ntevs++];
+
+       ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
+                                    &tev->point);
+       if (ret < 0)
+               return ret;
+
+       pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
+                tev->point.offset);
+
+       /* Find each argument */
+       tev->nargs = pf->pev->nargs;
+       tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
+       if (tev->args == NULL)
+               return -ENOMEM;
+       for (i = 0; i < pf->pev->nargs; i++) {
+               pf->pvar = &pf->pev->args[i];
+               pf->tvar = &tev->args[i];
+               ret = find_variable(sp_die, pf);
+               if (ret != 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/* Find probe_trace_events specified by perf_probe_event from debuginfo */
+int find_probe_trace_events(int fd, struct perf_probe_event *pev,
+                           struct probe_trace_event **tevs, int max_tevs)
+{
+       struct trace_event_finder tf = {
+                       .pf = {.pev = pev, .callback = add_probe_trace_event},
+                       .max_tevs = max_tevs};
+       int ret;
+
+       /* Allocate result tevs array */
+       *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
+       if (*tevs == NULL)
+               return -ENOMEM;
+
+       tf.tevs = *tevs;
+       tf.ntevs = 0;
+
+       ret = find_probes(fd, &tf.pf);
+       if (ret < 0) {
+               free(*tevs);
+               *tevs = NULL;
+               return ret;
+       }
+
+       return (ret < 0) ? ret : tf.ntevs;
+}
+
+#define MAX_VAR_LEN 64
+
+/* Collect available variables in this scope */
+static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
+{
+       struct available_var_finder *af = data;
+       struct variable_list *vl;
+       char buf[MAX_VAR_LEN];
+       int tag, ret;
+
+       vl = &af->vls[af->nvls - 1];
+
+       tag = dwarf_tag(die_mem);
+       if (tag == DW_TAG_formal_parameter ||
+           tag == DW_TAG_variable) {
+               ret = convert_variable_location(die_mem, af->pf.addr,
+                                               af->pf.fb_ops, NULL);
+               if (ret == 0) {
+                       ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
+                       pr_debug2("Add new var: %s\n", buf);
+                       if (ret > 0)
+                               strlist__add(vl->vars, buf);
+               }
+       }
+
+       if (af->child && dwarf_haspc(die_mem, af->pf.addr))
+               return DIE_FIND_CB_CONTINUE;
+       else
+               return DIE_FIND_CB_SIBLING;
+}
+
+/* Add a found vars into available variables list */
+static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
+{
+       struct available_var_finder *af =
+                       container_of(pf, struct available_var_finder, pf);
+       struct variable_list *vl;
+       Dwarf_Die die_mem, *scopes = NULL;
+       int ret, nscopes;
+
+       /* Check number of tevs */
+       if (af->nvls == af->max_vls) {
+               pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
+               return -ERANGE;
+       }
+       vl = &af->vls[af->nvls++];
+
+       ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
+                                    &vl->point);
+       if (ret < 0)
+               return ret;
+
+       pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
+                vl->point.offset);
+
+       /* Find local variables */
+       vl->vars = strlist__new(true, NULL);
+       if (vl->vars == NULL)
+               return -ENOMEM;
+       af->child = true;
+       die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
+
+       /* Find external variables */
+       if (!af->externs)
+               goto out;
+       /* Don't need to search child DIE for externs. */
+       af->child = false;
+       nscopes = dwarf_getscopes_die(sp_die, &scopes);
+       while (nscopes-- > 1)
+               die_find_child(&scopes[nscopes], collect_variables_cb,
+                              (void *)af, &die_mem);
+       if (scopes)
+               free(scopes);
+
+out:
+       if (strlist__empty(vl->vars)) {
+               strlist__delete(vl->vars);
+               vl->vars = NULL;
+       }
+
+       return ret;
+}
+
+/* Find available variables at given probe point */
+int find_available_vars_at(int fd, struct perf_probe_event *pev,
+                          struct variable_list **vls, int max_vls,
+                          bool externs)
+{
+       struct available_var_finder af = {
+                       .pf = {.pev = pev, .callback = add_available_vars},
+                       .max_vls = max_vls, .externs = externs};
+       int ret;
+
+       /* Allocate result vls array */
+       *vls = zalloc(sizeof(struct variable_list) * max_vls);
+       if (*vls == NULL)
+               return -ENOMEM;
+
+       af.vls = *vls;
+       af.nvls = 0;
+
+       ret = find_probes(fd, &af.pf);
+       if (ret < 0) {
+               /* Free vlist for error */
+               while (af.nvls--) {
+                       if (af.vls[af.nvls].point.symbol)
+                               free(af.vls[af.nvls].point.symbol);
+                       if (af.vls[af.nvls].vars)
+                               strlist__delete(af.vls[af.nvls].vars);
+               }
+               free(af.vls);
+               *vls = NULL;
+               return ret;
+       }
+
+       return (ret < 0) ? ret : af.nvls;
 }
 
 /* Reverse search */
-int find_perf_probe_point(int fd, unsigned long addr,
-                         struct perf_probe_point *ppt)
+int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
 {
        Dwarf_Die cudie, spdie, indie;
-       Dwarf *dbg;
+       Dwarf *dbg = NULL;
+       Dwfl *dwfl = NULL;
        Dwarf_Line *line;
-       Dwarf_Addr laddr, eaddr;
+       Dwarf_Addr laddr, eaddr, bias = 0;
        const char *tmp;
        int lineno, ret = 0;
        bool found = false;
 
-       dbg = dwarf_begin(fd, DWARF_C_READ);
-       if (!dbg)
-               return -EBADF;
+       /* Open the live linux kernel */
+       dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias);
+       if (!dbg) {
+               pr_warning("No dwarf info found in the vmlinux - "
+                       "please rebuild with CONFIG_DEBUG_INFO=y.\n");
+               ret = -EINVAL;
+               goto end;
+       }
 
+       /* Adjust address with bias */
+       addr += bias;
        /* Find cu die */
-       if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) {
+       if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) {
+               pr_warning("No CU DIE is found at %lx\n", addr);
                ret = -EINVAL;
                goto end;
        }
@@ -1225,7 +1597,8 @@ found:
        }
 
 end:
-       dwarf_end(dbg);
+       if (dwfl)
+               dwfl_end(dwfl);
        if (ret >= 0)
                ret = found ? 1 : 0;
        return ret;
@@ -1358,6 +1731,9 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
        struct line_finder *lf = param->data;
        struct line_range *lr = lf->lr;
 
+       pr_debug("find (%llx) %s\n",
+                (unsigned long long)dwarf_dieoffset(sp_die),
+                dwarf_diename(sp_die));
        if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
            die_compare_name(sp_die, lr->function)) {
                lf->fname = dwarf_decl_file(sp_die);
@@ -1401,10 +1777,12 @@ int find_line_range(int fd, struct line_range *lr)
        Dwarf_Off off = 0, noff;
        size_t cuhl;
        Dwarf_Die *diep;
-       Dwarf *dbg;
+       Dwarf *dbg = NULL;
+       Dwfl *dwfl;
+       Dwarf_Addr bias;        /* Currently ignored */
        const char *comp_dir;
 
-       dbg = dwarf_begin(fd, DWARF_C_READ);
+       dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias);
        if (!dbg) {
                pr_warning("No dwarf info found in the vmlinux - "
                        "please rebuild with CONFIG_DEBUG_INFO=y.\n");
@@ -1450,8 +1828,7 @@ int find_line_range(int fd, struct line_range *lr)
        }
 
        pr_debug("path: %s\n", lr->path);
-       dwarf_end(dbg);
-
+       dwfl_end(dwfl);
        return (ret < 0) ? ret : lf.found;
 }
 
index 4507d519f183b71be35c448dddb37f7610835cfc..bba69d4556999e5081b018857acd230de6740eea 100644 (file)
@@ -22,20 +22,27 @@ extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
                                    int max_tevs);
 
 /* Find a perf_probe_point from debuginfo */
-extern int find_perf_probe_point(int fd, unsigned long addr,
+extern int find_perf_probe_point(unsigned long addr,
                                 struct perf_probe_point *ppt);
 
+/* Find a line range */
 extern int find_line_range(int fd, struct line_range *lr);
 
+/* Find available variables */
+extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
+                                 struct variable_list **vls, int max_points,
+                                 bool externs);
+
 #include <dwarf.h>
 #include <libdw.h>
+#include <libdwfl.h>
 #include <version.h>
 
 struct probe_finder {
        struct perf_probe_event *pev;           /* Target probe event */
-       struct probe_trace_event *tevs;         /* Result trace events */
-       int                     ntevs;          /* Number of trace events */
-       int                     max_tevs;       /* Max number of trace events */
+
+       /* Callback when a probe point is found */
+       int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
 
        /* For function searching */
        int                     lno;            /* Line number */
@@ -53,6 +60,22 @@ struct probe_finder {
        struct probe_trace_arg  *tvar;          /* Current result variable */
 };
 
+struct trace_event_finder {
+       struct probe_finder     pf;
+       struct probe_trace_event *tevs;         /* Found trace events */
+       int                     ntevs;          /* Number of trace events */
+       int                     max_tevs;       /* Max number of trace events */
+};
+
+struct available_var_finder {
+       struct probe_finder     pf;
+       struct variable_list    *vls;           /* Found variable lists */
+       int                     nvls;           /* Number of variable lists */
+       int                     max_vls;        /* Max no. of variable lists */
+       bool                    externs;        /* Find external vars too */
+       bool                    child;          /* Search child scopes */
+};
+
 struct line_finder {
        struct line_range       *lr;            /* Target line range */
 
index 46e531d09e8bfcbe1064a4307ce5a75ef72a6405..0b91053a7d11af888eea81a4c8de24fdd60ce6f8 100644 (file)
@@ -70,7 +70,7 @@ struct hist_entry {
                struct hist_entry *pair;
                struct rb_root    sorted_chain;
        };
-       struct callchain_node   callchain[0];
+       struct callchain_root   callchain[0];
 };
 
 enum sort_type {
index b2f5ae97f33dded1cdaba3e843ab2df888515777..b39f499e575a604198bf1bb11d11d6280a091548 100644 (file)
@@ -388,6 +388,20 @@ size_t dso__fprintf_buildid(struct dso *self, FILE *fp)
        return fprintf(fp, "%s", sbuild_id);
 }
 
+size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp)
+{
+       size_t ret = 0;
+       struct rb_node *nd;
+       struct symbol_name_rb_node *pos;
+
+       for (nd = rb_first(&self->symbol_names[type]); nd; nd = rb_next(nd)) {
+               pos = rb_entry(nd, struct symbol_name_rb_node, rb_node);
+               fprintf(fp, "%s\n", pos->sym.name);
+       }
+
+       return ret;
+}
+
 size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
 {
        struct rb_node *nd;
index ea95c2756f05e73d09f6868f24b174ed1221f59a..038f2201ee09579ca3f460d9f59576770ea477d2 100644 (file)
@@ -182,6 +182,7 @@ size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp);
 size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits);
 
 size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
+size_t dso__fprintf_symbols_by_name(struct dso *self, enum map_type type, FILE *fp);
 size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
 
 enum dso_origin {
index 66f2d583d8c4326971dc9d37cd47df57eeb82306..8bc010edca259f48014218a5fcc810d7fe8863b1 100644 (file)
@@ -1,16 +1,5 @@
-#define _GNU_SOURCE
-#include <stdio.h>
-#undef _GNU_SOURCE
-/*
- * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
- * the build if it isn't defined. Use the equivalent one that glibc
- * has on features.h.
- */
-#include <features.h>
-#ifndef HAVE_LONG_LONG
-#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
-#endif
-#include <slang.h>
+#include "libslang.h"
+#include <linux/compiler.h>
 #include <linux/list.h>
 #include <linux/rbtree.h>
 #include <stdlib.h>
@@ -19,17 +8,9 @@
 #include "helpline.h"
 #include "../color.h"
 #include "../util.h"
+#include <stdio.h>
 
-#if SLANG_VERSION < 20104
-#define sltt_set_color(obj, name, fg, bg) \
-       SLtt_set_color(obj,(char *)name, (char *)fg, (char *)bg)
-#else
-#define sltt_set_color SLtt_set_color
-#endif
-
-newtComponent newt_form__new(void);
-
-int ui_browser__percent_color(double percent, bool current)
+static int ui_browser__percent_color(double percent, bool current)
 {
        if (current)
                return HE_COLORSET_SELECTED;
@@ -40,6 +21,23 @@ int ui_browser__percent_color(double percent, bool current)
        return HE_COLORSET_NORMAL;
 }
 
+void ui_browser__set_color(struct ui_browser *self __used, int color)
+{
+       SLsmg_set_color(color);
+}
+
+void ui_browser__set_percent_color(struct ui_browser *self,
+                                  double percent, bool current)
+{
+        int color = ui_browser__percent_color(percent, current);
+        ui_browser__set_color(self, color);
+}
+
+void ui_browser__gotorc(struct ui_browser *self, int y, int x)
+{
+       SLsmg_gotorc(self->y + y, self->x + x);
+}
+
 void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
 {
        struct list_head *head = self->entries;
@@ -111,7 +109,7 @@ unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
        nd = self->top;
 
        while (nd != NULL) {
-               SLsmg_gotorc(self->y + row, self->x);
+               ui_browser__gotorc(self, row, 0);
                self->write(self, nd, row);
                if (++row == self->height)
                        break;
@@ -131,13 +129,10 @@ void ui_browser__refresh_dimensions(struct ui_browser *self)
        int cols, rows;
        newtGetScreenSize(&cols, &rows);
 
-       if (self->width > cols - 4)
-               self->width = cols - 4;
-       self->height = rows - 5;
-       if (self->height > self->nr_entries)
-               self->height = self->nr_entries;
-       self->y  = (rows - self->height) / 2;
-       self->x = (cols - self->width) / 2;
+       self->width = cols - 1;
+       self->height = rows - 2;
+       self->y = 1;
+       self->x = 0;
 }
 
 void ui_browser__reset_index(struct ui_browser *self)
@@ -146,34 +141,48 @@ void ui_browser__reset_index(struct ui_browser *self)
        self->seek(self, 0, SEEK_SET);
 }
 
+void ui_browser__add_exit_key(struct ui_browser *self, int key)
+{
+       newtFormAddHotKey(self->form, key);
+}
+
+void ui_browser__add_exit_keys(struct ui_browser *self, int keys[])
+{
+       int i = 0;
+
+       while (keys[i] && i < 64) {
+               ui_browser__add_exit_key(self, keys[i]);
+               ++i;
+       }
+}
+
 int ui_browser__show(struct ui_browser *self, const char *title,
                     const char *helpline, ...)
 {
        va_list ap;
+       int keys[] = { NEWT_KEY_UP, NEWT_KEY_DOWN, NEWT_KEY_PGUP,
+                      NEWT_KEY_PGDN, NEWT_KEY_HOME, NEWT_KEY_END, ' ',
+                      NEWT_KEY_LEFT, NEWT_KEY_ESCAPE, 'q', CTRL('c'), 0 };
 
-       if (self->form != NULL) {
+       if (self->form != NULL)
                newtFormDestroy(self->form);
-               newtPopWindow();
-       }
+
        ui_browser__refresh_dimensions(self);
-       newtCenteredWindow(self->width, self->height, title);
-       self->form = newt_form__new();
+       self->form = newtForm(NULL, NULL, 0);
        if (self->form == NULL)
                return -1;
 
-       self->sb = newtVerticalScrollbar(self->width, 0, self->height,
+       self->sb = newtVerticalScrollbar(self->width, 1, self->height,
                                         HE_COLORSET_NORMAL,
                                         HE_COLORSET_SELECTED);
        if (self->sb == NULL)
                return -1;
 
-       newtFormAddHotKey(self->form, NEWT_KEY_UP);
-       newtFormAddHotKey(self->form, NEWT_KEY_DOWN);
-       newtFormAddHotKey(self->form, NEWT_KEY_PGUP);
-       newtFormAddHotKey(self->form, NEWT_KEY_PGDN);
-       newtFormAddHotKey(self->form, NEWT_KEY_HOME);
-       newtFormAddHotKey(self->form, NEWT_KEY_END);
-       newtFormAddHotKey(self->form, ' ');
+       SLsmg_gotorc(0, 0);
+       ui_browser__set_color(self, NEWT_COLORSET_ROOT);
+       slsmg_write_nstring(title, self->width);
+
+       ui_browser__add_exit_keys(self, keys);
        newtFormAddComponent(self->form, self->sb);
 
        va_start(ap, helpline);
@@ -185,7 +194,6 @@ int ui_browser__show(struct ui_browser *self, const char *title,
 void ui_browser__hide(struct ui_browser *self)
 {
        newtFormDestroy(self->form);
-       newtPopWindow();
        self->form = NULL;
        ui_helpline__pop();
 }
@@ -196,28 +204,28 @@ int ui_browser__refresh(struct ui_browser *self)
 
        newtScrollbarSet(self->sb, self->index, self->nr_entries - 1);
        row = self->refresh(self);
-       SLsmg_set_color(HE_COLORSET_NORMAL);
+       ui_browser__set_color(self, HE_COLORSET_NORMAL);
        SLsmg_fill_region(self->y + row, self->x,
                          self->height - row, self->width, ' ');
 
        return 0;
 }
 
-int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es)
+int ui_browser__run(struct ui_browser *self)
 {
+       struct newtExitStruct es;
+
        if (ui_browser__refresh(self) < 0)
                return -1;
 
        while (1) {
                off_t offset;
 
-               newtFormRun(self->form, es);
+               newtFormRun(self->form, &es);
 
-               if (es->reason != NEWT_EXIT_HOTKEY)
+               if (es.reason != NEWT_EXIT_HOTKEY)
                        break;
-               if (is_exit_key(es->u.key))
-                       return es->u.key;
-               switch (es->u.key) {
+               switch (es.u.key) {
                case NEWT_KEY_DOWN:
                        if (self->index == self->nr_entries - 1)
                                break;
@@ -274,12 +282,12 @@ int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es)
                        self->seek(self, -offset, SEEK_END);
                        break;
                default:
-                       return es->u.key;
+                       return es.u.key;
                }
                if (ui_browser__refresh(self) < 0)
                        return -1;
        }
-       return 0;
+       return -1;
 }
 
 unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
@@ -294,7 +302,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
        pos = self->top;
 
        list_for_each_from(pos, head) {
-               SLsmg_gotorc(self->y + row, self->x);
+               ui_browser__gotorc(self, row, 0);
                self->write(self, pos, row);
                if (++row == self->height)
                        break;
index 0b9f829214f756ec16227745835cfea55d7ee503..0dc7e4da36f52c42ef3574dc89dce7102ae8438d 100644 (file)
@@ -25,16 +25,21 @@ struct ui_browser {
 };
 
 
-int ui_browser__percent_color(double percent, bool current);
+void ui_browser__set_color(struct ui_browser *self, int color);
+void ui_browser__set_percent_color(struct ui_browser *self,
+                                  double percent, bool current);
 bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
 void ui_browser__refresh_dimensions(struct ui_browser *self);
 void ui_browser__reset_index(struct ui_browser *self);
 
+void ui_browser__gotorc(struct ui_browser *self, int y, int x);
+void ui_browser__add_exit_key(struct ui_browser *self, int key);
+void ui_browser__add_exit_keys(struct ui_browser *self, int keys[]);
 int ui_browser__show(struct ui_browser *self, const char *title,
                     const char *helpline, ...);
 void ui_browser__hide(struct ui_browser *self);
 int ui_browser__refresh(struct ui_browser *self);
-int ui_browser__run(struct ui_browser *self, struct newtExitStruct *es);
+int ui_browser__run(struct ui_browser *self);
 
 void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
 unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
index a90273e63f4fb6939ea64e074513e1afabb1f289..82b78f99251bb2b764165cf8066a85f1e6e4b97d 100644 (file)
@@ -40,14 +40,12 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro
 
        if (ol->offset != -1) {
                struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
-               int color = ui_browser__percent_color(olrb->percent, current_entry);
-               SLsmg_set_color(color);
+               ui_browser__set_percent_color(self, olrb->percent, current_entry);
                slsmg_printf(" %7.2f ", olrb->percent);
                if (!current_entry)
-                       SLsmg_set_color(HE_COLORSET_CODE);
+                       ui_browser__set_color(self, HE_COLORSET_CODE);
        } else {
-               int color = ui_browser__percent_color(0, current_entry);
-               SLsmg_set_color(color);
+               ui_browser__set_percent_color(self, 0, current_entry);
                slsmg_write_nstring(" ", 9);
        }
 
@@ -135,32 +133,31 @@ static void annotate_browser__set_top(struct annotate_browser *self,
        self->curr_hot = nd;
 }
 
-static int annotate_browser__run(struct annotate_browser *self,
-                                struct newtExitStruct *es)
+static int annotate_browser__run(struct annotate_browser *self)
 {
        struct rb_node *nd;
        struct hist_entry *he = self->b.priv;
+       int key;
 
        if (ui_browser__show(&self->b, he->ms.sym->name,
-                            "<- or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0)
+                            "<-, -> or ESC: exit, TAB/shift+TAB: cycle thru samples") < 0)
                return -1;
-
-       newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
-       newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT);
+       /*
+        * To allow builtin-annotate to cycle thru multiple symbols by
+        * examining the exit key for this function.
+        */
+       ui_browser__add_exit_key(&self->b, NEWT_KEY_RIGHT);
 
        nd = self->curr_hot;
        if (nd) {
-               newtFormAddHotKey(self->b.form, NEWT_KEY_TAB);
-               newtFormAddHotKey(self->b.form, NEWT_KEY_UNTAB);
+               int tabs[] = { NEWT_KEY_TAB, NEWT_KEY_UNTAB, 0 };
+               ui_browser__add_exit_keys(&self->b, tabs);
        }
 
        while (1) {
-               ui_browser__run(&self->b, es);
-
-               if (es->reason != NEWT_EXIT_HOTKEY)
-                       break;
+               key = ui_browser__run(&self->b);
 
-               switch (es->u.key) {
+               switch (key) {
                case NEWT_KEY_TAB:
                        nd = rb_prev(nd);
                        if (nd == NULL)
@@ -179,12 +176,11 @@ static int annotate_browser__run(struct annotate_browser *self,
        }
 out:
        ui_browser__hide(&self->b);
-       return es->u.key;
+       return key;
 }
 
 int hist_entry__tui_annotate(struct hist_entry *self)
 {
-       struct newtExitStruct es;
        struct objdump_line *pos, *n;
        struct objdump_line_rb_node *rbpos;
        LIST_HEAD(head);
@@ -232,7 +228,7 @@ int hist_entry__tui_annotate(struct hist_entry *self)
                annotate_browser__set_top(&browser, browser.curr_hot);
 
        browser.b.width += 18; /* Percentage */
-       ret = annotate_browser__run(&browser, &es);
+       ret = annotate_browser__run(&browser);
        list_for_each_entry_safe(pos, n, &head, node) {
                list_del(&pos->node);
                objdump_line__free(pos);
index 6866aa4c41e09cfd0239559cc903506a351a549c..ebda8c3fde9e6468ddbd84fc2df7e324ba862854 100644 (file)
@@ -58,6 +58,11 @@ static char callchain_list__folded(const struct callchain_list *self)
        return map_symbol__folded(&self->ms);
 }
 
+static void map_symbol__set_folding(struct map_symbol *self, bool unfold)
+{
+       self->unfolded = unfold ? self->has_children : false;
+}
+
 static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
 {
        int n = 0;
@@ -129,16 +134,16 @@ static void callchain_node__init_have_children_rb_tree(struct callchain_node *se
        for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
                struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
                struct callchain_list *chain;
-               int first = true;
+               bool first = true;
 
                list_for_each_entry(chain, &child->val, list) {
                        if (first) {
                                first = false;
                                chain->ms.has_children = chain->list.next != &child->val ||
-                                                        rb_first(&child->rb_root) != NULL;
+                                                        !RB_EMPTY_ROOT(&child->rb_root);
                        } else
                                chain->ms.has_children = chain->list.next == &child->val &&
-                                                        rb_first(&child->rb_root) != NULL;
+                                                        !RB_EMPTY_ROOT(&child->rb_root);
                }
 
                callchain_node__init_have_children_rb_tree(child);
@@ -150,7 +155,7 @@ static void callchain_node__init_have_children(struct callchain_node *self)
        struct callchain_list *chain;
 
        list_for_each_entry(chain, &self->val, list)
-               chain->ms.has_children = rb_first(&self->rb_root) != NULL;
+               chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root);
 
        callchain_node__init_have_children_rb_tree(self);
 }
@@ -168,6 +173,7 @@ static void callchain__init_have_children(struct rb_root *self)
 static void hist_entry__init_have_children(struct hist_entry *self)
 {
        if (!self->init_have_children) {
+               self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain);
                callchain__init_have_children(&self->sorted_chain);
                self->init_have_children = true;
        }
@@ -195,43 +201,114 @@ static bool hist_browser__toggle_fold(struct hist_browser *self)
        return false;
 }
 
-static int hist_browser__run(struct hist_browser *self, const char *title,
-                            struct newtExitStruct *es)
+static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold)
+{
+       int n = 0;
+       struct rb_node *nd;
+
+       for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
+               struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
+               struct callchain_list *chain;
+               bool has_children = false;
+
+               list_for_each_entry(chain, &child->val, list) {
+                       ++n;
+                       map_symbol__set_folding(&chain->ms, unfold);
+                       has_children = chain->ms.has_children;
+               }
+
+               if (has_children)
+                       n += callchain_node__set_folding_rb_tree(child, unfold);
+       }
+
+       return n;
+}
+
+static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
+{
+       struct callchain_list *chain;
+       bool has_children = false;
+       int n = 0;
+
+       list_for_each_entry(chain, &node->val, list) {
+               ++n;
+               map_symbol__set_folding(&chain->ms, unfold);
+               has_children = chain->ms.has_children;
+       }
+
+       if (has_children)
+               n += callchain_node__set_folding_rb_tree(node, unfold);
+
+       return n;
+}
+
+static int callchain__set_folding(struct rb_root *chain, bool unfold)
+{
+       struct rb_node *nd;
+       int n = 0;
+
+       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+               n += callchain_node__set_folding(node, unfold);
+       }
+
+       return n;
+}
+
+static void hist_entry__set_folding(struct hist_entry *self, bool unfold)
+{
+       hist_entry__init_have_children(self);
+       map_symbol__set_folding(&self->ms, unfold);
+
+       if (self->ms.has_children) {
+               int n = callchain__set_folding(&self->sorted_chain, unfold);
+               self->nr_rows = unfold ? n : 0;
+       } else
+               self->nr_rows = 0;
+}
+
+static void hists__set_folding(struct hists *self, bool unfold)
+{
+       struct rb_node *nd;
+
+       self->nr_entries = 0;
+
+       for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
+               struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
+               hist_entry__set_folding(he, unfold);
+               self->nr_entries += 1 + he->nr_rows;
+       }
+}
+
+static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
+{
+       hists__set_folding(self->hists, unfold);
+       self->b.nr_entries = self->hists->nr_entries;
+       /* Go to the start, we may be way after valid entries after a collapse */
+       ui_browser__reset_index(&self->b);
+}
+
+static int hist_browser__run(struct hist_browser *self, const char *title)
 {
-       char str[256], unit;
-       unsigned long nr_events = self->hists->stats.nr_events[PERF_RECORD_SAMPLE];
+       int key;
+       int exit_keys[] = { 'a', '?', 'h', 'C', 'd', 'D', 'E', 't',
+                           NEWT_KEY_ENTER, NEWT_KEY_RIGHT, NEWT_KEY_LEFT, 0, };
 
        self->b.entries = &self->hists->entries;
        self->b.nr_entries = self->hists->nr_entries;
 
        hist_browser__refresh_dimensions(self);
 
-       nr_events = convert_unit(nr_events, &unit);
-       snprintf(str, sizeof(str), "Events: %lu%c                            ",
-                nr_events, unit);
-       newtDrawRootText(0, 0, str);
-
        if (ui_browser__show(&self->b, title,
                             "Press '?' for help on key bindings") < 0)
                return -1;
 
-       newtFormAddHotKey(self->b.form, 'a');
-       newtFormAddHotKey(self->b.form, '?');
-       newtFormAddHotKey(self->b.form, 'h');
-       newtFormAddHotKey(self->b.form, 'd');
-       newtFormAddHotKey(self->b.form, 'D');
-       newtFormAddHotKey(self->b.form, 't');
-
-       newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
-       newtFormAddHotKey(self->b.form, NEWT_KEY_RIGHT);
-       newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
+       ui_browser__add_exit_keys(&self->b, exit_keys);
 
        while (1) {
-               ui_browser__run(&self->b, es);
+               key = ui_browser__run(&self->b);
 
-               if (es->reason != NEWT_EXIT_HOTKEY)
-                       break;
-               switch (es->u.key) {
+               switch (key) {
                case 'D': { /* Debug */
                        static int seq;
                        struct hist_entry *h = rb_entry(self->b.top,
@@ -245,18 +322,26 @@ static int hist_browser__run(struct hist_browser *self, const char *title,
                                           self->b.top_idx,
                                           h->row_offset, h->nr_rows);
                }
-                       continue;
+                       break;
+               case 'C':
+                       /* Collapse the whole world. */
+                       hist_browser__set_folding(self, false);
+                       break;
+               case 'E':
+                       /* Expand the whole world. */
+                       hist_browser__set_folding(self, true);
+                       break;
                case NEWT_KEY_ENTER:
                        if (hist_browser__toggle_fold(self))
                                break;
                        /* fall thru */
                default:
-                       return 0;
+                       goto out;
                }
        }
-
+out:
        ui_browser__hide(&self->b);
-       return 0;
+       return key;
 }
 
 static char *callchain_list__sym_name(struct callchain_list *self,
@@ -306,15 +391,10 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
                        int color;
                        bool was_first = first;
 
-                       if (first) {
+                       if (first)
                                first = false;
-                               chain->ms.has_children = chain->list.next != &child->val ||
-                                                        rb_first(&child->rb_root) != NULL;
-                       } else {
+                       else
                                extra_offset = LEVEL_OFFSET_STEP;
-                               chain->ms.has_children = chain->list.next == &child->val &&
-                                                        rb_first(&child->rb_root) != NULL;
-                       }
 
                        folded_sign = callchain_list__folded(chain);
                        if (*row_offset != 0) {
@@ -341,8 +421,8 @@ static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
                                *is_current_entry = true;
                        }
 
-                       SLsmg_set_color(color);
-                       SLsmg_gotorc(self->b.y + row, self->b.x);
+                       ui_browser__set_color(&self->b, color);
+                       ui_browser__gotorc(&self->b, row, 0);
                        slsmg_write_nstring(" ", offset + extra_offset);
                        slsmg_printf("%c ", folded_sign);
                        slsmg_write_nstring(str, width);
@@ -384,12 +464,7 @@ static int hist_browser__show_callchain_node(struct hist_browser *self,
        list_for_each_entry(chain, &node->val, list) {
                char ipstr[BITS_PER_LONG / 4 + 1], *s;
                int color;
-               /*
-                * FIXME: This should be moved to somewhere else,
-                * probably when the callchain is created, so as not to
-                * traverse it all over again
-                */
-               chain->ms.has_children = rb_first(&node->rb_root) != NULL;
+
                folded_sign = callchain_list__folded(chain);
 
                if (*row_offset != 0) {
@@ -405,8 +480,8 @@ static int hist_browser__show_callchain_node(struct hist_browser *self,
                }
 
                s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
-               SLsmg_gotorc(self->b.y + row, self->b.x);
-               SLsmg_set_color(color);
+               ui_browser__gotorc(&self->b, row, 0);
+               ui_browser__set_color(&self->b, color);
                slsmg_write_nstring(" ", offset);
                slsmg_printf("%c ", folded_sign);
                slsmg_write_nstring(s, width - 2);
@@ -465,7 +540,7 @@ static int hist_browser__show_entry(struct hist_browser *self,
        }
 
        if (symbol_conf.use_callchain) {
-               entry->ms.has_children = !RB_EMPTY_ROOT(&entry->sorted_chain);
+               hist_entry__init_have_children(entry);
                folded_sign = hist_entry__folded(entry);
        }
 
@@ -484,8 +559,8 @@ static int hist_browser__show_entry(struct hist_browser *self,
                                color = HE_COLORSET_NORMAL;
                }
 
-               SLsmg_set_color(color);
-               SLsmg_gotorc(self->b.y + row, self->b.x);
+               ui_browser__set_color(&self->b, color);
+               ui_browser__gotorc(&self->b, row, 0);
                if (symbol_conf.use_callchain) {
                        slsmg_printf("%c ", folded_sign);
                        width -= 2;
@@ -687,8 +762,6 @@ static struct hist_browser *hist_browser__new(struct hists *hists)
 
 static void hist_browser__delete(struct hist_browser *self)
 {
-       newtFormDestroy(self->b.form);
-       newtPopWindow();
        free(self);
 }
 
@@ -702,21 +775,26 @@ static struct thread *hist_browser__selected_thread(struct hist_browser *self)
        return self->he_selection->thread;
 }
 
-static int hist_browser__title(char *bf, size_t size, const char *ev_name,
-                              const struct dso *dso, const struct thread *thread)
+static int hists__browser_title(struct hists *self, char *bf, size_t size,
+                               const char *ev_name, const struct dso *dso,
+                               const struct thread *thread)
 {
-       int printed = 0;
+       char unit;
+       int printed;
+       unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
+
+       nr_events = convert_unit(nr_events, &unit);
+       printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
 
        if (thread)
                printed += snprintf(bf + printed, size - printed,
-                                   "Thread: %s(%d)",
-                                   (thread->comm_set ?  thread->comm : ""),
+                                   "Thread: %s(%d)",
+                                   (thread->comm_set ? thread->comm : ""),
                                    thread->pid);
        if (dso)
                printed += snprintf(bf + printed, size - printed,
-                                   "%sDSO: %s", thread ? " " : "",
-                                   dso->short_name);
-       return printed ?: snprintf(bf, size, "Event: %s", ev_name);
+                                   ", DSO: %s", dso->short_name);
+       return printed;
 }
 
 int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
@@ -725,7 +803,6 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
        struct pstack *fstack;
        const struct thread *thread_filter = NULL;
        const struct dso *dso_filter = NULL;
-       struct newtExitStruct es;
        char msg[160];
        int key = -1;
 
@@ -738,9 +815,8 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
 
        ui_helpline__push(helpline);
 
-       hist_browser__title(msg, sizeof(msg), ev_name,
-                           dso_filter, thread_filter);
-
+       hists__browser_title(self, msg, sizeof(msg), ev_name,
+                            dso_filter, thread_filter);
        while (1) {
                const struct thread *thread;
                const struct dso *dso;
@@ -749,70 +825,63 @@ int hists__browse(struct hists *self, const char *helpline, const char *ev_name)
                    annotate = -2, zoom_dso = -2, zoom_thread = -2,
                    browse_map = -2;
 
-               if (hist_browser__run(browser, msg, &es))
-                       break;
+               key = hist_browser__run(browser, msg);
 
                thread = hist_browser__selected_thread(browser);
                dso = browser->selection->map ? browser->selection->map->dso : NULL;
 
-               if (es.reason == NEWT_EXIT_HOTKEY) {
-                       key = es.u.key;
-
-                       switch (key) {
-                       case NEWT_KEY_F1:
-                               goto do_help;
-                       case NEWT_KEY_TAB:
-                       case NEWT_KEY_UNTAB:
-                               /*
-                                * Exit the browser, let hists__browser_tree
-                                * go to the next or previous
-                                */
-                               goto out_free_stack;
-                       default:;
-                       }
-
-                       switch (key) {
-                       case 'a':
-                               if (browser->selection->map == NULL ||
-                                   browser->selection->map->dso->annotate_warned)
-                                       continue;
-                               goto do_annotate;
-                       case 'd':
-                               goto zoom_dso;
-                       case 't':
-                               goto zoom_thread;
-                       case 'h':
-                       case '?':
-do_help:
-                               ui__help_window("->        Zoom into DSO/Threads & Annotate current symbol\n"
-                                               "<-        Zoom out\n"
-                                               "a         Annotate current symbol\n"
-                                               "h/?/F1    Show this window\n"
-                                               "d         Zoom into current DSO\n"
-                                               "t         Zoom into current Thread\n"
-                                               "q/CTRL+C  Exit browser");
+               switch (key) {
+               case NEWT_KEY_TAB:
+               case NEWT_KEY_UNTAB:
+                       /*
+                        * Exit the browser, let hists__browser_tree
+                        * go to the next or previous
+                        */
+                       goto out_free_stack;
+               case 'a':
+                       if (browser->selection->map == NULL &&
+                           browser->selection->map->dso->annotate_warned)
                                continue;
-                       default:;
-                       }
-                       if (is_exit_key(key)) {
-                               if (key == NEWT_KEY_ESCAPE &&
-                                   !ui__dialog_yesno("Do you really want to exit?"))
-                                       continue;
-                               break;
-                       }
-
-                       if (es.u.key == NEWT_KEY_LEFT) {
-                               const void *top;
+                       goto do_annotate;
+               case 'd':
+                       goto zoom_dso;
+               case 't':
+                       goto zoom_thread;
+               case NEWT_KEY_F1:
+               case 'h':
+               case '?':
+                       ui__help_window("->        Zoom into DSO/Threads & Annotate current symbol\n"
+                                       "<-        Zoom out\n"
+                                       "a         Annotate current symbol\n"
+                                       "h/?/F1    Show this window\n"
+                                       "C         Collapse all callchains\n"
+                                       "E         Expand all callchains\n"
+                                       "d         Zoom into current DSO\n"
+                                       "t         Zoom into current Thread\n"
+                                       "q/CTRL+C  Exit browser");
+                       continue;
+               case NEWT_KEY_ENTER:
+               case NEWT_KEY_RIGHT:
+                       /* menu */
+                       break;
+               case NEWT_KEY_LEFT: {
+                       const void *top;
 
-                               if (pstack__empty(fstack))
-                                       continue;
-                               top = pstack__pop(fstack);
-                               if (top == &dso_filter)
-                                       goto zoom_out_dso;
-                               if (top == &thread_filter)
-                                       goto zoom_out_thread;
+                       if (pstack__empty(fstack))
                                continue;
-                       }
+                       top = pstack__pop(fstack);
+                       if (top == &dso_filter)
+                               goto zoom_out_dso;
+                       if (top == &thread_filter)
+                               goto zoom_out_thread;
+                       continue;
+               }
+               case NEWT_KEY_ESCAPE:
+                       if (!ui__dialog_yesno("Do you really want to exit?"))
+                               continue;
+                       /* Fall thru */
+               default:
+                       goto out_free_stack;
                }
 
                if (browser->selection->sym != NULL &&
@@ -885,8 +954,8 @@ zoom_out_dso:
                                pstack__push(fstack, &dso_filter);
                        }
                        hists__filter_by_dso(self, dso_filter);
-                       hist_browser__title(msg, sizeof(msg), ev_name,
-                                           dso_filter, thread_filter);
+                       hists__browser_title(self, msg, sizeof(msg), ev_name,
+                                            dso_filter, thread_filter);
                        hist_browser__reset(browser);
                } else if (choice == zoom_thread) {
 zoom_thread:
@@ -903,8 +972,8 @@ zoom_out_thread:
                                pstack__push(fstack, &thread_filter);
                        }
                        hists__filter_by_thread(self, thread_filter);
-                       hist_browser__title(msg, sizeof(msg), ev_name,
-                                           dso_filter, thread_filter);
+                       hists__browser_title(self, msg, sizeof(msg), ev_name,
+                                            dso_filter, thread_filter);
                        hist_browser__reset(browser);
                }
        }
@@ -925,10 +994,6 @@ int hists__tui_browse_tree(struct rb_root *self, const char *help)
                const char *ev_name = __event_name(hists->type, hists->config);
 
                key = hists__browse(hists, help, ev_name);
-
-               if (is_exit_key(key))
-                       break;
-
                switch (key) {
                case NEWT_KEY_TAB:
                        next = rb_next(nd);
@@ -940,7 +1005,7 @@ int hists__tui_browse_tree(struct rb_root *self, const char *help)
                                continue;
                        nd = rb_prev(nd);
                default:
-                       break;
+                       return key;
                }
        }
 
index 142b825b42bf41d90ee013f51aaac5e79df44f5e..e35437dfa5b48aea8a0fb0237b2bf7ed7aaf90cd 100644 (file)
@@ -1,6 +1,5 @@
 #include "../libslang.h"
 #include <elf.h>
-#include <newt.h>
 #include <sys/ttydefaults.h>
 #include <ctype.h>
 #include <string.h>
@@ -47,7 +46,6 @@ out_free_form:
 struct map_browser {
        struct ui_browser b;
        struct map        *map;
-       u16               namelen;
        u8                addrlen;
 };
 
@@ -56,14 +54,16 @@ static void map_browser__write(struct ui_browser *self, void *nd, int row)
        struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
        struct map_browser *mb = container_of(self, struct map_browser, b);
        bool current_entry = ui_browser__is_current_entry(self, row);
-       int color = ui_browser__percent_color(0, current_entry);
+       int width;
 
-       SLsmg_set_color(color);
+       ui_browser__set_percent_color(self, 0, current_entry);
        slsmg_printf("%*llx %*llx %c ",
                     mb->addrlen, sym->start, mb->addrlen, sym->end,
                     sym->binding == STB_GLOBAL ? 'g' :
                     sym->binding == STB_LOCAL  ? 'l' : 'w');
-       slsmg_write_nstring(sym->name, mb->namelen);
+       width = self->width - ((mb->addrlen * 2) + 4);
+       if (width > 0)
+               slsmg_write_nstring(sym->name, width);
 }
 
 /* FIXME uber-kludgy, see comment on cmd_report... */
@@ -98,31 +98,29 @@ static int map_browser__search(struct map_browser *self)
        return 0;
 }
 
-static int map_browser__run(struct map_browser *self, struct newtExitStruct *es)
+static int map_browser__run(struct map_browser *self)
 {
+       int key;
+
        if (ui_browser__show(&self->b, self->map->dso->long_name,
                             "Press <- or ESC to exit, %s / to search",
                             verbose ? "" : "restart with -v to use") < 0)
                return -1;
 
-       newtFormAddHotKey(self->b.form, NEWT_KEY_LEFT);
-       newtFormAddHotKey(self->b.form, NEWT_KEY_ENTER);
        if (verbose)
-               newtFormAddHotKey(self->b.form, '/');
+               ui_browser__add_exit_key(&self->b, '/');
 
        while (1) {
-               ui_browser__run(&self->b, es);
+               key = ui_browser__run(&self->b);
 
-               if (es->reason != NEWT_EXIT_HOTKEY)
-                       break;
-               if (verbose && es->u.key == '/')
+               if (verbose && key == '/')
                        map_browser__search(self);
                else
                        break;
        }
 
        ui_browser__hide(&self->b);
-       return 0;
+       return key;
 }
 
 int map__browse(struct map *self)
@@ -136,7 +134,6 @@ int map__browse(struct map *self)
                },
                .map = self,
        };
-       struct newtExitStruct es;
        struct rb_node *nd;
        char tmp[BITS_PER_LONG / 4];
        u64 maxaddr = 0;
@@ -144,8 +141,6 @@ int map__browse(struct map *self)
        for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
                struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
 
-               if (mb.namelen < pos->namelen)
-                       mb.namelen = pos->namelen;
                if (maxaddr < pos->end)
                        maxaddr = pos->end;
                if (verbose) {
@@ -156,6 +151,5 @@ int map__browse(struct map *self)
        }
 
        mb.addrlen = snprintf(tmp, sizeof(tmp), "%llx", maxaddr);
-       mb.b.width += mb.addrlen * 2 + 4 + mb.namelen;
-       return map_browser__run(&mb, &es);
+       return map_browser__run(&mb);
 }
index 04600e26ceea21d08b701570494c5e72210aaa9e..9706d9d40279859321412b270c8ac3053141f4f9 100644 (file)
@@ -11,8 +11,6 @@
 #include "helpline.h"
 #include "util.h"
 
-newtComponent newt_form__new(void);
-
 static void newt_form__set_exit_keys(newtComponent self)
 {
        newtFormAddHotKey(self, NEWT_KEY_LEFT);
@@ -22,7 +20,7 @@ static void newt_form__set_exit_keys(newtComponent self)
        newtFormAddHotKey(self, CTRL('c'));
 }
 
-newtComponent newt_form__new(void)
+static newtComponent newt_form__new(void)
 {
        newtComponent self = newtForm(NULL, NULL, 0);
        if (self)
index f380fed74359034a843756256d6e7a79b0ff22b5..7562707ddd1c491755dc8ea5121637918ba1b844 100644 (file)
@@ -266,19 +266,6 @@ bool strglobmatch(const char *str, const char *pat);
 bool strlazymatch(const char *str, const char *pat);
 unsigned long convert_unit(unsigned long value, char *unit);
 
-#ifndef ESC
-#define ESC 27
-#endif
-
-static inline bool is_exit_key(int key)
-{
-       char up;
-       if (key == CTRL('c') || key == ESC)
-               return true;
-       up = toupper(key);
-       return up == 'Q';
-}
-
 #define _STR(x) #x
 #define STR(x) _STR(x)